From 8572922996bd2db0400ccbf5043b1fdbff2fd936 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 21 Oct 2016 09:16:29 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 47 ++ gcc/config/sparc/predicates.md | 7 + gcc/config/sparc/sparc-modes.def | 6 + gcc/config/sparc/sparc.c | 41 +- gcc/config/sparc/sparc.md | 645 ++++++++++++++++++++ gcc/testsuite/ChangeLog | 6 + gcc/testsuite/gcc.target/sparc/overflow-1.c | 43 ++ gcc/testsuite/gcc.target/sparc/overflow-2.c | 46 ++ gcc/testsuite/gcc.target/sparc/overflow-3.c | 44 ++ 9 files changed, 879 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/sparc/overflow-1.c create mode 100644 gcc/testsuite/gcc.target/sparc/overflow-2.c create mode 100644 gcc/testsuite/gcc.target/sparc/overflow-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd7e9680d8c..c74ba1729b8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,50 @@ +2016-10-21 Eric Botcazou + + * 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 PR rtl-optimization/78038 diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md index dd57bf5e52f..05ed68a1465 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 9c6fe039164..6c3eadfb69c 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 4b878c1fcdd..9fda4387ea3 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 64376c7cad3..9e665130e1a 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 aaa683f9f37..0e32435bba4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-10-21 Eric Botcazou + + * 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 * 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 00000000000..e3fa0d04573 --- /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 +#include + +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 00000000000..9e42bd214de --- /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 +#include + +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 00000000000..31b326486ee --- /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 +#include + +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%" } } */ -- 2.30.2