]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V] Add splitters to restore condops generation after recent phiopt changes
authorJeff Law <jlaw@ventanamicro.com>
Mon, 7 Oct 2024 17:49:21 +0000 (11:49 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Mon, 7 Oct 2024 17:51:52 +0000 (11:51 -0600)
V2:
  Fix typo in ChangeLog.
  Remove now extraneous comment in cset-sext.c.
  Throttle back branch cost to 1 in various tests

--

Andrew P's recent improvements to phiopt regressed on the riscv testsuite.

Essentially the new code presented to the RTL optimizers is straightline code rather than branchy for the CE pass to analyze and optimize.  In the absence of conditional move support or sfb, the new code would be better.

Unfortunately the presented form isn't a great fit for xventanacondops, zicond or xtheadcondmov.  The net is the resulting code is actually slightly worse than before.  Essentially sne+czero turned into sne+sne+and.

Thankfully, combine is presented with

(and (ne (op1) (const_int 0))
     (ne (op2) (const_int 0)))

As the RHS of a set.  We can use a 3->2 splitter to guide combine on how to profitably rewrite the sequence in a form suitable for condops.  Just splitting that would be enough to fix the regression, but I'm fairly confident that other cases need to be handled and would have regressed had the testsuite been more thorough.

One arm of the AND is going to turn into an sCC instruction.  We have a variety of those that we support.  The codes vary as do the allowed operands of the sCC.  That produces a set of new splitters to handle those cases.

The other arm is going to turn into a czero (or similar) instruction. That one can be generalized to eq/ne.  So another set for that generalization.

We can remove a couple of XFAILs in the rv32 space as it's behaving much more like rv64 at this point.

For SFB targets it's unclear if the new code is better or worse.  In both cases it's a 3 instruction sequence.   So I just adjusted the test.  If the new code is worse for SFB, someone with an understanding of the tradeoffs for an SFB target will need to make adjustments.

Tested in my tester on rv64gcv and rv32gc.  Will wait for the pre-commit testers to render their verdict before moving forward.

gcc/

* config/riscv/iterators.md (scc_0): New code iterator.
* config/riscv/zicond.md: New splitters to improve code generated for
cases like (and (scc) (scc)) for zicond, xventanacondops, xtheadcondmov.

gcc/testsuite/

* gcc.target/riscv/cset-sext-sfb.c: Turn off ssa-phiopt.
* gcc.target/riscv/cset-sext-thead.c: Do not check CE output anymore.
* gcc.target/riscv/cset-sext-ventana.c: Similarly.  Adjust branch cost.
* gcc.target/riscv/cset-sext-zicond.c: Similarly.
* gcc.target/riscv/cset-sext.c: Similarly.  No longer allow
"neg" in asm output.

gcc/config/riscv/iterators.md
gcc/config/riscv/zicond.md
gcc/testsuite/gcc.target/riscv/cset-sext-sfb.c
gcc/testsuite/gcc.target/riscv/cset-sext-thead.c
gcc/testsuite/gcc.target/riscv/cset-sext-ventana.c
gcc/testsuite/gcc.target/riscv/cset-sext-zicond.c
gcc/testsuite/gcc.target/riscv/cset-sext.c

index 2844cb02ff09526c9f69615f5becfc4b0427fed4..872c542e90652a92b2947fdb9ff42700838b4bf6 100644 (file)
 (define_code_iterator any_ge [ge geu])
 (define_code_iterator any_lt [lt ltu])
 (define_code_iterator any_le [le leu])
+;; Iterators for conditions we can emit a sCC against 0 or a reg directly
+(define_code_iterator scc_0  [eq ne gt gtu])
 
 ; atomics code iterator
 (define_code_iterator any_atomic [plus ior xor and])
index 3876be7f9d297511474676d07b2029172aa42c7d..ab1a5337ee53822c2b8f44c7f991e60a89004b99 100644 (file)
 {
   operands[2] = GEN_INT (1 << UINTVAL(operands[2]));
 })
