aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2020-11-28 12:54:48 +0100
committerEric Botcazou <ebotcazou@adacore.com>2020-11-28 13:01:41 +0100
commitc04bd12b06a21ad4a9c432c109ec2a543725ad1b (patch)
treee7e3f760877b50cce72852c0bff6478f8e3d0359 /gcc
parent36ec54aac7da134441c83248e14825381b8d6f17 (diff)
downloadgcc-c04bd12b06a21ad4a9c432c109ec2a543725ad1b.zip
gcc-c04bd12b06a21ad4a9c432c109ec2a543725ad1b.tar.gz
gcc-c04bd12b06a21ad4a9c432c109ec2a543725ad1b.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/sparc/predicates.md2
-rw-r--r--gcc/config/sparc/sparc.md146
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-6.c20
3 files changed, 113 insertions, 55 deletions
diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md
index 3d49972..42316ad 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 edfb635..6e9ccb4 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 0000000..11aafc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-6.c
@@ -0,0 +1,20 @@
+/* PR target/97939 */
+/* Reported by Vincent Lefevre <vincent-gcc@vinc17.net> */
+
+/* { dg-do run } */
+
+#include <limits.h>
+
+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;
+}