This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, 5/n] Handle CCMP in ifcvt to make it work with cmov
- From: Zhenqiang Chen <zhenqiang dot chen at linaro dot org>
- To: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Earnshaw <rearnsha at arm dot com>
- Date: Mon, 17 Mar 2014 17:46:32 +0800
- Subject: [PATCH, 5/n] Handle CCMP in ifcvt to make it work with cmov
- Authentication-results: sourceware.org; auth=none
Hi,
The patch enhances ifcvt to handle conditional compare instruction
(ccmp) to make it work with cmov. For ccmp, ALLOW_CC_MODE is set to
TRUE when calling canonicalize_condition. And the backend does not
need to generate additional "compare (CC, 0)" for it.
Bootstrap and no check regression on X84-64, ARM Chromebook and qemu-aarch64.
Is it OK for next stage1?
Thanks!
-Zhenqiang
ChangeLog:
2014-03-17 Zhenqiang Chen <zhenqiang.chen@linaro.org>
* ifcvt.c (struct noce_if_info): Add a new field ccmp_p.
(noce_emit_cmove): Allow ccmp condition.
(noce_get_alt_condition): Call canonicalize_condition with ccmp_p.
(noce_get_condition): Set ALLOW_CC_MODE to TRUE for ccmp.
(noce_process_if_block): Set ccmp_p for ccmp.
* recog.h (ccmp_insn_p): New prototype.
* recog.c (ccmp_insn_p): Make it global.
* config/aarch64/aarch64.md (mov<mode>cc): Handle ccmp_cc.
testsuite/ChangeLog:
2014-03-17 Zhenqiang Chen <zhenqiang.chen@linaro.org>
* gcc.target/aarch64/ccmn-csel-1.c: New testcase.
* gcc.target/aarch64/ccmn-csel-2.c: New testcase.
* gcc.target/aarch64/ccmn-csel-3.c: New testcase.
* gcc.target/aarch64/ccmp-csel-1.c: New testcase.
* gcc.target/aarch64/ccmp-csel-2.c: New testcase.
* gcc.target/aarch64/ccmp-csel-3.c: New testcase.
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 79aa2f3..4e18bb2 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -786,6 +786,9 @@ struct noce_if_info
/* Estimated cost of the particular branch instruction. */
int branch_cost;
+
+ /* The COND is a conditional compare. */
+ bool ccmp_p;
};
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -1407,9 +1410,16 @@ noce_emit_cmove (struct noce_if_info *if_info,
rtx x, enum rtx_code code,
end_sequence ();
}
- /* Don't even try if the comparison operands are weird. */
- if (! general_operand (cmp_a, GET_MODE (cmp_a))
- || ! general_operand (cmp_b, GET_MODE (cmp_b)))
+ /* Don't even try if the comparison operands are weird
+ except conditional compare. */
+ if (if_info->ccmp_p)
+ {
+ if (!(GET_MODE_CLASS (GET_MODE (cmp_a)) == MODE_CC
+ || GET_MODE_CLASS (GET_MODE (cmp_b)) == MODE_CC))
+ return NULL_RTX;
+ }
+ else if (! general_operand (cmp_a, GET_MODE (cmp_a))
+ || ! general_operand (cmp_b, GET_MODE (cmp_b)))
return NULL_RTX;
#if HAVE_conditional_move
@@ -1849,7 +1859,7 @@ noce_get_alt_condition (struct noce_if_info
*if_info, rtx target,
}
cond = canonicalize_condition (if_info->jump, cond, reverse,
- earliest, target, false, true);
+ earliest, target, if_info->ccmp_p, true);
if (! cond || ! reg_mentioned_p (target, cond))
return NULL;
@@ -2300,6 +2310,7 @@ noce_get_condition (rtx jump, rtx *earliest,
bool then_else_reversed)
{
rtx cond, set, tmp;
bool reverse;
+ int allow_cc_mode = false;
if (! any_condjump_p (jump))
return NULL_RTX;
@@ -2333,10 +2344,21 @@ noce_get_condition (rtx jump, rtx *earliest,
bool then_else_reversed)
return cond;
}
+ /* For conditional compare, set ALLOW_CC_MODE to TRUE. */
+ if (targetm.gen_ccmp_first)
+ {
+ rtx prev = prev_nonnote_nondebug_insn (jump);
+ if (prev
+ && NONJUMP_INSN_P (prev)
+ && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (jump)
+ && ccmp_insn_p (prev))
+ allow_cc_mode = true;
+ }
+
/* Otherwise, fall back on canonicalize_condition to do the dirty
work of manipulating MODE_CC values and COMPARE rtx codes. */
tmp = canonicalize_condition (jump, cond, reverse, earliest,
- NULL_RTX, false, true);
+ NULL_RTX, allow_cc_mode, true);
/* We don't handle side-effects in the condition, like handling
REG_INC notes and making sure no duplicate conditions are emitted. */
@@ -2577,6 +2599,11 @@ noce_process_if_block (struct noce_if_info *if_info)
if_info->a = a;
if_info->b = b;
+ if (targetm.gen_ccmp_first)
+ if (GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 0))) == MODE_CC
+ || GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 1))) == MODE_CC)
+ if_info->ccmp_p = true;
+
/* Try optimizations in some approximation of a useful order. */
/* ??? Should first look to see if X is live incoming at all. If it
isn't, we don't need anything but an unconditional set. */
diff -aru gcc/gcc/recog.c ccmp-all/gcc/recog.c
--- a/gcc/recog.c 2014-03-13 16:45:00.524945484 +0800
+++ b/gcc/recog.c 2014-03-13 15:30:22.468912473 +0800
@@ -556,7 +556,7 @@
#define CODE_FOR_extzv CODE_FOR_nothing
#endif
-static bool
+bool
ccmp_insn_p (rtx object)
{
rtx x = PATTERN (object);
diff -aru gcc/gcc/recog.h ccmp-all/gcc/recog.h
--- a/gcc/recog.h 2014-03-13 16:44:42.284945350 +0800
+++ b/gcc/recog.h 2014-03-13 15:30:22.348912472 +0800
@@ -360,5 +360,6 @@
extern const struct insn_data_d insn_data[];
extern int peep2_current_count;
+bool ccmp_insn_p (rtx);
#endif /* GCC_RECOG_H */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 99a6ac8..5a965f5 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2313,15 +2359,19 @@
(match_operand:ALLI 3 "register_operand" "")))]
""
{
- rtx ccreg;
enum rtx_code code = GET_CODE (operands[1]);
if (code == UNEQ || code == LTGT)
FAIL;
- ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
- XEXP (operands[1], 1));
- operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+ if (!ccmp_cc_register (XEXP (operands[1], 0),
+ GET_MODE (XEXP (operands[1], 0))))
+ {
+ rtx ccreg;
+ ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
+ XEXP (operands[1], 1));
+ operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+ }
}
)
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
new file mode 100644
index 0000000..330e58d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > -5 ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
new file mode 100644
index 0000000..c73d329
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > -9 ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
new file mode 100644
index 0000000..64d6b0b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a > b && c <= -2 ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
new file mode 100644
index 0000000..ced87b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c <= d ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
new file mode 100644
index 0000000..8a4de3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > d ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
new file mode 100644
index 0000000..60b6438
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a > b && c <= d ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 79aa2f3..4e18bb2 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -786,6 +786,9 @@ struct noce_if_info
/* Estimated cost of the particular branch instruction. */
int branch_cost;
+
+ /* The COND is a conditional compare. */
+ bool ccmp_p;
};
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -1407,9 +1410,16 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
end_sequence ();
}
- /* Don't even try if the comparison operands are weird. */
- if (! general_operand (cmp_a, GET_MODE (cmp_a))
- || ! general_operand (cmp_b, GET_MODE (cmp_b)))
+ /* Don't even try if the comparison operands are weird
+ except conditional compare. */
+ if (if_info->ccmp_p)
+ {
+ if (!(GET_MODE_CLASS (GET_MODE (cmp_a)) == MODE_CC
+ || GET_MODE_CLASS (GET_MODE (cmp_b)) == MODE_CC))
+ return NULL_RTX;
+ }
+ else if (! general_operand (cmp_a, GET_MODE (cmp_a))
+ || ! general_operand (cmp_b, GET_MODE (cmp_b)))
return NULL_RTX;
#if HAVE_conditional_move
@@ -1849,7 +1859,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
}
cond = canonicalize_condition (if_info->jump, cond, reverse,
- earliest, target, false, true);
+ earliest, target, if_info->ccmp_p, true);
if (! cond || ! reg_mentioned_p (target, cond))
return NULL;
@@ -2300,6 +2310,7 @@ noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed)
{
rtx cond, set, tmp;
bool reverse;
+ int allow_cc_mode = false;
if (! any_condjump_p (jump))
return NULL_RTX;
@@ -2333,10 +2344,21 @@ noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed)
return cond;
}
+ /* For conditional compare, set ALLOW_CC_MODE to TRUE. */
+ if (targetm.gen_ccmp_first)
+ {
+ rtx prev = prev_nonnote_nondebug_insn (jump);
+ if (prev
+ && NONJUMP_INSN_P (prev)
+ && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (jump)
+ && ccmp_insn_p (prev))
+ allow_cc_mode = true;
+ }
+
/* Otherwise, fall back on canonicalize_condition to do the dirty
work of manipulating MODE_CC values and COMPARE rtx codes. */
tmp = canonicalize_condition (jump, cond, reverse, earliest,
- NULL_RTX, false, true);
+ NULL_RTX, allow_cc_mode, true);
/* We don't handle side-effects in the condition, like handling
REG_INC notes and making sure no duplicate conditions are emitted. */
@@ -2577,6 +2599,11 @@ noce_process_if_block (struct noce_if_info *if_info)
if_info->a = a;
if_info->b = b;
+ if (targetm.gen_ccmp_first)
+ if (GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 0))) == MODE_CC
+ || GET_MODE_CLASS (GET_MODE (XEXP (if_info->cond, 1))) == MODE_CC)
+ if_info->ccmp_p = true;
+
/* Try optimizations in some approximation of a useful order. */
/* ??? Should first look to see if X is live incoming at all. If it
isn't, we don't need anything but an unconditional set. */
diff -aru gcc/gcc/recog.c ccmp-all/gcc/recog.c
--- a/gcc/recog.c 2014-03-13 16:45:00.524945484 +0800
+++ b/gcc/recog.c 2014-03-13 15:30:22.468912473 +0800
@@ -556,7 +556,7 @@
#define CODE_FOR_extzv CODE_FOR_nothing
#endif
-static bool
+bool
ccmp_insn_p (rtx object)
{
rtx x = PATTERN (object);
diff -aru gcc/gcc/recog.h ccmp-all/gcc/recog.h
--- a/gcc/recog.h 2014-03-13 16:44:42.284945350 +0800
+++ b/gcc/recog.h 2014-03-13 15:30:22.348912472 +0800
@@ -360,5 +360,6 @@
extern const struct insn_data_d insn_data[];
extern int peep2_current_count;
+bool ccmp_insn_p (rtx);
#endif /* GCC_RECOG_H */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 99a6ac8..5a965f5 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2313,15 +2359,19 @@
(match_operand:ALLI 3 "register_operand" "")))]
""
{
- rtx ccreg;
enum rtx_code code = GET_CODE (operands[1]);
if (code == UNEQ || code == LTGT)
FAIL;
- ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
- XEXP (operands[1], 1));
- operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+ if (!ccmp_cc_register (XEXP (operands[1], 0),
+ GET_MODE (XEXP (operands[1], 0))))
+ {
+ rtx ccreg;
+ ccreg = aarch64_gen_compare_reg (code, XEXP (operands[1], 0),
+ XEXP (operands[1], 1));
+ operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
+ }
}
)
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
new file mode 100644
index 0000000..330e58d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > -5 ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
new file mode 100644
index 0000000..c73d329
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > -9 ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
new file mode 100644
index 0000000..64d6b0b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmn-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a > b && c <= -2 ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmn" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
new file mode 100644
index 0000000..ced87b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c <= d ? d : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
new file mode 100644
index 0000000..8a4de3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a < b && c > d ? d : c;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
new file mode 100644
index 0000000..60b6438
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ccmp-csel-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options " -O2 " } */
+
+int foo (int a, int b, int c, int d)
+{
+ return a > b && c <= d ? 9 : 7;
+}
+
+/* { dg-final { scan-assembler "ccmp" } } */
+/* { dg-final { scan-assembler "csel" } } */