aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorZhenqiang Chen <zhenqiang.chen@linaro.org>2014-11-17 06:24:36 +0000
committerZhenqiang Chen <zqchen@gcc.gnu.org>2014-11-17 06:24:36 +0000
commit7dd236702d11b60084560f56b0c3ffdd197c885a (patch)
tree5679e70771214678ce82802aa8d5770aac9cfc58 /gcc
parentcf67050334d42b14a7eecf2d503a96c1d284fbfd (diff)
downloadgcc-7dd236702d11b60084560f56b0c3ffdd197c885a.zip
gcc-7dd236702d11b60084560f56b0c3ffdd197c885a.tar.gz
gcc-7dd236702d11b60084560f56b0c3ffdd197c885a.tar.bz2
aarch64.c (aarch64_code_to_ccmode, [...]): New functions.
2014-11-17 Zhenqiang Chen <zhenqiang.chen@linaro.org> * config/aarch64/aarch64.c (aarch64_code_to_ccmode, aarch64_convert_mode, aarch64_gen_ccmp_first, aarch64_gen_ccmp_next): New functions. (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): Define. From-SVN: r217645
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/aarch64/aarch64.c138
2 files changed, 145 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6af355b..540784d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
2014-11-17 Zhenqiang Chen <zhenqiang.chen@linaro.org>
+ * config/aarch64/aarch64.c (aarch64_code_to_ccmode,
+ aarch64_convert_mode, aarch64_gen_ccmp_first,
+ aarch64_gen_ccmp_next): New functions.
+ (TARGET_GEN_CCMP_FIRST, TARGET_GEN_CCMP_NEXT): Define.
+
+2014-11-17 Zhenqiang Chen <zhenqiang.chen@linaro.org>
+
* config/aarch64/aarch64-protos.h (aarch64_ccmp_mode_to_code): New.
* aarch64.c (aarch64_nzcv_codes): New data.
(aarch64_ccmp_mode_to_code): New.
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b9383a4..3548335 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -10211,6 +10211,144 @@ aarch64_use_by_pieces_infrastructure_p (unsigned int size,
return default_use_by_pieces_infrastructure_p (size, align, op, speed_p);
}
+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;
+
+ 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, mode,
+ 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