On 12/03/2026 09:54, Muhammad Kamran wrote:
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.


Thanks, this is already looking pretty good, but a few nits below.
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

ChangeLog entries are sentences, so should start with a capital letter and end with a full stop.


---
  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")]
  )

I think it would help to have a comment here describing these operands; it's more necessary because you haven't added pro-forma RTL for the expand.
+(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));
aarch64 defines a function 'emit_set_insn' which can be used to simplify this:
         emit_set_insn (operands[1], pat);

+    }

I think you can also handle a const that is non-zero here, since the most efficient way to set the C flag in the CPSR is to compare a register (any register will do, though unfortunately Xzr isn't valid) against 0, since C=1 => unsigned higher or same.

There are also optimizations that can be made if you know that the RHS of the addition is a constant; but there are two cases to consider: 1) y = ~0 (all bits one). In this case the result will be X and the resulting carry flag will be 1. You no-longer need an ADD in this case.

2) All other values of y. In those cases you can just add 1 to y and use a simple add-with-carryout operation.

Note that for both these cases you'll need to change the operand type for the pattern to accept an immediate value (nonmemory_operand). If that value isn't then supported by the instruction you choose, you'll need to force it into a register before using it.

+  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"

This can just be the empty string "".

+  [(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

Please make sure there is a newline character at the end of files.

Also, it would be nice to see some tests for __builtin_addc() and some cases that check the constant folding cases I've described.

R.

Reply via email to