+
+;; In some cases gimple can give us a sequence with a logical and
+;; of two sCC insns.  This can be implemented an sCC feeding a
+;; conditional zero.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (ne:X (match_operand:X 1 "register_operand") (const_int 0))
+              (scc_0:X (match_operand:X 2 "register_operand")
+                       (match_operand:X 3 "reg_or_0_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (scc_0:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+;; Similarly but GE/GEU which requires (const_int 1) as an operand.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (ne:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_ge:X (match_operand:X 2 "register_operand")
+                        (const_int 1))))
+   (clobber (match_operand:X 3 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 3) (any_ge:X (match_dup 2) (const_int 1)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 3)))])
+
+;; Similarly but LU/LTU which allows an arith_operand
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (ne:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_lt:X (match_operand:X 2 "register_operand")
+                        (match_operand:X 3 "arith_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (any_lt:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+;; Finally LE/LEU which requires sle_operand.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (ne:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_le:X (match_operand:X 2 "register_operand")
+                        (match_operand:X 3 "sle_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (any_le:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+
+;; Inverted versions from above.  I tried to get this to work with
+;; iterators, but didn't have any success disambiguating the code attr
+;; for the eq/ne flip we have to do.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (eq:X (match_operand:X 1 "register_operand") (const_int 0))
+              (scc_0:X (match_operand:X 2 "register_operand")
+                       (match_operand:X 3 "reg_or_0_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (scc_0:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (ne:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+;; Similarly but GE/GEU which requires (const_int 1) as an operand.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (eq:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_ge:X (match_operand:X 2 "register_operand")
+                        (const_int 1))))
+   (clobber (match_operand:X 3 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 3) (any_ge:X (match_dup 2) (const_int 1)))
+   (set (match_dup 0) (if_then_else:X (ne:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 3)))])
+
+;; Similarly but LU/LTU which allows an arith_operand
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (eq:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_lt:X (match_operand:X 2 "register_operand")
+                        (match_operand:X 3 "arith_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (any_lt:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (ne:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+;; Finally LE/LEU which requires sle_operand.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (eq:X (match_operand:X 1 "register_operand") (const_int 0))
+              (any_le:X (match_operand:X 2 "register_operand")
+                        (match_operand:X 3 "sle_operand"))))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND_LIKE || TARGET_XTHEADCONDMOV"
+  [(set (match_dup 4) (any_le:X (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (if_then_else:X (ne:X (match_dup 1) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 4)))])
+
+
+
index 1a3e7104bd8c1b5ab25bf811ad443efe5c83f556..6e9f8cc61de09e6f73a53ebfebda6e83befcf2a6 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
-/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
-/* { dg-options "-march=rv32gc -mtune=sifive-7-series -mbranch-cost=1 -fdump-rtl-ce1" { target { rv32 } } } */
-/* { dg-options "-march=rv64gc -mtune=sifive-7-series -mbranch-cost=1 -fdump-rtl-ce1" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
+/* { dg-options "-march=rv32gc -mtune=sifive-7-series -mbranch-cost=1 -fno-ssa-phiopt -fdump-rtl-ce1" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc -mtune=sifive-7-series -mbranch-cost=1 -fno-ssa-phiopt -fdump-rtl-ce1" { target { rv64 } } } */
 
 int
 foo (long a, long b)
@@ -22,7 +22,7 @@ foo (long a, long b)
 1:
  */
 
-/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" { xfail { rv32 && { any-opts "-O1" } } } } } */
+/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" } }
 /* { dg-final { scan-assembler-times "\\ssnez\\s" 1 } } */
-/* { dg-final { scan-assembler-times "\\sbne\\s\[^\\s\]+\\s# movcc\\s" 1 { xfail { rv32 && { any-opts "-O1" } } } } } */
-/* { dg-final { scan-assembler-not "\\sbeq\\s" { xfail { rv32 && { any-opts "-O1" } } } } } */
+/* { dg-final { scan-assembler-times "\\sbne\\s\[^\\s\]+\\s# movcc\\s" 1 } } */
+/* { dg-final { scan-assembler-not "\\sbeq\\s" } } */
index 45b94704aaf6f17948f751b3f5097517855f109b..74cae71d7a0bb21c4d689df74977701759140a5d 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target rv64 } */
 /* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
-/* { dg-options "-march=rv64gc_xtheadcondmov -mtune=thead-c906 -mbranch-cost=1 -fdump-rtl-ce1" } */
+/* { dg-options "-march=rv64gc_xtheadcondmov -mtune=thead-c906 -mbranch-cost=1" } */
 
 int
 foo (long a, long b)
