aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2019-10-18 19:04:38 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2019-10-18 19:04:38 +0000
commitfa62df0e600ef617bce549d64026c0e5cc817c31 (patch)
tree56583c6d248e02eafd0d9dde04728a3aa05e74dd /gcc/config
parentdb962d0ad4501f2f673fc3fadd4ac572ef9a177e (diff)
downloadgcc-fa62df0e600ef617bce549d64026c0e5cc817c31.zip
gcc-fa62df0e600ef617bce549d64026c0e5cc817c31.tar.gz
gcc-fa62df0e600ef617bce549d64026c0e5cc817c31.tar.bz2
[arm] Early split addvdi4
This patch adds early splitting for addvdi4; it's very similar to the uaddvdi4 splitter, but the details are just different enough in places, especially for the patterns that match the splitting, where we have to compare against the non-widened version to detect if overflow occurred. I've also added a testcase to the testsuite for a couple of constants that caught me out during the development of this patch. They're probably arm-specific values, but the test is generic enough that I've included it for all targets. [gcc] * config/arm/arm.c (arm_select_cc_mode): Allow either the first or second operand of the PLUS inside a DImode equality test to be sign-extend when selecting CC_Vmode. * config/arm/arm.md (addvdi4): Early-split the operation into SImode instructions. (addsi3_cin_vout_reg, addsi3_cin_vout_imm, addsi3_cin_vout_0): New expand patterns. (addsi3_cin_vout_reg_insn, addsi3_cin_vout_imm_insn): New patterns. (addsi3_cin_vout_0): Likewise. (adddi3_compareV): Delete. [gcc/testsuite] * gcc.dg/builtin-arith-overflow-3.c: New test. From-SVN: r277186
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/arm/arm.c3
-rw-r--r--gcc/config/arm/arm.md181
2 files changed, 162 insertions, 22 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index ba23970..fe240b2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -15414,7 +15414,8 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
if (GET_MODE (x) == DImode
&& (op == EQ || op == NE)
&& GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+ && (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+ || GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
&& GET_CODE (y) == SIGN_EXTEND
&& GET_CODE (XEXP (y, 0)) == PLUS)
return CC_Vmode;
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index be002f7..e9e0ca9 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -505,18 +505,173 @@
})
(define_expand "addvdi4"
- [(match_operand:DI 0 "register_operand")
- (match_operand:DI 1 "register_operand")
- (match_operand:DI 2 "register_operand")
+ [(match_operand:DI 0 "s_register_operand")
+ (match_operand:DI 1 "s_register_operand")
+ (match_operand:DI 2 "reg_or_int_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
- emit_insn (gen_adddi3_compareV (operands[0], operands[1], operands[2]));
- arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+ rtx lo_result, hi_result;
+ rtx lo_op1, hi_op1, lo_op2, hi_op2;
+ arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
+ &lo_op2, &hi_op2);
+ lo_result = gen_lowpart (SImode, operands[0]);
+ hi_result = gen_highpart (SImode, operands[0]);
+
+ if (lo_op2 == const0_rtx)
+ {
+ emit_move_insn (lo_result, lo_op1);
+ if (!arm_add_operand (hi_op2, SImode))
+ hi_op2 = force_reg (SImode, hi_op2);
+
+ emit_insn (gen_addvsi4 (hi_result, hi_op1, hi_op2, operands[3]));
+ }
+ else
+ {
+ if (!arm_add_operand (lo_op2, SImode))
+ lo_op2 = force_reg (SImode, lo_op2);
+ if (!arm_not_operand (hi_op2, SImode))
+ hi_op2 = force_reg (SImode, hi_op2);
+
+ emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
+
+ if (hi_op2 == const0_rtx)
+ emit_insn (gen_addsi3_cin_vout_0 (hi_result, hi_op1));
+ else if (CONST_INT_P (hi_op2))
+ emit_insn (gen_addsi3_cin_vout_imm (hi_result, hi_op1, hi_op2));
+ else
+ emit_insn (gen_addsi3_cin_vout_reg (hi_result, hi_op1, hi_op2));
+
+ arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+ }
DONE;
})
+(define_expand "addsi3_cin_vout_reg"
+ [(parallel
+ [(set (match_dup 3)
+ (compare:CC_V
+ (plus:DI
+ (plus:DI (match_dup 4)
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+ (sign_extend:DI (match_operand:SI 2 "s_register_operand")))
+ (sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+ (match_dup 2)))))
+ (set (match_operand:SI 0 "s_register_operand")
+ (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+ (match_dup 2)))])]
+ "TARGET_32BIT"
+ {
+ operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+ rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+ operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+ operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+ }
+)
+
+(define_insn "*addsi3_cin_vout_reg_insn"
+ [(set (reg:CC_V CC_REGNUM)
+ (compare:CC_V
+ (plus:DI
+ (plus:DI
+ (match_operand:DI 3 "arm_carry_operation" "")
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
+ (sign_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
+ (sign_extend:DI
+ (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+ (match_dup 1))
+ (match_dup 2)))))
+ (set (match_operand:SI 0 "s_register_operand" "=l,r")
+ (plus:SI (plus:SI (match_dup 4) (match_dup 1))
+ (match_dup 2)))]
+ "TARGET_32BIT"
+ "@
+ adcs%?\\t%0, %0, %2
+ adcs%?\\t%0, %1, %2"
+ [(set_attr "type" "alus_sreg")
+ (set_attr "arch" "t2,*")
+ (set_attr "length" "2,4")]
+)
+
+(define_expand "addsi3_cin_vout_imm"
+ [(parallel
+ [(set (match_dup 3)
+ (compare:CC_V
+ (plus:DI
+ (plus:DI (match_dup 4)
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+ (match_dup 2))
+ (sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+ (match_dup 2)))))
+ (set (match_operand:SI 0 "s_register_operand")
+ (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+ (match_operand 2 "arm_adcimm_operand")))])]
+ "TARGET_32BIT"
+ {
+ operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+ rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+ operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+ operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+ }
+)
+
+(define_insn "*addsi3_cin_vout_imm_insn"
+ [(set (reg:CC_V CC_REGNUM)
+ (compare:CC_V
+ (plus:DI
+ (plus:DI
+ (match_operand:DI 3 "arm_carry_operation" "")
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
+ (match_operand 2 "arm_adcimm_operand" "I,K"))
+ (sign_extend:DI
+ (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+ (match_dup 1))
+ (match_dup 2)))))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (plus:SI (plus:SI (match_dup 4) (match_dup 1))
+ (match_dup 2)))]
+ "TARGET_32BIT"
+ "@
+ adcs%?\\t%0, %1, %2
+ sbcs%?\\t%0, %1, #%B2"
+ [(set_attr "type" "alus_imm")]
+)
+
+(define_expand "addsi3_cin_vout_0"
+ [(parallel
+ [(set (match_dup 2)
+ (compare:CC_V
+ (plus:DI (match_dup 3)
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+ (sign_extend:DI (plus:SI (match_dup 4) (match_dup 1)))))
+ (set (match_operand:SI 0 "s_register_operand")
+ (plus:SI (match_dup 4) (match_dup 1)))])]
+ "TARGET_32BIT"
+ {
+ operands[2] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+ rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+ operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+ operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+ }
+)
+
+(define_insn "*addsi3_cin_vout_0_insn"
+ [(set (reg:CC_V CC_REGNUM)
+ (compare:CC_V
+ (plus:DI
+ (match_operand:DI 2 "arm_carry_operation" "")
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
+ (sign_extend:DI (plus:SI
+ (match_operand:SI 3 "arm_carry_operation" "")
+ (match_dup 1)))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 3) (match_dup 1)))]
+ "TARGET_32BIT"
+ "adcs%?\\t%0, %1, #0"
+ [(set_attr "type" "alus_imm")]
+)
+
(define_expand "uaddvsi4"
[(match_operand:SI 0 "s_register_operand")
(match_operand:SI 1 "s_register_operand")
@@ -770,22 +925,6 @@
]
)
-(define_insn "adddi3_compareV"
- [(set (reg:CC_V CC_REGNUM)
- (ne:CC_V
- (plus:TI
- (sign_extend:TI (match_operand:DI 1 "s_register_operand" "r"))
- (sign_extend:TI (match_operand:DI 2 "s_register_operand" "r")))
- (sign_extend:TI (plus:DI (match_dup 1) (match_dup 2)))))
- (set (match_operand:DI 0 "s_register_operand" "=&r")
- (plus:DI (match_dup 1) (match_dup 2)))]
- "TARGET_32BIT"
- "adds\\t%Q0, %Q1, %Q2;adcs\\t%R0, %R1, %R2"
- [(set_attr "conds" "set")
- (set_attr "length" "8")
- (set_attr "type" "multiple")]
-)
-
(define_insn "addsi3_compareV_reg"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V