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
