@@ -9601,6 +9601,137 @@ aarch64_uimm5 (HOST_WIDE_INT val)
return (val & (HOST_WIDE_INT) 0x1f) == val;
}
+static enum machine_mode
+aarch64_code_to_ccmode (enum rtx_code code)
+{
+ switch (code)
+ {
+ case NE:
+ return CC_DNEmode;
+ case EQ:
+ return CC_DEQmode;
+ case LE:
+ return CC_DLEmode;
+ case LT:
+ return CC_DLTmode;
+ case GE:
+ return CC_DGEmode;
+ case GT:
+ return CC_DGTmode;
+ case LEU:
+ return CC_DLEUmode;
+ case LTU:
+ return CC_DLTUmode;
+ case GEU:
+ return CC_DGEUmode;
+ case GTU:
+ return CC_DGTUmode;
+ default:
+ return CCmode;
+ }
+}
+
+static bool
+aarch64_convert_mode (rtx* op0, rtx* op1, int unsignedp)
+{
+ enum machine_mode mode;
+
+ mode = GET_MODE (*op0);
+ if (mode == VOIDmode)
+ mode = GET_MODE (*op1);
+
+ if (mode == QImode || mode == HImode)
+ {
+ *op0 = convert_modes (SImode, mode, *op0, unsignedp);
+ *op1 = convert_modes (SImode, mode, *op1, unsignedp);
+ }
+ else if (mode != SImode && mode != DImode)
+ return false;
+
+ return true;
+}
+
+static rtx
+aarch64_gen_ccmp_first (int code, rtx op0, rtx op1)
+{
+ enum machine_mode mode;
+ rtx cmp, target;
+ int unsignedp = code == LTU || code == LEU || code == GTU || code == GEU;
+
+ mode = GET_MODE (op0);
+ if (mode == VOIDmode)
+ mode = GET_MODE (op1);
+
+ if (mode == VOIDmode)
+ return NULL_RTX;
+
+ /* Make op0 and op1 are legal operands for cmp. */
+ if (!register_operand (op0, GET_MODE (op0)))
+ op0 = force_reg (mode, op0);
+ if (!aarch64_plus_operand (op1, GET_MODE (op1)))
+ op1 = force_reg (mode, op1);
+
+ if (!aarch64_convert_mode (&op0, &op1, unsignedp))
+ return NULL_RTX;
+
+ mode = aarch64_code_to_ccmode ((enum rtx_code) code);
+ if (mode == CCmode)
+ return NULL_RTX;
+
+ cmp = gen_rtx_fmt_ee (COMPARE, CCmode, op0, op1);
+ target = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM), cmp));
+ return target;
+}
+
+static rtx
+aarch64_gen_ccmp_next (rtx prev, int cmp_code, rtx op0, rtx op1, int bit_code)
+{
+ rtx cmp0, cmp1, target, bit_op;
+ enum machine_mode mode;
+ int unsignedp = cmp_code == LTU || cmp_code == LEU
+ || cmp_code == GTU || cmp_code == GEU;
+
+ mode = GET_MODE (op0);
+ if (mode == VOIDmode)
+ mode = GET_MODE (op1);
+
+ if (mode == VOIDmode)
+ return NULL_RTX;
+
+ /* Give up if the operand is illegal since force_reg will introduce
+ additional overhead. */
+ if (!register_operand (op0, GET_MODE (op0))
+ || !aarch64_ccmp_operand (op1, GET_MODE (op1)))
+ return NULL_RTX;
+
+ if (!aarch64_convert_mode (&op0, &op1, unsignedp))
+ return NULL_RTX;
+
+ mode = aarch64_code_to_ccmode ((enum rtx_code) cmp_code);
+ if (mode == CCmode)
+ return NULL_RTX;
+
+ cmp1 = gen_rtx_fmt_ee ((enum rtx_code) cmp_code, SImode, op0, op1);
+
+ cmp0 = gen_rtx_fmt_ee (NE, SImode, prev, const0_rtx);
+
+ bit_op = gen_rtx_fmt_ee ((enum rtx_code) bit_code, SImode, cmp0, cmp1);
+
+ /* Generate insn to match ccmp_and/ccmp_ior. */
+ target = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn (gen_rtx_SET (VOIDmode, target,
+ gen_rtx_fmt_ee (COMPARE, VOIDmode,
+ bit_op, const0_rtx)));
+ return target;
+}
+
+#undef TARGET_GEN_CCMP_FIRST
+#define TARGET_GEN_CCMP_FIRST aarch64_gen_ccmp_first
+
+#undef TARGET_GEN_CCMP_NEXT
+#define TARGET_GEN_CCMP_NEXT aarch64_gen_ccmp_next
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST aarch64_address_cost