Commit deb254e0 by Richard Earnshaw Committed by Richard Earnshaw

[arm] Early expansion of uaddvdi4.

This code borrows strongly on the uaddvti4 expansion for aarch64 since
the principles are similar.  Firstly, if the one of the low words of
the expansion is 0, we can simply copy the other low word to the
destination and use uaddvsi4 for the upper word.  If that doesn't work
we have to handle three possible cases for the upper work (the lower
word is simply an add-with-carry operation as for adddi3): zero in the
upper word, some other constant and a register (each has a different
canonicalization).  We use CC_ADCmode (a new CC mode variant) to
describe the cases as the introduction of the carry means we can
no-longer use the normal overflow trick of comparing the sum against
one of the operands.

	* config/arm/arm-modes.def (CC_ADC): New CC mode.
	* config/arm/arm.c (arm_select_cc_mode): Detect selection of
	CC_ADCmode.
	(maybe_get_arm_condition_code): Handle CC_ADCmode.
	* config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition
	with overflow.
	(addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New
	expand patterns.
	(addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns
	(addsi3_cin_cout_imm_insn): Likewise.
	(adddi3_compareC): Delete insn.
	* config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode.

From-SVN: r277183
parent ed6588f2
2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* config/arm/arm-modes.def (CC_ADC): New CC mode.
* config/arm/arm.c (arm_select_cc_mode): Detect selection of
CC_ADCmode.
(maybe_get_arm_condition_code): Handle CC_ADCmode.
* config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition
with overflow.
(addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New
expand patterns.
(addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns
(addsi3_cin_cout_imm_insn): Likewise.
(adddi3_compareC): Delete insn.
* config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode.
2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* config/arm/arm.md (adddi3): Call gen_addsi3_compare_op1.
* (uaddv<mode>4): Delete expansion pattern.
(uaddvsi4): New pattern.
......
......@@ -42,6 +42,9 @@ ADJUST_FLOAT_FORMAT (HF, ((arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE)
CC_Bmode should be used if only the C flag is correct after a subtract
(eg after an unsigned borrow with carry-in propagation).
(used for DImode signed comparisons).
CC_ADCmode is used when the carry is formed from the output of ADC for an
addtion. In this case we cannot use the trick of comparing the sum
against one of the other operands.
CCmode should be used otherwise. */
CC_MODE (CC_NOOV);
......@@ -65,6 +68,7 @@ CC_MODE (CC_C);
CC_MODE (CC_B);
CC_MODE (CC_N);
CC_MODE (CC_V);
CC_MODE (CC_ADC);
/* Vector modes. */
VECTOR_MODES (INT, 4); /* V4QI V2HI */
......
......@@ -15388,6 +15388,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
return CC_Cmode;
if (GET_MODE (x) == DImode
&& GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == ZERO_EXTEND
&& CONST_INT_P (y)
&& UINTVAL (y) == 0x800000000
&& (op == GEU || op == LTU))
return CC_ADCmode;
if (GET_MODE (x) == DImode
&& (op == GE || op == LT)
&& GET_CODE (x) == SIGN_EXTEND
&& ((GET_CODE (y) == PLUS
......@@ -23952,6 +23960,14 @@ maybe_get_arm_condition_code (rtx comparison)
default: return ARM_NV;
}
case E_CC_ADCmode:
switch (comp_code)
{
case GEU: return ARM_CS;
case LTU: return ARM_CC;
default: return ARM_NV;
}
case E_CCmode:
case E_CC_RSBmode:
switch (comp_code)
......
......@@ -517,16 +517,165 @@
(define_expand "uaddvdi4"
[(match_operand:DI 0 "s_register_operand")
(match_operand:DI 1 "s_register_operand")
(match_operand:DI 2 "s_register_operand")
(match_operand:DI 2 "reg_or_int_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
emit_insn (gen_adddi3_compareC (operands[0], operands[1], operands[2]));
arm_gen_unlikely_cbranch (LTU, CC_Cmode, 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);
gen_uaddvsi4 (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_cout_0 (hi_result, hi_op1));
else if (CONST_INT_P (hi_op2))
emit_insn (gen_addsi3_cin_cout_imm (hi_result, hi_op1, hi_op2));
else
emit_insn (gen_addsi3_cin_cout_reg (hi_result, hi_op1, hi_op2));
arm_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]);
}
DONE;
})
(define_expand "addsi3_cin_cout_reg"
[(parallel
[(set (match_dup 3)
(compare:CC_ADC
(plus:DI
(plus:DI (match_dup 4)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(zero_extend:DI (match_operand:SI 2 "s_register_operand")))
(const_int 4294967296)))
(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_ADCmode, 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_cout_reg_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
(zero_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=l,r")
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(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_cout_imm"
[(parallel
[(set (match_dup 3)
(compare:CC_ADC
(plus:DI
(plus:DI (match_dup 4)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(match_dup 6))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_operand:SI 2 "arm_adcimm_operand")))])]
"TARGET_32BIT"
{
operands[3] = gen_rtx_REG (CC_ADCmode, 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);
operands[6] = GEN_INT (UINTVAL (operands[2]) & 0xffffffff);
}
)
(define_insn "*addsi3_cin_cout_imm_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
(match_operand:DI 5 "const_int_operand" "n,n"))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=r,r")
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(match_dup 1))
(match_operand:SI 2 "arm_adcimm_operand" "I,K")))]
"TARGET_32BIT
&& (UINTVAL (operands[2]) & 0xffffffff) == UINTVAL (operands[5])"
"@
adcs%?\\t%0, %1, %2
sbcs%?\\t%0, %1, #%B2"
[(set_attr "type" "alus_imm")]
)
(define_expand "addsi3_cin_cout_0"
[(parallel
[(set (match_dup 2)
(compare:CC_ADC
(plus:DI (match_dup 3)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (match_dup 4) (match_dup 1)))])]
"TARGET_32BIT"
{
operands[2] = gen_rtx_REG (CC_ADCmode, 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_cout_0_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(match_operand:DI 2 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=r")
(plus:SI (match_operand:SI 3 "arm_carry_operation" "") (match_dup 1)))]
"TARGET_32BIT"
"adcs%?\\t%0, %1, #0"
[(set_attr "type" "alus_imm")]
)
(define_expand "addsi3"
[(set (match_operand:SI 0 "s_register_operand")
(plus:SI (match_operand:SI 1 "s_register_operand")
......@@ -636,22 +785,6 @@
(set_attr "type" "alus_sreg")]
)
(define_insn "adddi3_compareC"
[(set (reg:CC_C CC_REGNUM)
(compare:CC_C
(plus:DI
(match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "register_operand" "r"))
(match_dup 1)))
(set (match_operand:DI 0 "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_compare0"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV
......
......@@ -376,7 +376,7 @@
machine_mode ccmode = GET_MODE (op0);
if (ccmode == CC_Cmode)
return GET_CODE (op) == LTU;
else if (ccmode == CCmode || ccmode == CC_RSBmode)
else if (ccmode == CCmode || ccmode == CC_RSBmode || ccmode == CC_ADCmode)
return GET_CODE (op) == GEU;
return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment