Fix PR target/97939
authorEric Botcazou <ebotcazou@adacore.com>
Sat, 28 Nov 2020 11:54:48 +0000 (12:54 +0100)
committerEric Botcazou <ebotcazou@adacore.com>
Sat, 28 Nov 2020 12:01:41 +0000 (13:01 +0100)
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.

gcc/config/sparc/predicates.md
gcc/config/sparc/sparc.md
gcc/testsuite/gcc.target/sparc/overflow-6.c [new file with mode: 0644]

index 3d4997211ca70b34eacca864e30cf2c5d8fabdd8..42316adc94e01fe12bca40416b500e7dcba38d1d 100644 (file)
   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);
 })
 
index edfb6353683d1f7f525d309f3666ede387255e1b..6e9ccb4ecfd7b69e859a760d916a23f27b5b0b5a 100644 (file)
@@ -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 (file)
index 0000000..11aafc5
--- /dev/null
@@ -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;
+}