@@ -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 */
@@ -15387,6 +15387,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
&& (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), 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
@@ -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 "uaddvsi4"
(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 @@ (define_insn "addsi3_compareV"
(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 @@ (define_special_predicate "arm_carry_operation"
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;