https://gcc.gnu.org/g:1d90f8c7933eb225e26b7598960bc220a582c452

commit r16-1181-g1d90f8c7933eb225e26b7598960bc220a582c452
Author: Jeff Law <j...@ventanamicro.com>
Date:   Thu Jun 5 06:17:25 2025 -0600

    [RISC-V] Improve sequences to generate -1, 1 in some cases.
    
    This patch has a minor improvement to if-converted sequences based on
    observations I found while evaluating another patch from Shreya to handle 
more
    cases with zicond insns.
    
    Specifically there is a smaller/faster way than zicond to generate a -1,1
    result when the condition is testing the sign bit.
    
    So let's consider these two tests (rv64):
    
    long foo1 (long c, long a) { return c >= 0 ? 1 : -1; }
    long foo2 (long c, long a) { return c < 0 ? -1 : 1; }
    
    So if we right arithmetic shift c by 63 bits, that splats the sign bit 
across a
    register giving us 0, -1 for the first test and -1, 0 for the second test.  
We
    then unconditionally turn on the LSB resulting in 1, -1 for the first case 
and
    -1, 1 for the second.
    
    This is implemented as a 4->2 splitter.  There's another pair of cases we 
don't
    handle because we don't have 4->3 splitters.  Specifically if the true/false
    values are reversed in the above examples without reversing the condition.
    
    Raphael is playing a bit in the gimple space to see what opportunities might
    exist to recognize more idioms in phiopt and generate better code earlier.  
No
    idea how that's likely to pan out.
    
    This is a pretty consistent small win.  It's been through the rounds in my
    tester.  Just waiting on a green light from pre-commit testing.
    
    gcc/
            * config/riscv/zicond.md: Add new splitters to select
            1, -1 or -1, 1 based on a sign bit test.
    
    gcc/testsuite/
    
            * gcc.target/riscv/nozicond-1.c: New test.
            * gcc.target/riscv/nozicond-2.c: New test.

Diff:
---
 gcc/config/riscv/zicond.md                  | 36 ++++++++++++++++++++++++++++-
 gcc/testsuite/gcc.target/riscv/nozicond-1.c | 11 +++++++++
 gcc/testsuite/gcc.target/riscv/nozicond-2.c | 15 ++++++++++++
 3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index f87b4f25c0b0..d170f6ab2628 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -234,5 +234,39 @@
                                      (const_int 0)
                                      (match_dup 4)))])
 
+;; We can splat the sign bit across a GPR with a arithmetic right shift
+;; which gives us a 0, -1 result.  We then turn on bit #0 unconditionally
+;; which results in 1, -1.  There's probably other cases that could be
+;; handled, this seems particularly important though.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (plus:X (if_then_else:X (ge:X (match_operand:X 1 "register_operand")
+                                     (const_int 0))
+                               (match_operand 2 "const_int_operand")
+                               (match_operand 3 "const_int_operand"))
+               (match_operand 4 "const_int_operand")))]
+  "((TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV)
+    && INTVAL (operands[2]) + INTVAL (operands[4]) == 1
+    && INTVAL (operands[3]) + INTVAL (operands[4]) == -1)"
+  [(set (match_dup 0) (ashiftrt:X (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (ior:X (match_dup 0) (const_int 1)))]
+  { operands[2] = GEN_INT (GET_MODE_BITSIZE (word_mode) - 1); })
 
-
+;; Similarly, but the condition and true/false values are reversed
+;;
+;; Note the case where the condition is reversed, but not the true/false
+;; values.  Or vice-versa is not handled because we don't support 4->3
+;; splits.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (plus:X (if_then_else:X (lt:X (match_operand:X 1 "register_operand")
+                                     (const_int 0))
+                               (match_operand 2 "const_int_operand")
+                               (match_operand 3 "const_int_operand"))
+               (match_operand 4 "const_int_operand")))]
+  "((TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV)
+    && INTVAL (operands[2]) + INTVAL (operands[4]) == -1
+    && INTVAL (operands[3]) + INTVAL (operands[4]) == 1)"
+  [(set (match_dup 0) (ashiftrt:X (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (ior:X (match_dup 0) (const_int 1)))]
+  { operands[2] = GEN_INT (GET_MODE_BITSIZE (word_mode) - 1); })
diff --git a/gcc/testsuite/gcc.target/riscv/nozicond-1.c 
b/gcc/testsuite/gcc.target/riscv/nozicond-1.c
new file mode 100644
index 000000000000..35ab6fe56949
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/nozicond-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-additional-options "-march=rv64gc_zicond -mabi=lp64d -mbranch-cost=4" 
} */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+
+long foo1 (long c) { return c >= 0 ? 1 : -1; }
+long foo2 (long c) { return c < 0 ? -1 : 1; }
+
+/* { dg-final { scan-assembler-times {srai\t}  2 } } */
+/* { dg-final { scan-assembler-times {ori\t}  2 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/nozicond-2.c 
b/gcc/testsuite/gcc.target/riscv/nozicond-2.c
new file mode 100644
index 000000000000..f70525342a85
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/nozicond-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-additional-options "-march=rv64gc_zicond -mabi=lp64d -mbranch-cost=4" 
} */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+
+long foo1 (long c) { return c < 0 ? 1 : -1; }
+long foo2 (long c) { return c >= 0 ? -1 : 1; }
+
+/* We don't support 4->3 splitters, so this fails.  We could perhaps
+   try to catch it in the expander as a special case rather than waiting
+   for combine.  */
+/* { dg-final { scan-assembler-times {srai\t} 2 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {ori\t} 2 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {not\t} 2 { xfail *-*-* } } } */
+

Reply via email to