Commit 0406dccd by Richard Earnshaw Committed by Richard Earnshaw

[arm] Perform early splitting of adddi3.

This patch causes the expansion of adddi3 to split the operation
immediately for Arm and Thumb-2.  This is desirable as it frees up the
register allocator to pick what ever combination of registers suits
best and reduces the number of auxiliary patterns that we need in the
back-end.  Three of the testcases that we disabled earlier are already
fixed by this patch.  Finally, we add a new pattern to match the
canonicalization of add-with-carry when using an immediate of zero.

gcc:
	* config/arm/arm-protos.h (arm_decompose_di_binop): New prototype.
	* config/arm/arm.c (arm_decompose_di_binop): New function.
	* config/arm/arm.md (adddi3): Also accept any const_int for op2.
	If not generating Thumb-1 code, decompose the operation into 32-bit
	pieces.
	* add0si_carryin_<optab>: New pattern.

testsuite:
	* gcc.target/arm/pr53447-1.c: Remove XFAIL.
	* gcc.target/arm/pr53447-3.c: Remove XFAIL.
	* gcc.target/arm/pr53447-4.c: Remove XFAIL.

From-SVN: r277165
parent 1769e3f3
2019-10-18 Richard Earnshaw <rearnsha@arm.com> 2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* config/arm/arm-protos.h (arm_decompose_di_binop): New prototype.
* config/arm/arm.c (arm_decompose_di_binop): New function.
* config/arm/arm.md (adddi3): Also accept any const_int for op2.
If not generating Thumb-1 code, decompose the operation into 32-bit
pieces.
* add0si_carryin_<optab>: New pattern.
2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* arm.md (adddi3): Only accept register operands. * arm.md (adddi3): Only accept register operands.
(arm_adddi3): Convert to simple insn with no split. Do not accept (arm_adddi3): Convert to simple insn with no split. Do not accept
constants. constants.
......
...@@ -57,6 +57,7 @@ extern rtx arm_simd_vect_par_cnst_half (machine_mode mode, bool high); ...@@ -57,6 +57,7 @@ extern rtx arm_simd_vect_par_cnst_half (machine_mode mode, bool high);
extern bool arm_simd_check_vect_par_cnst_half_p (rtx op, machine_mode mode, extern bool arm_simd_check_vect_par_cnst_half_p (rtx op, machine_mode mode,
bool high); bool high);
extern void arm_emit_speculation_barrier_function (void); extern void arm_emit_speculation_barrier_function (void);
extern void arm_decompose_di_binop (rtx, rtx, rtx *, rtx *, rtx *, rtx *);
#ifdef RTX_CODE #ifdef RTX_CODE
extern void arm_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode, extern void arm_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode,
......
...@@ -14933,6 +14933,21 @@ gen_cpymem_ldrd_strd (rtx *operands) ...@@ -14933,6 +14933,21 @@ gen_cpymem_ldrd_strd (rtx *operands)
return true; return true;
} }
/* Decompose operands for a 64-bit binary operation in OP1 and OP2
into its component 32-bit subregs. OP2 may be an immediate
constant and we want to simplify it in that case. */
void
arm_decompose_di_binop (rtx op1, rtx op2, rtx *lo_op1, rtx *hi_op1,
rtx *lo_op2, rtx *hi_op2)
{
*lo_op1 = gen_lowpart (SImode, op1);
*hi_op1 = gen_highpart (SImode, op1);
*lo_op2 = simplify_gen_subreg (SImode, op2, DImode,
subreg_lowpart_offset (SImode, DImode));
*hi_op2 = simplify_gen_subreg (SImode, op2, DImode,
subreg_highpart_offset (SImode, DImode));
}
/* Select a dominance comparison mode if possible for a test of the general /* Select a dominance comparison mode if possible for a test of the general
form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms. form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms.
COND_OR == DOM_CC_X_AND_Y => (X && Y) COND_OR == DOM_CC_X_AND_Y => (X && Y)
......
...@@ -437,25 +437,53 @@ ...@@ -437,25 +437,53 @@
[(parallel [(parallel
[(set (match_operand:DI 0 "s_register_operand") [(set (match_operand:DI 0 "s_register_operand")
(plus:DI (match_operand:DI 1 "s_register_operand") (plus:DI (match_operand:DI 1 "s_register_operand")
(match_operand:DI 2 "s_register_operand"))) (match_operand:DI 2 "reg_or_int_operand")))
(clobber (reg:CC CC_REGNUM))])] (clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER" "TARGET_EITHER"
" "
if (TARGET_THUMB1 && !REG_P (operands[2])) if (TARGET_THUMB1)
operands[2] = force_reg (DImode, operands[2]); {
" if (!REG_P (operands[2]))
) operands[2] = force_reg (DImode, operands[2]);
}
else
{
rtx lo_result, hi_result, lo_dest, hi_dest;
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 = lo_dest = gen_lowpart (SImode, operands[0]);
hi_result = hi_dest = gen_highpart (SImode, operands[0]);
if (lo_op2 == const0_rtx)
{
lo_dest = lo_op1;
if (!arm_add_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
/* Assume hi_op2 won't also be zero. */
emit_insn (gen_addsi3 (hi_dest, hi_op1, hi_op2));
}
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_compareC (lo_dest, lo_op1, lo_op2));
if (hi_op2 == const0_rtx)
emit_insn (gen_add0si3_carryin_ltu (hi_dest, hi_op1));
else
emit_insn (gen_addsi3_carryin_ltu (hi_dest, hi_op1, hi_op2));
}
(define_insn "*arm_adddi3" if (lo_result != lo_dest)
[(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") emit_move_insn (lo_result, lo_dest);
(plus:DI (match_operand:DI 1 "s_register_operand" " %0,0,r") if (hi_result != hi_dest)
(match_operand:DI 2 "s_register_operand" " r,0,r"))) emit_move_insn (gen_highpart (SImode, operands[0]), hi_dest);
(clobber (reg:CC CC_REGNUM))] DONE;
"TARGET_32BIT" }
"adds\\t%Q0, %Q1, %Q2;adc\\t%R0, %R1, %R2" "
[(set_attr "conds" "clob")
(set_attr "length" "8")
(set_attr "type" "multiple")]
) )
(define_expand "addv<mode>4" (define_expand "addv<mode>4"
...@@ -830,7 +858,7 @@ ...@@ -830,7 +858,7 @@
(set_attr "type" "alus_imm,alus_sreg,alus_imm,alus_imm,alus_sreg")] (set_attr "type" "alus_imm,alus_sreg,alus_imm,alus_imm,alus_sreg")]
) )
(define_insn "*addsi3_carryin_<optab>" (define_insn "addsi3_carryin_<optab>"
[(set (match_operand:SI 0 "s_register_operand" "=l,r,r") [(set (match_operand:SI 0 "s_register_operand" "=l,r,r")
(plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%l,r,r") (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%l,r,r")
(match_operand:SI 2 "arm_not_operand" "0,rI,K")) (match_operand:SI 2 "arm_not_operand" "0,rI,K"))
...@@ -848,6 +876,19 @@ ...@@ -848,6 +876,19 @@
(set_attr "type" "adc_reg,adc_reg,adc_imm")] (set_attr "type" "adc_reg,adc_reg,adc_imm")]
) )
;; Canonicalization of the above when the immediate is zero.
(define_insn "add0si3_carryin_<optab>"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))
(match_operand:SI 1 "arm_not_operand" "r")))]
"TARGET_32BIT"
"adc%?\\t%0, %1, #0"
[(set_attr "conds" "use")
(set_attr "predicable" "yes")
(set_attr "length" "4")
(set_attr "type" "adc_imm")]
)
(define_insn "*addsi3_carryin_alt2_<optab>" (define_insn "*addsi3_carryin_alt2_<optab>"
[(set (match_operand:SI 0 "s_register_operand" "=l,r,r") [(set (match_operand:SI 0 "s_register_operand" "=l,r,r")
(plus:SI (plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0)) (plus:SI (plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))
......
2019-10-18 Richard Earnshaw <rearnsha@arm.com> 2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* gcc.target/arm/pr53447-1.c: Remove XFAIL.
* gcc.target/arm/pr53447-3.c: Remove XFAIL.
* gcc.target/arm/pr53447-4.c: Remove XFAIL.
2019-10-18 Richard Earnshaw <rearnsha@arm.com>
* gcc.target/arm/negdi-3.c: Add XFAILS. * gcc.target/arm/negdi-3.c: Add XFAILS.
* gcc.target/arm/pr3447-1.c: Likewise. * gcc.target/arm/pr3447-1.c: Likewise.
* gcc.target/arm/pr3447-3.c: Likewise. * gcc.target/arm/pr3447-3.c: Likewise.
......
/* { dg-options "-O2" } */ /* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */ /* { dg-require-effective-target arm32 } */
/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */ /* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p) void t0p(long long * p)
{ {
......
/* { dg-options "-O2" } */ /* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */ /* { dg-require-effective-target arm32 } */
/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */ /* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p) void t0p(long long * p)
......
/* { dg-options "-O2" } */ /* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */ /* { dg-require-effective-target arm32 } */
/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */ /* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p) void t0p(long long * p)
......
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