This is one more case where we can use the "splat the sign bit" idiom
to do a bit better than with a zicond sequence.
For example, using zicond for (c < 0 ? a + 7 : a) we get:
> srli a5,a0,63
> li a4,7
> czero.eqz a5,a4,a5
> add a0,a5,a1
After this patch we get:
> srai a0,a0,63
> srli a0,a0,61
> add a0,a0,a1
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_expand_conditional_move):
Synthesize the 0 or 2^n-1 avoiding zicond.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/nozicond-4.c: New test.
---
gcc/config/riscv/riscv.cc | 33 +++++++++++++++++++++
gcc/testsuite/gcc.target/riscv/nozicond-4.c | 14 +++++++++
2 files changed, 47 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/riscv/nozicond-4.c
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 681b816d248..feb1039a948 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -5818,6 +5818,39 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx
cons, rtx alt)
&& !CONST_INT_P (alt))
return false;
+ /* If one value is zero and the other value is a 2^n-1 constant, it can
be
+ synthesized using the splatted sign bit. But we don't do that in the
+ generic expander, so do it here. */
+ if (CONST_INT_P (alt)
+ && alt == CONST0_RTX (dst_mode)
+ && CONST_INT_P (cons)
+ && pow2p_hwi (INTVAL (cons) + 1))
+ {
+ int size = GET_MODE_BITSIZE (dst_mode).to_constant ();
+ int shift = (size - exact_log2 (INTVAL (cons) + 1));
+ rtx temp = gen_reg_rtx (dst_mode);
+ emit_insn (gen_rtx_SET (temp,
+ gen_rtx_ASHIFTRT (dst_mode, op0,
+ GEN_INT (size - 1))));
+
+ /* We need a bit inversion step to optimize GE. */
+ if (code == GE)
+ emit_insn (gen_rtx_SET (temp, gen_rtx_NOT (dst_mode, temp)));
+
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_LSHIFTRT (dst_mode, temp,
+ GEN_INT (shift))));
+
+ return true;
+ }
+
+ /* For the inverted condition let it fail and try again. */
+ if (CONST_INT_P (cons)
+ && cons == CONST0_RTX (dst_mode)
+ && CONST_INT_P (alt)
+ && pow2p_hwi (INTVAL (alt) + 1))
+ return false;
+
/* If we need more special cases, add them here. */
}
diff --git a/gcc/testsuite/gcc.target/riscv/nozicond-4.c
b/gcc/testsuite/gcc.target/riscv/nozicond-4.c
new file mode 100644
index 00000000000..5e68d68151e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/nozicond-4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-additional-options "-march=rv64gc_zicond -mabi=lp64d -mbranch-cost=4"
} */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+long foo(long c, long a)
+{
+ return c < 0 ? a + 7 : a;
+}
+
+/* { dg-final { scan-assembler-times {srai\t} 1 } } */
+/* { dg-final { scan-assembler-times {srli\t} 1 } } */
+/* { dg-final { scan-assembler-times {add\t} 1 } } */
+/* { dg-final { scan-assembler-not {czero} } } */
+
--
2.53.0