aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2016-10-21 09:16:29 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2016-10-21 09:16:29 +0000
commit8572922996bd2db0400ccbf5043b1fdbff2fd936 (patch)
tree1c3213226bdaf9d03e4c453e15e1c9b5701c2a83
parentd17f2c3b496cce8c1eea2dab929c28e5899f9cc4 (diff)
downloadgcc-8572922996bd2db0400ccbf5043b1fdbff2fd936.zip
gcc-8572922996bd2db0400ccbf5043b1fdbff2fd936.tar.gz
gcc-8572922996bd2db0400ccbf5043b1fdbff2fd936.tar.bz2
sparc-modes.def (CCV): New.
* config/sparc/sparc-modes.def (CCV): New. (CCXV): Likewise. * config/sparc/predicates.md (v_comparison_operator): New. (icc_comparison_operator): Add support for CCV/CCXV. (xcc_comparison_operator): Likewise. * config/sparc/sparc.c (output_cbranch): Likewise. (sparc_print_operand): Likewise. * config/sparc/sparc.md (UNSPEC_{ADD,SUB,NEG}V): New constants. (uaddvdi4): New expander. (addvdi4): Likewise. (uaddvdi4_sp32): New instruction. (addvdi4_sp32): Likewise. (uaddvsi4): New expander. (addvsi4): Likewise. (cmp_ccc_plus_sltu_set): New instruction. (cmp_ccv_plus): Likewise. (cmp_ccxv_plus): Likewise. (cmp_ccv_plus_set): Likewise. (cmp_ccxv_plus_set): Likewise. (cmp_ccv_plus_sltu_set): Likewise. (uaddvdi4): New expander. (subvdi4): Likewise. (usubdi4_sp32): New instruction. (subvdi4_sp32): Likewise. (usubvsi4): New expander. (subvsi4): Likewise. (cmpsi_minus_sltu_set): New instruction. (cmp_ccv_minus): Likewise. (cmp_ccxv_minus): Likewise. (cmp_ccv_minus_set): Likewise. (cmp_ccxv_minus_set): Likewise. (cmp_ccv_minus_sltu_set): Likewise. (unegvdi3): New expander. (negvdi3): Likewise. (unegdi3_sp32): New instruction. (negvdi3_sp32): Likewise. (unegvsi3): New expander. (negvsi3): Likewise. (cmp_ccc_neg_sltu_set): New instruction. (cmp_ccv_neg): Likewise. (cmp_ccxv_neg): Likewise. (cmp_ccv_neg_set): Likewise. (cmp_ccxv_neg_set): Likewise. (cmp_ccv_neg_sltu_set): Likewise. From-SVN: r241397
-rw-r--r--gcc/ChangeLog47
-rw-r--r--gcc/config/sparc/predicates.md7
-rw-r--r--gcc/config/sparc/sparc-modes.def6
-rw-r--r--gcc/config/sparc/sparc.c41
-rw-r--r--gcc/config/sparc/sparc.md645
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-1.c43
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-2.c46
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-3.c44
9 files changed, 879 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bd7e968..c74ba17 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,50 @@
+2016-10-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * config/sparc/sparc-modes.def (CCV): New.
+ (CCXV): Likewise.
+ * config/sparc/predicates.md (v_comparison_operator): New.
+ (icc_comparison_operator): Add support for CCV/CCXV.
+ (xcc_comparison_operator): Likewise.
+ * config/sparc/sparc.c (output_cbranch): Likewise.
+ (sparc_print_operand): Likewise.
+ * config/sparc/sparc.md (UNSPEC_{ADD,SUB,NEG}V): New constants.
+ (uaddvdi4): New expander.
+ (addvdi4): Likewise.
+ (uaddvdi4_sp32): New instruction.
+ (addvdi4_sp32): Likewise.
+ (uaddvsi4): New expander.
+ (addvsi4): Likewise.
+ (cmp_ccc_plus_sltu_set): New instruction.
+ (cmp_ccv_plus): Likewise.
+ (cmp_ccxv_plus): Likewise.
+ (cmp_ccv_plus_set): Likewise.
+ (cmp_ccxv_plus_set): Likewise.
+ (cmp_ccv_plus_sltu_set): Likewise.
+ (uaddvdi4): New expander.
+ (subvdi4): Likewise.
+ (usubdi4_sp32): New instruction.
+ (subvdi4_sp32): Likewise.
+ (usubvsi4): New expander.
+ (subvsi4): Likewise.
+ (cmpsi_minus_sltu_set): New instruction.
+ (cmp_ccv_minus): Likewise.
+ (cmp_ccxv_minus): Likewise.
+ (cmp_ccv_minus_set): Likewise.
+ (cmp_ccxv_minus_set): Likewise.
+ (cmp_ccv_minus_sltu_set): Likewise.
+ (unegvdi3): New expander.
+ (negvdi3): Likewise.
+ (unegdi3_sp32): New instruction.
+ (negvdi3_sp32): Likewise.
+ (unegvsi3): New expander.
+ (negvsi3): Likewise.
+ (cmp_ccc_neg_sltu_set): New instruction.
+ (cmp_ccv_neg): Likewise.
+ (cmp_ccxv_neg): Likewise.
+ (cmp_ccv_neg_set): Likewise.
+ (cmp_ccxv_neg_set): Likewise.
+ (cmp_ccv_neg_sltu_set): Likewise.
+
2016-10-21 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR rtl-optimization/78038
diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md
index dd57bf5..05ed68a 100644
--- a/gcc/config/sparc/predicates.md
+++ b/gcc/config/sparc/predicates.md
@@ -420,6 +420,10 @@
(define_predicate "c_comparison_operator"
(match_code "ltu,geu"))
+;; Return true if OP is a valid comparison operator for CCVmode.
+(define_predicate "v_comparison_operator"
+ (match_code "eq,ne"))
+
;; Return true if OP is an integer comparison operator. This allows
;; the use of MATCH_OPERATOR to recognize all the branch insns.
(define_predicate "icc_comparison_operator"
@@ -436,6 +440,9 @@
case CCCmode:
case CCXCmode:
return c_comparison_operator (op, mode);
+ case CCVmode:
+ case CCXVmode:
+ return v_comparison_operator (op, mode);
default:
return false;
}
diff --git a/gcc/config/sparc/sparc-modes.def b/gcc/config/sparc/sparc-modes.def
index 9c6fe03..6c3eadf 100644
--- a/gcc/config/sparc/sparc-modes.def
+++ b/gcc/config/sparc/sparc-modes.def
@@ -34,6 +34,10 @@ FLOAT_MODE (TF, 16, ieee_quad_format);
they explicitly set the C flag (unsigned overflow). Only the unsigned
<,>= operators can be used in conjunction with it.
+ We also have a CCVmode which is used by the arithmetic instructions when
+ they explicitly set the V flag (signed overflow). Only the =,!= operators
+ can be used in conjunction with it.
+
We also have two modes to indicate that the relevant condition code is
in the floating-point condition code register. One for comparisons which
will generate an exception if the result is unordered (CCFPEmode) and
@@ -46,6 +50,8 @@ CC_MODE (CCNZ);
CC_MODE (CCXNZ);
CC_MODE (CCC);
CC_MODE (CCXC);
+CC_MODE (CCV);
+CC_MODE (CCXV);
CC_MODE (CCFP);
CC_MODE (CCFPE);
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 4b878c1..9fda438 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -2784,8 +2784,9 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y)
gcc_unreachable ();
}
}
- else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
- || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+ else if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
+ || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+ && y == const0_rtx)
{
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCXNZmode;
@@ -2803,6 +2804,18 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y)
return CCCmode;
}
+ /* This is for the [u]addvdi4_sp32 and [u]subvdi4_sp32 patterns. */
+ if (!TARGET_ARCH64 && GET_MODE (x) == DImode)
+ {
+ if (GET_CODE (y) == UNSPEC
+ && (XINT (y, 1) == UNSPEC_ADDV
+ || XINT (y, 1) == UNSPEC_SUBV
+ || XINT (y, 1) == UNSPEC_NEGV))
+ return CCVmode;
+ else
+ return CCCmode;
+ }
+
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCXmode;
else
@@ -7724,10 +7737,16 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
switch (code)
{
case NE:
- branch = "bne";
+ if (mode == CCVmode || mode == CCXVmode)
+ branch = "bvs";
+ else
+ branch = "bne";
break;
case EQ:
- branch = "be";
+ if (mode == CCVmode || mode == CCXVmode)
+ branch = "bvc";
+ else
+ branch = "be";
break;
case GE:
if (mode == CCNZmode || mode == CCXNZmode)
@@ -7794,6 +7813,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
case CCmode:
case CCNZmode:
case CCCmode:
+ case CCVmode:
labelno = "%%icc, ";
if (v8)
labelno = "";
@@ -7801,6 +7821,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
case CCXmode:
case CCXNZmode:
case CCXCmode:
+ case CCXVmode:
labelno = "%%xcc, ";
gcc_assert (!v8);
break;
@@ -8804,11 +8825,13 @@ sparc_print_operand (FILE *file, rtx x, int code)
case CCmode:
case CCNZmode:
case CCCmode:
+ case CCVmode:
s = "%icc";
break;
case CCXmode:
case CCXNZmode:
case CCXCmode:
+ case CCXVmode:
s = "%xcc";
break;
default:
@@ -8883,10 +8906,16 @@ sparc_print_operand (FILE *file, rtx x, int code)
switch (GET_CODE (x))
{
case NE:
- s = "ne";
+ if (mode == CCVmode || mode == CCXVmode)
+ s = "vs";
+ else
+ s = "ne";
break;
case EQ:
- s = "e";
+ if (mode == CCVmode || mode == CCXVmode)
+ s = "vc";
+ else
+ s = "e";
break;
case GE:
if (mode == CCNZmode || mode == CCXNZmode)
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 64376c7..9e66513 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -92,6 +92,10 @@
UNSPEC_MUL8
UNSPEC_MUL8SU
UNSPEC_MULDSU
+
+ UNSPEC_ADDV
+ UNSPEC_SUBV
+ UNSPEC_NEGV
])
(define_c_enum "unspecv" [
@@ -3714,6 +3718,51 @@
}
})
+(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_dup 1)))
+ (set (match_operand:DI 0 "register_operand")
+ (plus:DI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ltu (reg:CCXC CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_uaddvdi4_sp32 (operands[0], operands[1], operands[2]));
+ rtx x = gen_rtx_LTU (VOIDmode, gen_rtx_REG (CCCmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[3]));
+ DONE;
+ }
+})
+
+(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"))
+ (unspec:DI [(match_dup 1) (match_dup 2)]
+ UNSPEC_ADDV)))
+ (set (match_operand:DI 0 "register_operand")
+ (plus:DI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ne (reg:CCXV CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_addvdi4_sp32 (operands[0], operands[1], operands[2]));
+ rtx x = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCVmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[3]));
+ DONE;
+ }
+})
+
(define_insn_and_split "adddi3_sp32"
[(set (match_operand:DI 0 "register_operand" "=&r")
(plus:DI (match_operand:DI 1 "register_operand" "%r")
@@ -3740,6 +3789,80 @@
}
[(set_attr "length" "2")])
+(define_insn_and_split "uaddvdi4_sp32"
+ [(set (reg:CCC CC_REG)
+ (compare:CCC (plus:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (match_dup 1)))
+ (set (match_operand:DI 0 "register_operand" "=&r")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (plus:SI (match_dup 4) (match_dup 5))
+ (match_dup 4)))
+ (set (match_dup 3)
+ (plus:SI (match_dup 4) (match_dup 5)))])
+ (parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (zero_extend:DI
+ (plus:SI (plus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0))))
+ (plus:DI (plus:DI (zero_extend:DI (match_dup 7))
+ (zero_extend:DI (match_dup 8)))
+ (ltu:DI (reg:CCC CC_REG)
+ (const_int 0)))))
+ (set (match_dup 6)
+ (plus:SI (plus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0))))])]
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
+}
+ [(set_attr "length" "2")])
+
+(define_insn_and_split "addvdi4_sp32"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (plus:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))
+ (set (match_operand:DI 0 "register_operand" "=&r")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (plus:SI (match_dup 4) (match_dup 5))
+ (match_dup 4)))
+ (set (match_dup 3)
+ (plus:SI (match_dup 4) (match_dup 5)))])
+ (parallel [(set (reg:CCV CC_REG)
+ (compare:CCV (plus:SI (plus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))
+ (unspec:SI [(plus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0))]
+ UNSPEC_ADDV)))
+ (set (match_dup 6)
+ (plus:SI (plus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))))])]
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
+}
+ [(set_attr "length" "2")])
+
(define_insn_and_split "*addx_extend_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (plus:SI (plus:SI
@@ -3797,6 +3920,31 @@
[(set_attr "type" "*,*")
(set_attr "fptype" "*,*")])
+(define_expand "uaddvsi4"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (plus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "arith_operand"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "register_operand")
+ (plus:SI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ltu (reg:CCC CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ "")
+
+(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"))
+ (unspec:SI [(match_dup 1) (match_dup 2)]
+ UNSPEC_ADDV)))
+ (set (match_operand:SI 0 "register_operand")
+ (plus:SI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ne (reg:CCV CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ "")
+
(define_insn "*cmp_ccnz_plus"
[(set (reg:CCNZ CC_REG)
(compare:CCNZ (plus:SI (match_operand:SI 0 "register_operand" "%r")
@@ -3877,6 +4025,79 @@
"addcc\t%1, %2, %0"
[(set_attr "type" "compare")])
+(define_insn "*cmp_ccc_plus_sltu_set"
+ [(set (reg:CCC CC_REG)
+ (compare:CCC (zero_extend:DI
+ (plus:SI
+ (plus:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))))
+ (plus:DI (plus:DI (zero_extend:DI (match_dup 1))
+ (zero_extend:DI (match_dup 2)))
+ (ltu:DI (reg:CCC CC_REG) (const_int 0)))))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (plus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))))]
+ ""
+ "addxcc\t%1, %2, %0"
+ [(set_attr "type" "compare")])
+
+(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"))
+ (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))]
+ ""
+ "addcc\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"))
+ (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))]
+ "TARGET_ARCH64"
+ "addcc\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"))
+ (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "addcc\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"))
+ (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_ARCH64"
+ "addcc\t%1, %2, %0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccv_plus_sltu_set"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (plus:SI (plus:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0)))
+ (unspec:SI [(plus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))]
+ UNSPEC_ADDV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (plus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))))]
+ ""
+ "addxcc\t%1, %2, %0"
+ [(set_attr "type" "compare")])
+
+
(define_expand "subdi3"
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
@@ -3890,6 +4111,56 @@
}
})
+(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")))
+ (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))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (operands[1] == const0_rtx)
+ {
+ emit_insn (gen_unegvdi3 (operands[0], operands[2], operands[3]));
+ DONE;
+ }
+
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_usubvdi4_sp32 (operands[0], operands[1], operands[2]));
+ rtx x = gen_rtx_LTU (VOIDmode, gen_rtx_REG (CCCmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[3]));
+ DONE;
+ }
+})
+
+(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"))
+ (unspec:DI [(match_dup 1) (match_dup 2)]
+ UNSPEC_SUBV)))
+ (set (match_operand:DI 0 "register_operand")
+ (minus:DI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ne (reg:CCXV CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_subvdi4_sp32 (operands[0], operands[1], operands[2]));
+ rtx x = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCVmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[3]));
+ DONE;
+ }
+})
+
(define_insn_and_split "subdi3_sp32"
[(set (match_operand:DI 0 "register_operand" "=&r")
(minus:DI (match_operand:DI 1 "register_operand" "r")
@@ -3915,6 +4186,80 @@
}
[(set_attr "length" "2")])
+(define_insn_and_split "usubvdi4_sp32"
+ [(set (reg:CCC CC_REG)
+ (compare:CCC (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (set (match_operand:DI 0 "register_operand" "=&r")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CC CC_REG)
+ (compare:CC (match_dup 4) (match_dup 5)))
+ (set (match_dup 3)
+ (minus:SI (match_dup 4) (match_dup 5)))])
+ (parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (zero_extend:DI
+ (minus:SI (minus:SI (match_dup 7)
+ (ltu:SI (reg:CC CC_REG)
+ (const_int 0)))
+ (match_dup 8)))
+ (minus:DI
+ (minus:DI (zero_extend:DI (match_dup 7))
+ (ltu:DI (reg:CC CC_REG)
+ (const_int 0)))
+ (zero_extend:DI (match_dup 8)))))
+ (set (match_dup 6)
+ (minus:SI (minus:SI (match_dup 7)
+ (ltu:SI (reg:CC CC_REG)
+ (const_int 0)))
+ (match_dup 8)))])]
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
+}
+ [(set_attr "length" "2")])
+
+(define_insn_and_split "subvdi4_sp32"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (minus:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))
+ (set (match_operand:DI 0 "register_operand" "=&r")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CC CC_REG)
+ (compare:CC (match_dup 4) (match_dup 5)))
+ (set (match_dup 3)
+ (minus:SI (match_dup 4) (match_dup 5)))])
+ (parallel [(set (reg:CCV CC_REG)
+ (compare:CCV (minus:SI (minus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CC CC_REG)
+ (const_int 0)))
+ (unspec:SI [(minus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CC CC_REG)
+ (const_int 0))]
+ UNSPEC_SUBV)))
+ (set (match_dup 6)
+ (minus:SI (minus:SI (match_dup 7) (match_dup 8))
+ (ltu:SI (reg:CC CC_REG) (const_int 0))))])]
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
+}
+ [(set_attr "length" "2")])
+
(define_insn_and_split "*subx_extend_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (minus:SI (minus:SI
@@ -3971,6 +4316,37 @@
[(set_attr "type" "*,*")
(set_attr "fptype" "*,*")])
+(define_expand "usubvsi4"
+ [(parallel [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 1 "register_or_zero_operand")
+ (match_operand:SI 2 "arith_operand")))
+ (set (match_operand:SI 0 "register_operand")
+ (minus:SI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ltu (reg:CC CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (operands[1] == const0_rtx)
+ {
+ emit_insn (gen_unegvsi3 (operands[0], operands[2], operands[3]));
+ DONE;
+ }
+})
+
+(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"))
+ (unspec:SI [(match_dup 1) (match_dup 2)]
+ UNSPEC_SUBV)))
+ (set (match_operand:SI 0 "register_operand")
+ (minus:SI (match_dup 1) (match_dup 2)))])
+ (set (pc) (if_then_else (ne (reg:CCV CC_REG) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ "")
+
(define_insn "*cmp_ccnz_minus"
[(set (reg:CCNZ CC_REG)
(compare:CCNZ (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
@@ -4031,6 +4407,82 @@
"subcc\t%r1, %2, %0"
[(set_attr "type" "compare")])
+(define_insn "*cmp_ccc_minus_sltu_set"
+ [(set (reg:CCC CC_REG)
+ (compare:CCC (zero_extend:DI
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 1 "register_or_zero_operand" "rJ")
+ (ltu:SI (reg:CC CC_REG) (const_int 0)))
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (minus:DI
+ (minus:DI
+ (zero_extend:DI (match_dup 1))
+ (ltu:DI (reg:CC CC_REG) (const_int 0)))
+ (zero_extend:DI (match_dup 2)))))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_dup 1)
+ (ltu:SI (reg:CC CC_REG) (const_int 0)))
+ (match_dup 2)))]
+ ""
+ "subxcc\t%r1, %2, %0"
+ [(set_attr "type" "compare")])
+
+(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"))
+ (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))]
+ ""
+ "subcc\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"))
+ (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))]
+ "TARGET_ARCH64"
+ "subcc\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"))
+ (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "subcc\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"))
+ (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_ARCH64"
+ "subcc\t%r1, %2, %0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccv_minus_sltu_set"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (minus:SI (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC CC_REG) (const_int 0)))
+ (unspec:SI [(minus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CC CC_REG) (const_int 0))]
+ UNSPEC_SUBV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CC CC_REG) (const_int 0))))]
+ ""
+ "subxcc\t%1, %2, %0"
+ [(set_attr "type" "compare")])
+
;; Integer multiply/divide instructions.
@@ -5127,6 +5579,50 @@
}
})
+(define_expand "unegvdi3"
+ [(parallel [(set (reg:CCXC CC_REG)
+ (compare:CCXC (not:DI (match_operand:DI 1 "register_operand" ""))
+ (const_int -1)))
+ (set (match_operand:DI 0 "register_operand" "")
+ (neg:DI (match_dup 1)))])
+ (set (pc)
+ (if_then_else (ltu (reg:CCXC CC_REG) (const_int 0))
+ (label_ref (match_operand 2 ""))
+ (pc)))]
+ ""
+{
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_unegvdi3_sp32 (operands[0], operands[1]));
+ rtx x = gen_rtx_LTU (VOIDmode, gen_rtx_REG (CCCmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[2]));
+ DONE;
+ }
+})
+
+(define_expand "negvdi3"
+ [(parallel [(set (reg:CCXV CC_REG)
+ (compare:CCXV (neg:DI (match_operand:DI 1 "register_operand" ""))
+ (unspec:DI [(match_dup 1)] UNSPEC_NEGV)))
+ (set (match_operand:DI 0 "register_operand" "")
+ (neg:DI (match_dup 1)))])
+ (set (pc)
+ (if_then_else (ne (reg:CCXV CC_REG) (const_int 0))
+ (label_ref (match_operand 2 ""))
+ (pc)))]
+ ""
+{
+ if (!TARGET_64BIT)
+ {
+ emit_insn (gen_negvdi3_sp32 (operands[0], operands[1]));
+ rtx x = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCVmode, SPARC_ICC_REG),
+ const0_rtx);
+ emit_jump_insn (gen_cbranchcc4 (x, XEXP (x, 0), XEXP (x, 1), operands[2]));
+ DONE;
+ }
+})
+
(define_insn_and_split "negdi2_sp32"
[(set (match_operand:DI 0 "register_operand" "=&r")
(neg:DI (match_operand:DI 1 "register_operand" "r")))
@@ -5145,6 +5641,64 @@
operands[5] = gen_lowpart (SImode, operands[1]);"
[(set_attr "length" "2")])
+(define_insn_and_split "unegvdi3_sp32"
+ [(set (reg:CCC CC_REG)
+ (compare:CCC (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)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (not:SI (match_dup 5)) (const_int -1)))
+ (set (match_dup 4) (neg:SI (match_dup 5)))])
+ (parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (zero_extend:DI
+ (neg:SI (plus:SI (match_dup 3)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))))
+ (neg:DI (plus:DI (zero_extend:DI (match_dup 3))
+ (ltu:DI (reg:CCC CC_REG)
+ (const_int 0))))))
+ (set (match_dup 2) (neg:SI (plus:SI (match_dup 3)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))))])]
+ "operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart (SImode, operands[1]);
+ operands[4] = gen_lowpart (SImode, operands[0]);
+ operands[5] = gen_lowpart (SImode, operands[1]);"
+ [(set_attr "length" "2")])
+
+(define_insn_and_split "negvdi3_sp32"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (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)))]
+ "!TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (not:SI (match_dup 5)) (const_int -1)))
+ (set (match_dup 4) (neg:SI (match_dup 5)))])
+ (parallel [(set (reg:CCV CC_REG)
+ (compare:CCV (neg:SI (plus:SI (match_dup 3)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0))))
+ (unspec:SI [(plus:SI (match_dup 3)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))]
+ UNSPEC_NEGV)))
+ (set (match_dup 2) (neg:SI (plus:SI (match_dup 3)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))))])]
+ "operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart (SImode, operands[1]);
+ operands[4] = gen_lowpart (SImode, operands[0]);
+ operands[5] = gen_lowpart (SImode, operands[1]);"
+ [(set_attr "length" "2")])
+
(define_insn "*negdi2_sp64"
[(set (match_operand:DI 0 "register_operand" "=r")
(neg:DI (match_operand:DI 1 "register_operand" "r")))]
@@ -5157,6 +5711,30 @@
""
"sub\t%%g0, %1, %0")
+(define_expand "unegvsi3"
+ [(parallel [(set (reg:CCC CC_REG)
+ (compare:CCC (not:SI (match_operand:SI 1 "arith_operand" ""))
+ (const_int -1)))
+ (set (match_operand:SI 0 "register_operand" "")
+ (neg:SI (match_dup 1)))])
+ (set (pc)
+ (if_then_else (ltu (reg:CCC CC_REG) (const_int 0))
+ (label_ref (match_operand 2 ""))
+ (pc)))]
+ "")
+
+(define_expand "negvsi3"
+ [(parallel [(set (reg:CCV CC_REG)
+ (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" ""))
+ (unspec:SI [(match_dup 1)] UNSPEC_NEGV)))
+ (set (match_operand:SI 0 "register_operand" "")
+ (neg:SI (match_dup 1)))])
+ (set (pc)
+ (if_then_else (ne (reg:CCV CC_REG) (const_int 0))
+ (label_ref (match_operand 2 ""))
+ (pc)))]
+"")
+
(define_insn "*cmp_ccnz_neg"
[(set (reg:CCNZ CC_REG)
(compare:CCNZ (neg:SI (match_operand:SI 0 "arith_operand" "rI"))
@@ -5213,6 +5791,73 @@
"subcc\t%%g0, %1, %0"
[(set_attr "type" "compare")])
+(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")
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))))
+ (neg:DI (plus:DI (zero_extend:DI (match_dup 1))
+ (ltu:DI (reg:CCC CC_REG)
+ (const_int 0))))))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (plus:SI (match_dup 1)
+ (ltu:SI (reg:CCC CC_REG) (const_int 0)))))]
+ ""
+ "subxcc\t%%g0, %1, %0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccv_neg"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (neg:SI (match_operand:SI 0 "arith_operand" "rI"))
+ (unspec:SI [(match_dup 0)] UNSPEC_NEGV)))]
+ ""
+ "subcc\t%%g0, %0, %%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccxv_neg"
+ [(set (reg:CCXV CC_REG)
+ (compare:CCXV (neg:DI (match_operand:DI 0 "arith_operand" "rI"))
+ (unspec:DI [(match_dup 0)] UNSPEC_NEGV)))]
+ "TARGET_ARCH64"
+ "subcc\t%%g0, %0, %%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccv_neg_set"
+ [(set (reg:CCV CC_REG)
+ (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" "rI"))
+ (unspec:SI [(match_dup 1)] UNSPEC_NEGV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_dup 1)))]
+ ""
+ "subcc\t%%g0, %1, %0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccxv_neg_set"
+ [(set (reg:CCXV CC_REG)
+ (compare:CCXV (neg:DI (match_operand:DI 1 "arith_operand" "rI"))
+ (unspec:DI [(match_dup 1)] UNSPEC_NEGV)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_dup 1)))]
+ "TARGET_ARCH64"
+ "subcc\t%%g0, %1, %0"
+ [(set_attr "type" "compare")])
+
+(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")
+ (ltu:SI (reg:CCC CC_REG) (const_int 0))))
+ (unspec:SI [(plus:SI (match_dup 1)
+ (ltu:SI (reg:CCC CC_REG)
+ (const_int 0)))]
+ UNSPEC_NEGV)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (plus:SI (match_dup 1)
+ (ltu:SI (reg:CCC CC_REG) (const_int 0)))))]
+ ""
+ "subxcc\t%%g0, %1, %0"
+ [(set_attr "type" "compare")])
+
(define_insn "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=r")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index aaa683f..0e32435 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2016-10-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.target/sparc/overflow-1.c: New test.
+ * gcc.target/sparc/overflow-2.c: Likewise.
+ * gcc.target/sparc/overflow-3.c: Likewise.
+
2016-10-21 Andre Vieira <andre.simoesdiasvieira@arm.com>
* gcc.target/arm/pure-code/pure-code.exp: Require arm_cortex_m
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-1.c b/gcc/testsuite/gcc.target/sparc/overflow-1.c
new file mode 100644
index 0000000..e3fa0d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-1.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mcpu=v8" } */
+/* { dg-require-effective-target ilp32 } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool my_uadd_overflow (uint32_t a, uint32_t b, uint32_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (uint32_t a, uint32_t b, uint32_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (uint32_t a, uint32_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int32_t a, int32_t b, int32_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int32_t a, int32_t b, int32_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int32_t a, int32_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "addx\t%" 3 } } */
+/* { dg-final { scan-assembler-times "bvs" 3 } } */
+/* { dg-final { scan-assembler-not "cmp\t%" } } */
+/* { dg-final { scan-assembler-not "save\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-2.c b/gcc/testsuite/gcc.target/sparc/overflow-2.c
new file mode 100644
index 0000000..9e42bd2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-2.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mcpu=v8" } */
+/* { dg-require-effective-target ilp32 } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool my_uadd_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (uint64_t a, uint64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int64_t a, int64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "addxcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "subxcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "addx\t%" 2 } } */
+/* { dg-final { scan-assembler-times "blu" 1 } } */
+/* { dg-final { scan-assembler-times "bvs" 3 } } */
+/* { dg-final { scan-assembler-not "cmp\t%" } } */
+/* { dg-final { scan-assembler-not "save\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-3.c b/gcc/testsuite/gcc.target/sparc/overflow-3.c
new file mode 100644
index 0000000..31b3264
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-3.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-require-effective-target lp64 } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool my_uadd_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (uint64_t a, uint64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int64_t a, int64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "movlu\t%" 1 } } */
+/* { dg-final { scan-assembler-times "blu" 2 } } */
+/* { dg-final { scan-assembler-times "bvs" 3 } } */
+/* { dg-final { scan-assembler-not "cmp\t%" } } */
+/* { dg-final { scan-assembler-not "save\t%" } } */