|| arm_borrow_operation (y, DImode)))
return CC_Bmode;
- if (GET_MODE (x) == DImode || GET_MODE (y) == DImode)
- {
- switch (op)
- {
- case EQ:
- case NE:
- /* A DImode comparison against zero can be implemented by
- or'ing the two halves together. We can also handle
- immediates where one word of that value is zero by
- subtracting the non-zero word from the corresponding word
- in the other register and then ORRing it with the other
- word. */
- if (CONST_INT_P (y)
- && ((UINTVAL (y) & 0xffffffff) == 0
- || (UINTVAL (y) >> 32) == 0))
- return CC_Zmode;
-
- /* We can do an equality test in three Thumb instructions. */
- if (!TARGET_32BIT)
- return CC_Zmode;
-
- /* FALLTHROUGH */
-
- case LTU:
- case LEU:
- case GTU:
- case GEU:
- /* DImode unsigned comparisons can be implemented by cmp +
- cmpeq without a scratch register. Not worth doing in
- Thumb-2. */
- if (TARGET_32BIT)
- return CC_CZmode;
-
- /* FALLTHROUGH */
-
- case LT:
- case LE:
- case GT:
- case GE:
- /* DImode signed and unsigned comparisons can be implemented
- by cmp + sbcs with a scratch register, but that does not
- set the Z flag - we must reverse GT/LE/GTU/LEU. */
- gcc_assert (op != EQ && op != NE);
- return CC_NCVmode;
-
- default:
- gcc_unreachable ();
- }
- }
-
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
return GET_MODE (x);
}
default:
- break;
- }
-
- /* We might have X as a constant, Y as a register because of the predicates
- used for cmpdi. If so, force X to a register here. */
- if (!REG_P (x))
- x = force_reg (DImode, x);
-
- mode = SELECT_CC_MODE (code, x, y);
- cc_reg = gen_rtx_REG (mode, CC_REGNUM);
-
- if (mode != CC_CZmode)
- {
- rtx clobber, set;
-
- /* To compare two non-zero values for equality, XOR them and
- then compare against zero. Not used for ARM mode; there
- CC_CZmode is cheaper. */
- if (mode == CC_Zmode)
- {
- mode = CC_NOOVmode;
- PUT_MODE (cc_reg, mode);
- if (y != const0_rtx)
- {
- gcc_assert (CONST_INT_P (y));
- rtx xlo, xhi, ylo, yhi;
- arm_decompose_di_binop (x, y, &xlo, &xhi, &ylo, &yhi);
- if (!scratch)
- scratch = gen_reg_rtx (SImode);
- if (ylo == const0_rtx)
- {
- yhi = gen_int_mode (-INTVAL (yhi), SImode);
- if (!arm_add_operand (yhi, SImode))
- yhi = force_reg (SImode, yhi);
- emit_insn (gen_addsi3 (scratch, xhi, yhi));
- y = xlo;
- }
- else
- {
- gcc_assert (yhi == const0_rtx);
- ylo = gen_int_mode (-INTVAL (ylo), SImode);
- if (!arm_add_operand (ylo, SImode))
- ylo = force_reg (SImode, ylo);
- emit_insn (gen_addsi3 (scratch, xlo, ylo));
- y = xhi;
- }
- x = gen_rtx_IOR (SImode, scratch, y);
- y = const0_rtx;
- }
- else
- x = gen_rtx_IOR (SImode, gen_lowpart (SImode, x),
- gen_highpart (SImode, x));
- }
- else if (!cmpdi_operand (y, mode))
- y = force_reg (DImode, y);
-
- /* A scratch register is required. */
- if (reload_completed)
- gcc_assert (scratch != NULL && GET_MODE (scratch) == SImode);
- else
- scratch = gen_rtx_SCRATCH (SImode);
-
- clobber = gen_rtx_CLOBBER (VOIDmode, scratch);
- set = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y));
- emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
- }
- else
- {
- if (!cmpdi_operand (y, mode))
- y = force_reg (DImode, y);
-
- emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
+ gcc_unreachable ();
}
-
- return cc_reg;
}
/* X and Y are two things to compare using CODE. Emit the compare insn and
default: return ARM_NV;
}
- case E_CC_CZmode:
- switch (comp_code)
- {
- case NE: return ARM_NE;
- case EQ: return ARM_EQ;
- case GEU: return ARM_CS;
- case GTU: return ARM_HI;
- case LEU: return ARM_LS;
- case LTU: return ARM_CC;
- default: return ARM_NV;
- }
-
- case E_CC_NCVmode:
- switch (comp_code)
- {
- case GE: return ARM_GE;
- case LT: return ARM_LT;
- case GEU: return ARM_CS;
- case LTU: return ARM_CC;
- default: return ARM_NV;
- }
-
case E_CC_NVmode:
switch (comp_code)
{
(set_attr "predicable" "yes")]
)
-;; DImode comparisons. The generic code generates branches that
-;; if-conversion cannot reduce to a conditional compare, so we do
-;; that directly.
-
-(define_insn "*arm_cmpdi_insn"
- [(set (reg:CC_NCV CC_REGNUM)
- (compare:CC_NCV (match_operand:DI 0 "s_register_operand" "r")
- (match_operand:DI 1 "arm_di_operand" "rDi")))
- (clobber (match_scratch:SI 2 "=r"))]
- "TARGET_32BIT"
- "cmp\\t%Q0, %Q1\;sbcs\\t%2, %R0, %R1"
- [(set_attr "conds" "set")
- (set_attr "length" "8")
- (set_attr "type" "multiple")]
-)
-
-(define_insn_and_split "*arm_cmpdi_unsigned"
- [(set (reg:CC_CZ CC_REGNUM)
- (compare:CC_CZ (match_operand:DI 0 "s_register_operand" "l,r,r,r")
- (match_operand:DI 1 "arm_di_operand" "Py,r,Di,rDi")))]
-
- "TARGET_32BIT"
- "#" ; "cmp\\t%R0, %R1\;it eq\;cmpeq\\t%Q0, %Q1"
- "&& reload_completed"
- [(set (reg:CC CC_REGNUM)
- (compare:CC (match_dup 2) (match_dup 3)))
- (cond_exec (eq:SI (reg:CC CC_REGNUM) (const_int 0))
- (set (reg:CC CC_REGNUM)
- (compare:CC (match_dup 0) (match_dup 1))))]
- {
- operands[2] = gen_highpart (SImode, operands[0]);
- operands[0] = gen_lowpart (SImode, operands[0]);
- if (CONST_INT_P (operands[1]))
- operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
- else
- operands[3] = gen_highpart (SImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- }
- [(set_attr "conds" "set")
- (set_attr "enabled_for_short_it" "yes,yes,no,*")
- (set_attr "arch" "t2,t2,t2,a")
- (set_attr "length" "6,6,10,8")
- (set_attr "type" "multiple")]
-)
-
; This insn allows redundant compares to be removed by cse, nothing should
; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
; is deleted later on. The match_dup will match the mode here, so that