@@ -20,7 +20,6 @@ foo (long a, long b)
        th.mveqz        a0,zero,a1
  */
 
-/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" } } */
 /* { dg-final { scan-assembler-times "\\ssnez\\s" 1 } } */
 /* { dg-final { scan-assembler-times "\\s(?:th\\.mveqz|th\\.mvnez)\\s" 1 } } */
 /* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" } } */
index eac1e1376cb4e119b7f7bb6fe11dda3fa4608cbe..8c3ca98bc2fcec9118556968e850db4a2d09cb0f 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target rv64 } */
 /* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
-/* { dg-options "-march=rv64gc_xventanacondops -mtune=rocket -mbranch-cost=3 -fdump-rtl-ce1" } */
+/* { dg-options "-march=rv64gc_xventanacondops -mtune=rocket -mbranch-cost=1" } */
 
 int
 foo (long a, long b)
@@ -20,7 +20,6 @@ foo (long a, long b)
        vt.maskc        a0,a0,a1
  */
 
-/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" } } */
 /* { dg-final { scan-assembler-times "\\ssnez\\s" 1 } } */
 /* { dg-final { scan-assembler-times "\\svt\\.maskc\\s" 1 } } */
 /* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" } } */
index a526b0c3d5a68570354f7abf2ce316d0dd534805..ec715254d4e21c52d693e351243dbd78808d1013 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
-/* { dg-options "-march=rv64gc_zicond -mtune=rocket -mbranch-cost=3 -fdump-rtl-ce1" { target { rv64 } } } */
-/* { dg-options "-march=rv32gc_zicond -mtune=rocket -mbranch-cost=3 -fdump-rtl-ce1" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_zicond -mtune=rocket -mbranch-cost=1" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mtune=rocket -mbranch-cost=1" { target { rv32 } } } */
 
 int
 foo (long a, long b)
@@ -20,7 +20,6 @@ foo (long a, long b)
        czero.eqz       a0,a0,a1
  */
 
-/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" { xfail { rv32 && { any-opts "-O1" "-Os" "-Oz" } } } } } */
 /* { dg-final { scan-assembler-times "\\ssnez\\s" 1 } } */
-/* { dg-final { scan-assembler-times "\\sczero\\.eqz\\s" 1 { xfail { rv32 && { any-opts "-O1" "-Os" "-Oz" } } } } } */
-/* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" { xfail { rv32 && { any-opts "-O1" "-Os" "-Oz" } } } } } */
+/* { dg-final { scan-assembler-times "\\sczero\\.eqz\\s" 1 } } */
+/* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" } } */
index a1293cd62ea7eae5fd262a8603dd0732d303d383..e1c3239d146107fc10f23584a6e4e74fa7bf0542 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
-/* { dg-options "-march=rv32gc -mtune=sifive-5-series -mbranch-cost=6 -mmovcc -fdump-rtl-ce1" { target { rv32 } } } */
-/* { dg-options "-march=rv64gc -mtune=sifive-5-series -mbranch-cost=6 -mmovcc -fdump-rtl-ce1" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc -mtune=sifive-5-series -mbranch-cost=1 -mmovcc" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc -mtune=sifive-5-series -mbranch-cost=1 -mmovcc" { target { rv64 } } } */
 
 int
 foo (long a, long b)
@@ -17,11 +17,10 @@ foo (long a, long b)
 /* Expect branchless assembly like:
 
        snez    a1,a1
-       neg     a1,a1
        snez    a0,a0
        and     a0,a1,a0
  */
 
-/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through noce_try_cmove_arith" 1 "ce1" { xfail { rv32 && { any-opts "-O1" } } } } } */
-/* { dg-final { scan-assembler-times "\\ssnez\\s" 2 { xfail { rv32 && { any-opts "-O1" } } } } } */
-/* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" { xfail { rv32 && { any-opts "-O1" } } } } } */
+/* { dg-final { scan-assembler-times "\\ssnez\\s" 2 } } */
+/* { dg-final { scan-assembler-not "\\s(?:beq|bne)\\s" } } */
+/* { dg-final { scan-assembler-not "\\sneg\\s" } } */