diff mbox

[9/10] aarch64: generate conditional compare instructions

Message ID CACgzC7C6uKV=AQ-81oivAjy+67nMK1zWHRc5jDq51Mwny4LXxA@mail.gmail.com
State New
Headers show

Commit Message

Zhenqiang Chen June 23, 2014, 7:01 a.m. UTC
Hi,

The patches implements the two hooks for AARCH64 to generate ccmp instructions.

Bootstrap and no make check regression on qemu.

OK for trunk?

Thanks!
-Zhenqiang

ChangeLog:
2014-06-23  Zhenqiang Chen  <zhenqiang.chen@linaro.org>

        * config/aarch64/aarch64.c (aarch64_code_to_ccmode): New function.
        (aarch64_convert_mode, aarch64_convert_mode): New functions.
        (aarch64_gen_ccmp_first, aarch64_gen_ccmp_next): New functions.
        (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): Define the two hooks.
diff mbox

Patch

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 4e8d55b..6f08e38 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -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