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

Reply via email to