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 <[email protected]>
Signed-off-by: Vineet Gupta <[email protected]>
---
gcc/ifcvt.cc | 40 +++--------------------
gcc/testsuite/gcc.target/riscv/pr122769.c | 17 ++++++++++
2 files changed, 21 insertions(+), 36 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/pr122769.c
diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index ef59a93e987e..280f398cee6c 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -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
index 000000000000..0f7e19ca5045
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr122769.c
@@ -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} } } */
+
--
2.43.0