Hi,

this patch adds two bridge patterns for combine in order to fix the
widen-complicate tests that regressed since GCC 14.

They key is to allow combination with a ephemeral binary-operation insn
that widens its first operand.  This can subsequently be combined two
a double-widening insn.  If the combination doesn't happen we fall back
to the original non-combined two insns.  We have been doing the same
thing for multiply-add patterns for a while.

There are still remaining tests of a similar kind that fail.  The issue
there is indeed that combine (now) lacks the capability to continue in
cases where there is no apparent local progress but two or three
seemingly no-progress combinations would help us get a better "global" result.

late_combine cannot rescue us here either because it only performs a
propagation if the source can be propagated into all its uses which is
not the case here.  What we might need to do is create internal functions
for those widening operations and combine/simplify at gimple-level already.

I have done testing on rv64gcv_zvl512b but on an older local commit.
Curious what the CI has to say about it now.

Regards
 Robin

gcc/ChangeLog:

        * config/riscv/autovec-opt.md
        (*single_widen_first_<any_widen_binop:optab><any_extend:su><mode>):
        New combine "bridge" pattern.
---
 gcc/config/riscv/autovec-opt.md | 56 ++++++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index 53431863441..0c3b0cc7e05 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -638,6 +638,34 @@ (define_insn_and_split 
"*single_widen_sub<any_extend:su><mode>"
 }
 [(set_attr "type" "viwalu")])
 
+; This is a bridge pattern for combine.  Although we do not have a
+; pattern that extends just the first operand it helps combine bridge
+; the gap to the pred_dual_widen insns.
+; If combination fails it will just expand two a separate extend and
+; a binop again.
+(define_insn_and_split "*single_widen_first_sub<any_extend:su><mode>"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+       (minus:VWEXTI
+         (any_extend:VWEXTI
+           (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand"))
+         (match_operand:VWEXTI 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code extend_icode = code_for_pred_vf2 (<any_extend:CODE>, <MODE>mode);
+  rtx tmp = gen_reg_rtx (<MODE>mode);
+  rtx extend_ops[] = {tmp, operands[1]};
+  riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP, 
extend_ops);
+
+  rtx ops[] = {operands[0], tmp, operands[2]};
+  insn_code icode = code_for_pred (MINUS, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops);
+  DONE;
+}
+[(set_attr "type" "vector")])
+
 (define_insn_and_split "*single_widen_add<any_extend:su><mode>"
   [(set (match_operand:VWEXTI 0 "register_operand")
        (plus:VWEXTI
@@ -674,7 +702,8 @@ (define_insn_and_split 
"*single_widen_mul<any_extend:su><mode>"
   insn_code extend_icode = code_for_pred_vf2 (<any_extend:CODE>, <MODE>mode);
   rtx tmp = gen_reg_rtx (<MODE>mode);
   rtx extend_ops[] = {tmp, operands[2]};
-  riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP, 
extend_ops);
+  riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP,
+                                extend_ops);
 
   rtx ops[] = {operands[0], operands[1], tmp};
   insn_code icode = code_for_pred (MULT, <MODE>mode);
@@ -771,6 +800,31 @@ (define_insn_and_split "*single_widen_sub<mode>"
 }
 [(set_attr "type" "vfwalu")])
 
+; This is a bridge pattern for combine (see above).
+(define_insn_and_split "*single_widen_first_sub<mode>"
+  [(set (match_operand:VWEXTF 0 "register_operand")
+       (minus:VWEXTF
+         (float_extend:VWEXTF
+           (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand"))
+         (match_operand:VWEXTF 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code extend_icode = code_for_pred_extend (<MODE>mode);
+  rtx tmp = gen_reg_rtx (<MODE>mode);
+  rtx extend_ops[] = {tmp, operands[1]};
+  riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP,
+                                extend_ops);
+
+  rtx ops[] = {operands[0], tmp, operands[2]};
+  insn_code icode = code_for_pred (MINUS, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_FRM_DYN, ops);
+  DONE;
+}
+[(set_attr "type" "vector")])
+
 ;; This combine pattern does not correspond to an single instruction,
 ;; i.e. there is no vfwmul.wv instruction. This is a temporary pattern
 ;; produced by a combine pass and if there is no further combine into
-- 
2.48.1

Reply via email to