]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ifcvt: cond zero arith: elide short forward branch for signed GE 0 comparison [PR122769]
authorVineet Gupta <vineetg@rivosinc.com>
Mon, 22 Dec 2025 16:54:06 +0000 (08:54 -0800)
committerVineet Gupta <vineetg@rivosinc.com>
Mon, 22 Dec 2025 17:11:32 +0000 (09:11 -0800)
             Before            After
      ---------------------+----------------------
        bge a0,zero,.L2    | slti      a0,a0,0
                           | czero.eqz a0,a0,a0
        xor a1,a1,a3       | xor       a0,a0,a0
      .L2                  |
        mv  a0,a1          |
        ret                | ret

This is what all the prev NFC patches have been preparing to get to.

Currently the cond arith code only handles EQ/NE zero conditions missing
ifcvt optimization for cases such as GE zero, as show in example above.
This is due to the limitation of noce_emit_czero () so switch to
noce_emit_cmove () which can handle conditions other than EQ/NE and
if needed generate additional supporting insns such as SLT.

This also allows us to remove the constraint at the entry to limit to EQ/NE
conditions, improving ifcvt outcomes in general.

PR target/122769

gcc/ChangeLog:

* ifcvt.cc (noce_try_cond_zero_arith): Use noce_emit_cmove.
Delete noce_emit_czero () no longer used.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/pr122769.c: New test.

Co-authored-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
Signed-off-by: Vineet Gupta <vineetg@rivosinc.com>
gcc/ifcvt.cc
gcc/testsuite/gcc.target/riscv/pr122769.c [new file with mode: 0644]

index ef59a93e987e9c70b96edae3830d8c5fa580cca9..280f398cee6cb24ed78300a19337bffdd86f2cf9 100644 (file)
@@ -2037,35 +2037,6 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
     return NULL_RTX;
 }
 
-/*  Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
-    IF_INFO describes the if-conversion scenario under consideration.
-    CZERO_CODE selects the condition (EQ/NE).
-    NON_ZERO_OP is the nonzero operand of the conditional move
-    TARGET is the desired output register.  */
-
-static rtx
-noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
-                rtx non_zero_op, rtx target)
-{
-  machine_mode mode = GET_MODE (target);
-  rtx cond_op0 = XEXP (if_info->cond, 0);
-  rtx czero_cond
-    = gen_rtx_fmt_ee (czero_code, GET_MODE (cond_op0), cond_op0, const0_rtx);
-  rtx if_then_else
-    = gen_rtx_IF_THEN_ELSE (mode, czero_cond, const0_rtx, non_zero_op);
-  rtx set = gen_rtx_SET (target, if_then_else);
-
-  rtx_insn *insn = make_insn_raw (set);
-
-  if (recog_memoized (insn) >= 0)
-    {
-      add_insn (insn);
-      return target;
-    }
-
-  return NULL_RTX;
-}
-
 /* Try only simple constants and registers here.  More complex cases
    are handled in noce_try_cmove_arith after noce_try_store_flag_arith
    has had a go at it.  */
@@ -3177,10 +3148,6 @@ noce_try_cond_zero_arith (struct noce_if_info *if_info)
   if (!noce_simple_bbs (if_info))
     return false;
 
-  /* COND must be EQ or NE comparision of a reg and 0.  */
-  if (GET_CODE (cond) != NE && GET_CODE (cond) != EQ)
-    return false;
-
   if (!REG_P (XEXP (cond, 0)) || !rtx_equal_p (XEXP (cond, 1), const0_rtx))
     return false;
 
@@ -3222,9 +3189,10 @@ noce_try_cond_zero_arith (struct noce_if_info *if_info)
   target = gen_reg_rtx (mode);
 
   /* AND requires !cond, instead we swap ops around.  */
-  target = noce_emit_czero (if_info, GET_CODE (if_info->cond),
-                           op != AND ? a_op1 : a_op0, target);
-
+  target = noce_emit_cmove (if_info, target, GET_CODE (if_info->cond),
+                           XEXP (if_info->cond, 0), XEXP (if_info->cond, 1),
+                           op != AND ? a_op1 : const0_rtx,
+                           op != AND ? const0_rtx : a_op0);
   if (!target)
     goto end_seq_n_fail;
 
diff --git a/gcc/testsuite/gcc.target/riscv/pr122769.c b/gcc/testsuite/gcc.target/riscv/pr122769.c
new file mode 100644 (file)
index 0000000..0f7e19c
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc_zbs_zicond -mabi=lp64d" { target rv64} } */
+
+/* Elide a short forward branch and generate a czero instead.  */
+
+#include <stdint.h>
+
+uint64_t updateLSB63 (uint64_t val, uint64_t val2, int bits, int n)
+{
+  if (val & (1ULL << 63))
+    val2 ^= n;
+  return val2;
+}
+
+/* { dg-final { scan-assembler-times {\tczero} 1 } } */
+/* { dg-final { scan-assembler-not {\tbge} } } */
+