https://gcc.gnu.org/g:8ab2af4964f41248c3b1330f331a78ba6b5a6cc0
commit r17-3933-g8ab2af4964f41248c3b1330f331a78ba6b5a6cc0 Author: Richard Earnshaw <[email protected]> Date: Wed Sep 2 17:14:16 2026 +0100 aarch64: Fix issues with 'overflow' insns [PR126463] This issue looked like a simple 1-character typo, but when trying to construct a suitable testcase, I found that the patterns were hardly ever being used. In the end there turned out to be three underlying issues: - we were selecting the wrong CCmode for NEG and MINUS overflow checks (more precisely, we weren't detecting these at all and then falling back to CCmode). - The patterns were not in canonical form, preventing combine from finding a match while optimizing. - Finally, when we did eventually get the preferred form, we had the invalid output template, causing the reported ICE. gcc/ChangeLog: PR target/126463 * config/aarch64/aarch64.cc (aarch64_select_cc_mode): Correctly match overflow detection idioms using MINUS and NEG. * config/aarch64/aarch64.md (subv<GPI:mode>4): Re-order the compare into canonical form. (subv<GPI:mode>4_insn): Likewise. (negv<GPI:mode>4): Likewise. (negv<GPI:mode>_insn): Likewise. Fix typo in output template. gcc/testsuite/ChangeLog: PR target/126463 * gcc.target/aarch64/negv.c: New test. Diff: --- gcc/config/aarch64/aarch64.cc | 10 +++++---- gcc/config/aarch64/aarch64.md | 38 ++++++++++++++++----------------- gcc/testsuite/gcc.target/aarch64/negv.c | 27 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 5544d5f8c7ad..ccb4f5fbb10d 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -12792,11 +12792,13 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y) << (GET_MODE_BITSIZE (mode_x).to_constant () / 2)))) return CC_ADCmode; - /* A test for signed overflow. */ + /* Tests for signed overflow. */ if ((mode_x == DImode || mode_x == TImode) - && code == NE - && code_x == PLUS - && GET_CODE (y) == SIGN_EXTEND) + && (code == NE || code == EQ) + && (code_x == PLUS || code_x == MINUS || code_x == NEG) + && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND + && GET_CODE (y) == SIGN_EXTEND + && GET_CODE (XEXP (y, 0)) == code_x) return CC_Vmode; /* For everything else, return CCmode. */ diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 715de93fd516..3f304c79366f 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -3598,12 +3598,11 @@ (define_insn "subv<GPI:mode>_insn" [(set (reg:CC_V CC_REGNUM) (compare:CC_V + (minus:<DWI> + (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "rk")) + (sign_extend:<DWI> (match_operand:GPI 2 "register_operand" "r"))) (sign_extend:<DWI> - (minus:GPI - (match_operand:GPI 1 "register_operand" "rk") - (match_operand:GPI 2 "register_operand" "r"))) - (minus:<DWI> (sign_extend:<DWI> (match_dup 1)) - (sign_extend:<DWI> (match_dup 2))))) + (minus:GPI (match_dup 1) (match_dup 2))))) (set (match_operand:GPI 0 "register_operand" "=r") (minus:GPI (match_dup 1) (match_dup 2)))] "" @@ -3614,12 +3613,11 @@ (define_insn "subv<GPI:mode>_imm" [(set (reg:CC_V CC_REGNUM) (compare:CC_V + (minus:<DWI> + (sign_extend:<DWI> (match_operand:GPI 1 "register_operand")) + (match_operand:GPI 2 "aarch64_plus_immediate")) (sign_extend:<DWI> - (minus:GPI - (match_operand:GPI 1 "register_operand") - (match_operand:GPI 2 "aarch64_plus_immediate"))) - (minus:<DWI> (sign_extend:<DWI> (match_dup 1)) - (match_dup 2)))) + (minus:GPI (match_dup 1) (match_dup 2))))) (set (match_operand:GPI 0 "register_operand") (minus:GPI (match_dup 1) (match_dup 2)))] "" @@ -3646,9 +3644,10 @@ (define_insn "negv<GPI:mode>_insn" [(set (reg:CC_V CC_REGNUM) (compare:CC_V + (neg:<DWI> + (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))) (sign_extend:<DWI> - (neg:GPI (match_operand:GPI 1 "register_operand" "r"))) - (neg:<DWI> (sign_extend:<DWI> (match_dup 1))))) + (neg:GPI (match_dup 1))))) (set (match_operand:GPI 0 "register_operand" "=r") (neg:GPI (match_dup 1)))] "" @@ -3659,22 +3658,23 @@ (define_insn "negv<GPI:mode>_cmp_only" [(set (reg:CC_V CC_REGNUM) (compare:CC_V + (neg:<DWI> + (sign_extend:<DWI> (match_operand:GPI 0 "register_operand" "r"))) (sign_extend:<DWI> - (neg:GPI (match_operand:GPI 0 "register_operand" "r"))) - (neg:<DWI> (sign_extend:<DWI> (match_dup 0)))))] + (neg:GPI (match_dup 0)))))] "" - "negs\\t%<w>zr, %<w>0" + "negs\\t<w>zr, %<w>0" [(set_attr "type" "alus_sreg")] ) (define_insn "*cmpv<GPI:mode>_insn" [(set (reg:CC_V CC_REGNUM) (compare:CC_V + (minus:<DWI> + (sign_extend:<DWI> (match_operand:GPI 0 "register_operand")) + (sign_extend:<DWI> (match_operand:GPI 1 "aarch64_plus_operand"))) (sign_extend:<DWI> - (minus:GPI (match_operand:GPI 0 "register_operand") - (match_operand:GPI 1 "aarch64_plus_operand"))) - (minus:<DWI> (sign_extend:<DWI> (match_dup 0)) - (sign_extend:<DWI> (match_dup 1)))))] + (minus:GPI (match_dup 0) (match_dup 1)))))] "" {@ [ cons: 0 , 1 ] [ r , r ] cmp\t%<w>0, %<w>1 diff --git a/gcc/testsuite/gcc.target/aarch64/negv.c b/gcc/testsuite/gcc.target/aarch64/negv.c new file mode 100644 index 000000000000..91abd96e8b19 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/negv.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +_Bool negvsi (int x) +{ + int result; + return __builtin_sub_overflow (0, x, &result); +} +/* +** negvsi: +** negs wzr, w0 +** cset w0, vs +** ret +*/ + +_Bool negvdi (long x) +{ + long result; + return __builtin_sub_overflow (0, x, &result); +} +/* +** negvdi: +** negs xzr, x0 +** cset w0, vs +** ret +*/
