@@ -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,
bool high);
extern void arm_emit_speculation_barrier_function (void);
+extern void arm_decompose_di_binop (rtx, rtx, rtx *, rtx *, rtx *, rtx *);
#ifdef RTX_CODE
extern void arm_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode,
@@ -14933,6 +14933,21 @@ gen_cpymem_ldrd_strd (rtx *operands)
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
form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms.
COND_OR == DOM_CC_X_AND_Y => (X && Y)
@@ -437,25 +437,53 @@ (define_expand "adddi3"
[(parallel
[(set (match_operand:DI 0 "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))])]
"TARGET_EITHER"
"
- if (TARGET_THUMB1 && !REG_P (operands[2]))
- operands[2] = force_reg (DImode, operands[2]);
- "
-)
+ if (TARGET_THUMB1)
+ {
+ 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"
- [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r")
- (plus:DI (match_operand:DI 1 "s_register_operand" " %0,0,r")
- (match_operand:DI 2 "s_register_operand" " r,0,r")))
- (clobber (reg:CC CC_REGNUM))]
- "TARGET_32BIT"
- "adds\\t%Q0, %Q1, %Q2;adc\\t%R0, %R1, %R2"
- [(set_attr "conds" "clob")
- (set_attr "length" "8")
- (set_attr "type" "multiple")]
+ if (lo_result != lo_dest)
+ emit_move_insn (lo_result, lo_dest);
+ if (hi_result != hi_dest)
+ emit_move_insn (gen_highpart (SImode, operands[0]), hi_dest);
+ DONE;
+ }
+ "
)
(define_expand "addv<mode>4"
@@ -830,7 +858,7 @@ (define_insn "*compare_addsi2_op1"
(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")
(plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%l,r,r")
(match_operand:SI 2 "arm_not_operand" "0,rI,K"))
@@ -848,6 +876,19 @@ (define_insn "*addsi3_carryin_<optab>"
(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>"
[(set (match_operand:SI 0 "s_register_operand" "=l,r,r")
(plus:SI (plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))
@@ -1,6 +1,6 @@
/* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */
-/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p)
{
@@ -1,6 +1,6 @@
/* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */
-/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p)
@@ -1,6 +1,6 @@
/* { dg-options "-O2" } */
/* { dg-require-effective-target arm32 } */
-/* { dg-final { scan-assembler-not "mov" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "mov" } } */
void t0p(long long * p)