aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorFei Gao <gaofei@eswincomputing.com>2023-12-10 22:21:58 -0700
committerJeff Law <jlaw@ventanamicro.com>2023-12-10 22:23:13 -0700
commitec201e2a6021d144797f5558e4d08a2385de7a63 (patch)
tree73ba5fccfdb635b30adcf0eed4ac201188979f0d /gcc
parent4719b6f5ae4d758f193a17bbd5fb6cbacd702a23 (diff)
downloadgcc-ec201e2a6021d144797f5558e4d08a2385de7a63.zip
gcc-ec201e2a6021d144797f5558e4d08a2385de7a63.tar.gz
gcc-ec201e2a6021d144797f5558e4d08a2385de7a63.tar.bz2
[PATCH 3/5] [ifcvt] optimize x=c ? (y AND z) : y by RISC-V Zicond like insns
Take the following case for example. CFLAGS: -march=rv64gc_zbb_zicond -mabi=lp64d -O2 long test_AND_ceqz (long x, long y, long z, long c) { if (c) x = y & z; else x = y; return x; } Before patch: and a2,a1,a2 czero.eqz a0,a2,a3 czero.nez a3,a1,a3 or a0,a3,a0 ret After patch: and a0,a1,a2 czero.nez a1,a1,a3 or a0,a1,a0 ret Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com> gcc/ChangeLog: * ifcvt.cc (noce_cond_zero_binary_op_supported): Add support for AND. (noce_bbs_ok_for_cond_zero_arith): Likewise. (noce_try_cond_zero_arith): Likewise. gcc/testsuite/ChangeLog: * gcc.target/riscv/zicond_ifcvt_opt.c: Add TCs for AND.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ifcvt.cc69
-rw-r--r--gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c163
2 files changed, 211 insertions, 21 deletions
diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 6ac91b8..9e5e936 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -2922,7 +2922,7 @@ noce_cond_zero_binary_op_supported (rtx op)
if (opcode == PLUS || opcode == MINUS || opcode == IOR || opcode == XOR
|| opcode == ASHIFT || opcode == ASHIFTRT || opcode == LSHIFTRT
- || opcode == ROTATE || opcode == ROTATERT)
+ || opcode == ROTATE || opcode == ROTATERT || opcode == AND)
return true;
return false;
@@ -2952,6 +2952,7 @@ get_base_reg (rtx exp)
static bool
noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
+ rtx *bin_exp_ptr,
enum rtx_code *czero_code_ptr, rtx *a_ptr,
rtx **to_replace)
{
@@ -2996,7 +2997,7 @@ noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
{
common = b;
bin_op1 = XEXP (bin_exp, 1);
- czero_code = reverse
+ czero_code = (reverse ^ (GET_CODE (bin_exp) == AND))
? noce_reversed_cond_code (if_info)
: GET_CODE (cond);
}
@@ -3012,6 +3013,7 @@ noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
return false;
*common_ptr = common;
+ *bin_exp_ptr = bin_exp;
*czero_code_ptr = czero_code;
*a_ptr = a;
@@ -3025,38 +3027,67 @@ noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
static int
noce_try_cond_zero_arith (struct noce_if_info *if_info)
{
- rtx target, a;
+ rtx target, rtmp, a;
rtx_insn *seq;
machine_mode mode = GET_MODE (if_info->x);
rtx common = NULL_RTX;
enum rtx_code czero_code = UNKNOWN;
+ rtx bin_exp = NULL_RTX;
+ enum rtx_code bin_code = UNKNOWN;
rtx non_zero_op = NULL_RTX;
rtx *to_replace = NULL;
- if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
- &to_replace))
+ if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &bin_exp, &czero_code,
+ &a, &to_replace))
return false;
- non_zero_op = *to_replace;
-
start_sequence ();
- /* If x is used in both input and out like x = c ? x + z : x,
- use a new reg to avoid modifying x */
- if (common && rtx_equal_p (common, if_info->x))
- target = gen_reg_rtx (mode);
- else
- target = if_info->x;
+ bin_code = GET_CODE (bin_exp);
- target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
- if (!target || !to_replace)
+ if (bin_code == AND)
{
- end_sequence ();
- return false;
+ rtmp = gen_reg_rtx (mode);
+ noce_emit_move_insn (rtmp, a);
+
+ target = noce_emit_czero (if_info, czero_code, common, if_info->x);
+ if (!target)
+ {
+ end_sequence ();
+ return false;
+ }
+
+ target = expand_simple_binop (mode, IOR, rtmp, target, if_info->x, 0,
+ OPTAB_WIDEN);
+ if (!target)
+ {
+ end_sequence ();
+ return false;
+ }
+
+ if (target != if_info->x)
+ noce_emit_move_insn (if_info->x, target);
}
+ else
+ {
+ non_zero_op = *to_replace;
+ /* If x is used in both input and out like x = c ? x + z : x,
+ use a new reg to avoid modifying x */
+ if (common && rtx_equal_p (common, if_info->x))
+ target = gen_reg_rtx (mode);
+ else
+ target = if_info->x;
- *to_replace = target;
- noce_emit_move_insn (if_info->x, a);
+ target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
+ if (!target || !to_replace)
+ {
+ end_sequence ();
+ return false;
+ }
+
+ *to_replace = target;
+ noce_emit_move_insn (if_info->x, a);
+ }
seq = end_ifcvt_sequence (if_info);
if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
diff --git a/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
index efed199..a02a2757 100644
--- a/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
+++ b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
@@ -615,5 +615,164 @@ test_RotateR_eqz (unsigned long x, unsigned long y, unsigned long z,
return x;
}
-/* { dg-final { scan-assembler-times {czero\.eqz} 28 } } */
-/* { dg-final { scan-assembler-times {czero\.nez} 28 } } */
+long
+test_AND_ceqz (long x, long y, long z, long c)
+{
+ if (c)
+ x = y & z;
+ else
+ x = y;
+ return x;
+}
+
+long
+test_AND_ceqz_x (long x, long z, long c)
+{
+ if (c)
+ x = x & z;
+
+ return x;
+}
+
+long
+test_AND_nez (long x, long y, long z, long c)
+{
+ if (c)
+ x = y;
+ else
+ x = y & z;
+ return x;
+}
+
+long
+test_AND_nez_x (long x, long z, long c)
+{
+ if (c)
+ {
+ }
+ else
+ x = x & z;
+ return x;
+}
+
+long
+test_AND_nez_2 (long x, long y, long z, long c)
+{
+ if (!c)
+ x = y & z;
+ else
+ x = y;
+ return x;
+}
+
+long
+test_AND_nez_x_2 (long x, long z, long c)
+{
+ if (!c)
+ x = x & z;
+
+ return x;
+}
+
+long
+test_AND_eqz_2 (long x, long y, long z, long c)
+{
+ if (!c)
+ x = y;
+ else
+ x = y & z;
+ return x;
+}
+
+long
+test_AND_eqz_x_2 (long x, long z, long c)
+{
+ if (!c)
+ {
+ }
+ else
+ x = x & z;
+ return x;
+}
+
+long
+test_AND_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+ if (c)
+ x = z & y;
+ else
+ x = y;
+ return x;
+}
+
+long
+test_AND_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+ if (c)
+ x = z & x;
+
+ return x;
+}
+
+long
+test_AND_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+ if (c)
+ x = y;
+ else
+ x = z & y;
+ return x;
+}
+
+long
+test_AND_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+ if (c)
+ {
+ }
+ else
+ x = z & x;
+ return x;
+}
+
+long
+test_AND_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+ if (!c)
+ x = z & y;
+ else
+ x = y;
+ return x;
+}
+
+long
+test_AND_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+ if (!c)
+ x = z & x;
+
+ return x;
+}
+
+long
+test_AND_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+ if (!c)
+ x = y;
+ else
+ x = z & y;
+ return x;
+}
+
+long
+test_AND_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+ if (!c)
+ {
+ }
+ else
+ x = z & x;
+ return x;
+}
+/* { dg-final { scan-assembler-times {czero\.eqz} 36 } } */
+/* { dg-final { scan-assembler-times {czero\.nez} 36 } } */