From: Eric Botcazou Date: Sat, 28 Nov 2020 11:54:48 +0000 (+0100) Subject: Fix PR target/97939 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c04bd12b06a21ad4a9c432c109ec2a543725ad1b;p=gcc.git Fix PR target/97939 The little dance around 4096 that add/sub instructions do on the SPARC needs to be taken into account for the overflow arithmetic operations. It cannot be done for unsigned overflow, but it can be done for signed overflow. gcc/ChangeLog: PR target/97939 * config/sparc/predicates.md (arith_double_add_operand): Comment. * config/sparc/sparc.md (uaddvdi4): Use arith_double_operand. (addvdi4): Use arith_double_add_operand. (addsi3): Remove useless attributes. (addvsi4): Use arith_add_operand. (*cmp_ccv_plus): Likewise and add second alternative accordingly. (*cmp_ccxv_plus): Likewise. (*cmp_ccv_plus_set): Likewise. (*cmp_ccxv_plus_set): Likewise. (*cmp_ccv_plus_sltu_set): Likewise. (usubvdi4): Use arith_double_operand. (subvdi4): Use arith_double_add_operand. (subsi3): Remove useless attributes. (subvsi4): Use arith_add_operand. (*cmp_ccv_minus): Likewise and add second alternative accordingly. (*cmp_ccxv_minus): Likewise. (*cmp_ccv_minus_set): Likewise. (*cmp_ccxv_minus_set): Likewise. (*cmp_ccv_minus_sltu_set): Likewise. (negsi2): Use register_operand. (unegvsi3): Likewise. (negvsi3) Likewise. (*cmp_ccnz_neg): Likewise. (*cmp_ccxnz_neg): Likewise. (*cmp_ccnz_neg_set): Likewise. (*cmp_ccxnz_neg_set): Likewise. (*cmp_ccc_neg_set): Likewise. (*cmp_ccxc_neg_set): Likewise. (*cmp_ccc_neg_sltu_set): Likewise. (*cmp_ccv_neg): Likewise. (*cmp_ccxv_neg): Likewise. (*cmp_ccv_neg_set): Likewise. (*cmp_ccxv_neg_set): Likewise. (*cmp_ccv_neg_sltu_set): Likewise. gcc/testsuite/ChangeLog: * gcc.target/sparc/overflow-6.c: New test. --- diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md index 3d4997211ca..42316adc94e 100644 --- a/gcc/config/sparc/predicates.md +++ b/gcc/config/sparc/predicates.md @@ -296,6 +296,8 @@ if (arith_double_operand (op, mode)) return true; + /* Turning an add/sub instruction into the other changes the Carry flag + so the 4096 trick cannot be used for double operations in 32-bit mode. */ return TARGET_ARCH64 && const_4096_operand (op, mode); }) diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index edfb6353683..6e9ccb4ecfd 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -3768,10 +3768,13 @@ visl") } }) +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCXCmode. + (define_expand "uaddvdi4" [(parallel [(set (reg:CCXC CC_REG) (compare:CCXC (plus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_operand")) (match_dup 1))) (set (match_operand:DI 0 "register_operand") (plus:DI (match_dup 1) (match_dup 2)))]) @@ -3790,10 +3793,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCXVmode. + (define_expand "addvdi4" [(parallel [(set (reg:CCXV CC_REG) (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_add_operand")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) (set (match_operand:DI 0 "register_operand") @@ -3966,9 +3972,10 @@ visl") "" "@ add\t%1, %2, %0 - sub\t%1, -%2, %0" - [(set_attr "type" "*,*") - (set_attr "fptype" "*,*")]) + sub\t%1, -%2, %0") + +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCCmode. (define_expand "uaddvsi4" [(parallel [(set (reg:CCC CC_REG) @@ -3982,10 +3989,13 @@ visl") (pc)))] "") +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCVmode. + (define_expand "addvsi4" [(parallel [(set (reg:CCV CC_REG) (compare:CCV (plus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "arith_operand")) + (match_operand:SI 2 "arith_add_operand")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) (set (match_operand:SI 0 "register_operand") @@ -4094,42 +4104,50 @@ visl") (define_insn "*cmp_ccv_plus" [(set (reg:CCV CC_REG) - (compare:CCV (plus:SI (match_operand:SI 0 "register_operand" "%r") - (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (plus:SI (match_operand:SI 0 "register_operand" "%r,r") + (match_operand:SI 1 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))] "" - "addcc\t%0, %1, %%g0" + "@ + addcc\t%0, %1, %%g0 + subcc\t%0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_plus" [(set (reg:CCXV CC_REG) - (compare:CCXV (plus:DI (match_operand:DI 0 "register_operand" "%r") - (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (plus:DI (match_operand:DI 0 "register_operand" "%r,r") + (match_operand:DI 1 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))] "TARGET_ARCH64" - "addcc\t%0, %1, %%g0" + "@ + addcc\t%0, %1, %%g0 + subcc\t%0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_plus_set" [(set (reg:CCV CC_REG) - (compare:CCV (plus:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "arith_operand" "rI")) + (compare:CCV (plus:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) - (set (match_operand:SI 0 "register_operand" "=r") + (set (match_operand:SI 0 "register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] "" - "addcc\t%1, %2, %0" + "@ + addcc\t%1, %2, %0 + subcc\t%1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_plus_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand" "%r") - (match_operand:DI 2 "arith_operand" "rI")) + (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand" "%r,r") + (match_operand:DI 2 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) - (set (match_operand:DI 0 "register_operand" "=r") + (set (match_operand:DI 0 "register_operand" "=r,r") (plus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "addcc\t%1, %2, %0" + "@ + addcc\t%1, %2, %0 + subcc\t%1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_plus_sltu_set" @@ -4161,10 +4179,13 @@ visl") } }) +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCXmode. + (define_expand "usubvdi4" [(parallel [(set (reg:CCX CC_REG) (compare:CCX (match_operand:DI 1 "register_or_zero_operand") - (match_operand:DI 2 "arith_add_operand"))) + (match_operand:DI 2 "arith_double_operand"))) (set (match_operand:DI 0 "register_operand") (minus:DI (match_dup 1) (match_dup 2)))]) (set (pc) (if_then_else (ltu (reg:CCX CC_REG) (const_int 0)) @@ -4188,10 +4209,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCXVmode. + (define_expand "subvdi4" [(parallel [(set (reg:CCXV CC_REG) (compare:CCXV (minus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_add_operand")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) (set (match_operand:DI 0 "register_operand") @@ -4362,9 +4386,10 @@ visl") "" "@ sub\t%1, %2, %0 - add\t%1, -%2, %0" - [(set_attr "type" "*,*") - (set_attr "fptype" "*,*")]) + add\t%1, -%2, %0") + +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCmode. (define_expand "usubvsi4" [(parallel [(set (reg:CC CC_REG) @@ -4384,10 +4409,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCVmode. + (define_expand "subvsi4" [(parallel [(set (reg:CCV CC_REG) (compare:CCV (minus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "arith_operand")) + (match_operand:SI 2 "arith_add_operand")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) (set (match_operand:SI 0 "register_operand") @@ -4480,42 +4508,50 @@ visl") (define_insn "*cmp_ccv_minus" [(set (reg:CCV CC_REG) - (compare:CCV (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") - (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ,rJ") + (match_operand:SI 1 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))] "" - "subcc\t%r0, %1, %%g0" + "@ + subcc\t%r0, %1, %%g0 + addcc\t%r0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_minus" [(set (reg:CCXV CC_REG) - (compare:CCXV (minus:DI (match_operand:DI 0 "register_or_zero_operand" "rJ") - (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (minus:DI (match_operand:DI 0 "register_or_zero_operand" "rJ,rJ") + (match_operand:DI 1 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))] "TARGET_ARCH64" - "subcc\t%r0, %1, %%g0" + "@ + subcc\t%r0, %1, %%g0 + addcc\t%r0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_minus_set" [(set (reg:CCV CC_REG) - (compare:CCV (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") - (match_operand:SI 2 "arith_operand" "rI")) + (compare:CCV (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") + (match_operand:SI 2 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) - (set (match_operand:SI 0 "register_operand" "=r") + (set (match_operand:SI 0 "register_operand" "=r,r") (minus:SI (match_dup 1) (match_dup 2)))] "" - "subcc\t%r1, %2, %0" + "@ + subcc\t%r1, %2, %0 + addcc\t%r1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_minus_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (minus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ") - (match_operand:DI 2 "arith_operand" "rI")) + (compare:CCXV (minus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ,rJ") + (match_operand:DI 2 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) - (set (match_operand:DI 0 "register_operand" "=r") + (set (match_operand:DI 0 "register_operand" "=r,r") (minus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "subcc\t%r1, %2, %0" + "@ + subcc\t%r1, %2, %0 + addcc\t%r1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_minus_sltu_set" @@ -5766,13 +5802,13 @@ visl") (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + (neg:SI (match_operand:SI 1 "register_operand" "r")))] "" "sub\t%%g0, %1, %0") (define_expand "unegvsi3" [(parallel [(set (reg:CCC CC_REG) - (compare:CCC (not:SI (match_operand:SI 1 "arith_operand" "")) + (compare:CCC (not:SI (match_operand:SI 1 "register_operand" "")) (const_int -1))) (set (match_operand:SI 0 "register_operand" "") (neg:SI (match_dup 1)))]) @@ -5784,7 +5820,7 @@ visl") (define_expand "negvsi3" [(parallel [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" "")) + (compare:CCV (neg:SI (match_operand:SI 1 "register_operand" "")) (unspec:SI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:SI 0 "register_operand" "") (neg:SI (match_dup 1)))]) @@ -5796,7 +5832,7 @@ visl") (define_insn "*cmp_ccnz_neg" [(set (reg:CCNZ CC_REG) - (compare:CCNZ (neg:SI (match_operand:SI 0 "arith_operand" "rI")) + (compare:CCNZ (neg:SI (match_operand:SI 0 "register_operand" "r")) (const_int 0)))] "" "subcc\t%%g0, %0, %%g0" @@ -5804,7 +5840,7 @@ visl") (define_insn "*cmp_ccxnz_neg" [(set (reg:CCXNZ CC_REG) - (compare:CCXNZ (neg:DI (match_operand:DI 0 "arith_operand" "rI")) + (compare:CCXNZ (neg:DI (match_operand:DI 0 "register_operand" "r")) (const_int 0)))] "TARGET_ARCH64" "subcc\t%%g0, %0, %%g0" @@ -5812,7 +5848,7 @@ visl") (define_insn "*cmp_ccnz_neg_set" [(set (reg:CCNZ CC_REG) - (compare:CCNZ (neg:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCNZ (neg:SI (match_operand:SI 1 "register_operand" "r")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5822,7 +5858,7 @@ visl") (define_insn "*cmp_ccxnz_neg_set" [(set (reg:CCXNZ CC_REG) - (compare:CCXNZ (neg:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXNZ (neg:DI (match_operand:DI 1 "register_operand" "r")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5832,7 +5868,7 @@ visl") (define_insn "*cmp_ccc_neg_set" [(set (reg:CCC CC_REG) - (compare:CCC (not:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCC (not:SI (match_operand:SI 1 "register_operand" "r")) (const_int -1))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5842,7 +5878,7 @@ visl") (define_insn "*cmp_ccxc_neg_set" [(set (reg:CCXC CC_REG) - (compare:CCXC (not:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXC (not:DI (match_operand:DI 1 "register_operand" "r")) (const_int -1))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5853,7 +5889,7 @@ visl") (define_insn "*cmp_ccc_neg_sltu_set" [(set (reg:CCC CC_REG) (compare:CCC (zero_extend:DI - (neg:SI (plus:SI (match_operand:SI 1 "arith_operand" "rI") + (neg:SI (plus:SI (match_operand:SI 1 "register_operand" "r") (ltu:SI (reg:CCC CC_REG) (const_int 0))))) (neg:DI (plus:DI (zero_extend:DI (match_dup 1)) @@ -5868,7 +5904,7 @@ visl") (define_insn "*cmp_ccv_neg" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 0 "arith_operand" "rI")) + (compare:CCV (neg:SI (match_operand:SI 0 "register_operand" "r")) (unspec:SI [(match_dup 0)] UNSPEC_NEGV)))] "" "subcc\t%%g0, %0, %%g0" @@ -5876,7 +5912,7 @@ visl") (define_insn "*cmp_ccxv_neg" [(set (reg:CCXV CC_REG) - (compare:CCXV (neg:DI (match_operand:DI 0 "arith_operand" "rI")) + (compare:CCXV (neg:DI (match_operand:DI 0 "register_operand" "r")) (unspec:DI [(match_dup 0)] UNSPEC_NEGV)))] "TARGET_ARCH64" "subcc\t%%g0, %0, %%g0" @@ -5884,7 +5920,7 @@ visl") (define_insn "*cmp_ccv_neg_set" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (neg:SI (match_operand:SI 1 "register_operand" "r")) (unspec:SI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5894,7 +5930,7 @@ visl") (define_insn "*cmp_ccxv_neg_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (neg:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (neg:DI (match_operand:DI 1 "register_operand" "r")) (unspec:DI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5904,7 +5940,7 @@ visl") (define_insn "*cmp_ccv_neg_sltu_set" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (plus:SI (match_operand:SI 1 "arith_operand" "rI") + (compare:CCV (neg:SI (plus:SI (match_operand:SI 1 "register_operand" "r") (ltu:SI (reg:CCC CC_REG) (const_int 0)))) (unspec:SI [(plus:SI (match_dup 1) (ltu:SI (reg:CCC CC_REG) diff --git a/gcc/testsuite/gcc.target/sparc/overflow-6.c b/gcc/testsuite/gcc.target/sparc/overflow-6.c new file mode 100644 index 00000000000..11aafc581da --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/overflow-6.c @@ -0,0 +1,20 @@ +/* PR target/97939 */ +/* Reported by Vincent Lefevre */ + +/* { dg-do run } */ + +#include + +long add (long i) +{ + long r; + if (!__builtin_add_overflow (i, 4096, &r)) + __builtin_abort (); + return r; +} + +int main (void) +{ + add (LONG_MAX); + return 0; +}