When if-conversion encounters sequences using immediates, the sequences can't trivially map back onto czero.eqz/czero.nezt (even if benefitial) due to czero.eqz/czero.nez not having immediate forms.
This adds a splitter to rewrite opportunities for Zicond that operate on an immediate by first putting the immediate into a register to enable the non-immediate czero.eqz/czero.nez instructions to operate on the value. Consider code, such as long func2 (long a, long c) { if (c) a = 2; else a = 5; return a; } which will be converted to func2: seqz a0,a2 neg a0,a0 andi a0,a0,3 addi a0,a0,2 ret Following this change, we generate li a0,3 czero.nez a0,a0,a2 addi a0,a0,2 ret This commit also introduces a simple unit test for if-conversion with immediate (literal) values as the sources for simple sets in the THEN and ELSE blocks. The test checks that the conditional-zero instruction (czero.eqz/nez) is emitted as part of the resulting branchless instruction sequence. gcc/ChangeLog: * config/riscv/zicond.md: Support immediates for czero.eqz/czero.nez through a splitter. gcc/testsuite/ChangeLog: * gcc.target/riscv/zicond-ifconv-imm.c: New test. Signed-off-by: Philipp Tomsich <philipp.toms...@vrull.eu> --- gcc/config/riscv/zicond.md | 20 +++++++++++++++++++ .../gcc.target/riscv/zicond-ifconv-imm.c | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md index 278e3a67802..19d0b35585b 100644 --- a/gcc/config/riscv/zicond.md +++ b/gcc/config/riscv/zicond.md @@ -28,3 +28,23 @@ (define_insn "*czero.<eqz>" (match_operand:DI 2 "register_operand" "r")))] "TARGET_ZICOND" "czero.<eqz>\t%0,%2,%1") + +;; Zicond does not have immediate forms, so we need to do extra work +;; to support these: if we encounter a vt.maskc/n with an immediate, +;; we split this into a load-immediate followed by a czero.eqz/nez. +(define_split + [(set (match_operand:DI 0 "register_operand") + (and:DI (neg:DI (match_operator:DI 1 "equality_operator" + [(match_operand:DI 2 "register_operand") + (const_int 0)])) + (match_operand:DI 3 "immediate_operand"))) + (clobber (match_operand:DI 4 "register_operand"))] + "TARGET_ZICOND" + [(set (match_dup 4) (match_dup 3)) + (set (match_dup 0) (and:DI (neg:DI (match_dup 1)) + (match_dup 4)))] +{ + /* Eliminate the clobber/temporary, if it is not needed. */ + if (!rtx_equal_p (operands[0], operands[2])) + operands[4] = operands[0]; +}) diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c b/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c new file mode 100644 index 00000000000..f410537a4f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */ + +/* Each function below should emit a czero.nez instruction */ + +long +foo0 (long a, long b, long c) +{ + if (c) + a = 0; + else + a = 5; + return a; +} + +/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */ +/* { dg-final { scan-assembler-not "beqz\t" } } */ +/* { dg-final { scan-assembler-not "bnez\t" } } */ -- 2.34.1