The pattern expands uaddc sum into:
cmp openand[4], #1
adcs operand[0], operand[2], operand[3]
cset operand[1], cs

Carry chained uaddc expansion results in a rount trip CC -> register -> CC.
Remove that round-trip as CSET-like materialization does not clobber flags,
so CC already carries the same bit.

gcc/ChangeLog:

        * config/aarch64/aarch64.md
        (uaddc<mode>5): Expansion pattern for uaddc<m>5
        (*aarch64_setc_from_carry_combine_cc_c_<mode>) Post-combine no-op split
        pattern for carry chain elimination in CC_Cmode
        (*aarch64_setc_from_carry_combine_cc_adc_<mode> Post-combine no-op
        split for carry chain elimination in CC_ADCmode

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/uaddcm5.c: test chained uaddc expansion
---
 gcc/config/aarch64/aarch64.md              | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/uaddcm5.c | 26 ++++++++++
 2 files changed, 86 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/uaddcm5.c

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index df5f72ab94c..e875bcaec28 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -3390,6 +3390,66 @@ (define_insn "*add<mode>3_carryinC"
   [(set_attr "type" "adc_reg")]
 )
 
+(define_expand "uaddc<mode>5"
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "register_operand")
+   (match_operand:GPI 2 "register_operand")
+   (match_operand:GPI 3 "register_operand")
+   (match_operand:GPI 4 "nonmemory_operand")]
+  ""
+{
+  if (operands[4] == const0_rtx)
+    {
+      emit_insn (gen_add<mode>3_compareC (operands[0], operands[2],
+                                         operands[3]));
+      rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+      rtx pat = gen_rtx_LTU (<MODE>mode, cc, const0_rtx);
+      emit_insn (gen_rtx_SET (operands[1], pat));
+    }
+  else
+    {
+      rtx cin = force_reg (<MODE>mode, operands[4]);
+      rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+      rtx adc_cc = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+      rtx cmp = gen_rtx_COMPARE (CC_Cmode,
+                                gen_rtx_PLUS (<MODE>mode, cin, constm1_rtx),
+                                cin);
+      emit_insn (gen_rtx_SET (cc, cmp));
+      emit_insn (gen_add<mode>3_carryinC (operands[0], operands[2],
+                                         operands[3]));
+      rtx pat = gen_rtx_GEU (<MODE>mode, adc_cc, const0_rtx);
+      emit_insn (gen_rtx_SET (operands[1], pat));
+    }
+  DONE;
+})
+
+;; The uaddc expansion results in a rount trip CC -> register -> CC.  Remove
+;; that round-trip as CSET-like materialization does not clobber flags, so CC
+;; already carries the same bit.
+(define_insn_and_split "*aarch64_setc_from_carry_combine_cc_c_<mode>"
+  [(set (reg:CC_C CC_REGNUM)
+       (compare:CC_C
+         (neg:GPI
+           (geu:GPI (reg:CC_C CC_REGNUM) (const_int 0)))
+         (ltu:GPI (reg:CC_C CC_REGNUM) (const_int 0))))]
+  ""
+  "#"
+  "&& 1"
+  [(const_int 0)]
+  "emit_note (NOTE_INSN_DELETED); DONE;")
+
+(define_insn_and_split "*aarch64_setc_from_carry_combine_cc_adc_<mode>"
+  [(set (reg:CC_C CC_REGNUM)
+       (compare:CC_C
+         (neg:GPI
+           (ltu:GPI (reg:CC_ADC CC_REGNUM) (const_int 0)))
+         (geu:GPI (reg:CC_ADC CC_REGNUM) (const_int 0))))]
+  ""
+  "#"
+  "&& 1"
+  [(const_int 0)]
+  "emit_note (NOTE_INSN_DELETED); DONE;")
+
 (define_expand "add<mode>3_carryinV"
   [(parallel
      [(set (reg:CC_V CC_REGNUM)
diff --git a/gcc/testsuite/gcc.target/aarch64/uaddcm5.c 
b/gcc/testsuite/gcc.target/aarch64/uaddcm5.c
new file mode 100644
index 00000000000..39a3508b066
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/uaddcm5.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+static unsigned long
+uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long 
*carry_out)
+{
+  unsigned long r;
+  unsigned long c1 = __builtin_add_overflow (x, y, &r);
+  unsigned long c2 = __builtin_add_overflow (r, carry_in, &r);
+  *carry_out = c1 + c2;
+  return r;
+}
+
+void
+foo (unsigned long *p, unsigned long *q)
+{
+  unsigned long c;
+  p[0] = uaddc (p[0], q[0], 0, &c);
+  p[1] = uaddc (p[1], q[1], c, &c);
+  p[2] = uaddc (p[2], q[2], c, &c);
+  p[3] = uaddc (p[3], q[3], c, &c);
+}
+
+
+/* { dg-final { scan-assembler-times "adcs\\t\[xw\]\[0-9\]+, \[xw\]\[0-9\]+, 
\[xw\]\[0-9\]+" 3 } } */
+/* { dg-final { scan-assembler-not "cset\\t\[xw\]\[0-9\]+, cs+.*" } } */
\ No newline at end of file
-- 
2.43.0

Reply via email to