https://gcc.gnu.org/g:15952d674c9d6d4b0527da7ff48f9b520de6ca41

commit 15952d674c9d6d4b0527da7ff48f9b520de6ca41
Author: Jeff Law <[email protected]>
Date:   Sat Mar 14 08:58:03 2026 -0600

    Revamp zicond splits to unify across the eq/ne selection, and exploit 
commutativity.

Diff:
---
 gcc/config/riscv/zicond.md | 124 ++++++++++++++++++++-------------------------
 1 file changed, 55 insertions(+), 69 deletions(-)

diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 2aefcff4fefb..182df7eb825a 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -128,111 +128,97 @@
 ;; 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.
+;;
+;; AND is commutative, so every form has two variants
 (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"))]
+       (and:X (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])
+              (scc_0:X (match_operand:X 3 "register_operand")
+                       (match_operand:X 4 "reg_or_0_operand"))))
+   (clobber (match_operand:X 5 "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))
+  [(set (match_dup 5) (scc_0:X (match_dup 3) (match_dup 4)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup 1
+                                       [(match_dup 2) (const_int 0)])
                                      (const_int 0)
-                                     (match_dup 4)))])
+                                     (match_dup 5)))]
+  { PUT_CODE (operands[1], GET_CODE (operands[1]) == EQ ? NE : EQ); })
 
-;; 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"))]
+       (and:X (scc_0:X (match_operand:X 3 "register_operand")
+                       (match_operand:X 4 "reg_or_0_operand"))
+              (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])))
+   (clobber (match_operand:X 5 "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))
+  [(set (match_dup 5) (scc_0:X (match_dup 3) (match_dup 4)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup:X 1
+                                       [(match_dup 2) (const_int 0)])
                                      (const_int 0)
-                                     (match_dup 3)))])
+                                     (match_dup 5)))]
+  { PUT_CODE (operands[1], GET_CODE (operands[1]) == EQ ? NE : EQ); })
 
-;; 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.
+;; 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_le:X (match_operand:X 2 "register_operand")
-                        (match_operand:X 3 "sle_operand"))))
+       (and:X (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])
+              (any_ge:X (match_operand:X 3 "register_operand")
+                        (const_int 1))))
    (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))
+  [(set (match_dup 4) (any_ge:X (match_dup 3) (const_int 1)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup:X 1
+                                      [(match_dup 2) (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"))))
+       (and:X (any_ge:X (match_operand:X 3 "register_operand")
+                        (const_int 1))
+              (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])))
    (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))
+  [(set (match_dup 4) (any_ge:X (match_dup 3) (const_int 1)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup:X 1
+                                      [(match_dup 2) (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"))]
+       (and:X (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])
+              (any_lt:X (match_operand:X 3 "register_operand")
+                        (match_operand:X 4 "arith_operand"))))
+   (clobber (match_operand:X 5 "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))
+  [(set (match_dup 5) (any_lt:X (match_dup 3) (match_dup 4)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup:X 1
+                                      [(match_dup 2) (const_int 0)])
                                      (const_int 0)
-                                     (match_dup 4)))])
+                                     (match_dup 5)))])
 
 ;; 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"))]
+       (and:X (match_operator:X 1 "equality_operator"
+               [(match_operand:X 2 "register_operand") (const_int 0)])
+              (any_le:X (match_operand:X 3 "register_operand")
+                        (match_operand:X 4 "sle_operand"))))
+   (clobber (match_operand:X 5 "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))
+  [(set (match_dup 5) (any_le:X (match_dup 3) (match_dup 4)))
+   (set (match_dup 0) (if_then_else:X (match_op_dup:X 1
+                                      [(match_dup 2) (const_int 0)])
                                      (const_int 0)
-                                     (match_dup 4)))])
+                                     (match_dup 5)))])
 
 ;; 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

Reply via email to