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.

Jeff
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 --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index f87b4f25c0b..d170f6ab262 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -234,5 +234,39 @@ (define_split
                                      (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 00000000000..844f5953dd8
--- /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, long a) { return c >= 0 ? 1 : -1; }
+long foo2 (long c, long a) { 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 00000000000..05e85257b18
--- /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, long a) { return c < 0 ? 1 : -1; }
+long foo2 (long c, long a) { 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