When one of the two input operands is 0, ADD and IOR are functionally
equivalent.
ADD is slightly preferred over IOR because ADD has a higher likelihood
of being implemented as a compressed instruction when compared to IOR.
C.ADD uses the CR format with any of the 32 RVI registers availble,
while C.OR uses the CA format with limit to just 8 of them.
Conditional select, if zero case:
rd = (rc == 0) ? rs1 : rs2
before patch:
czero.nez rd, rs1, rc
czero.eqz rtmp, rs2, rc
or rd, rd, rtmp
after patch:
czero.eqz rd, rs1, rc
czero.nez rtmp, rs2, rc
add rd, rd, rtmp
Same trick applies for the conditional select, if non-zero case:
rd = (rc != 0) ? rs1 : rs2
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_expand_conditional_move):
replace or with add when expanding zicond if possible.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zicond-prefer-add-to-or.c: New test.
gen_rtx_IF_THEN_ELSE (mode, cond1,
CONST0_RTX (mode),
alt)));
- riscv_emit_binary (IOR, dest, reg1, reg2);
+ riscv_emit_binary (PLUS, dest, reg1, reg2);
return true;
}
}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d -mbranch-cost=4" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f -mbranch-cost=4" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Os" "-Oz"} } */
+
+long cond_select_if_zero(long a, long b, long c) {
+ return a == 0 ? c : b;
+}
+
+long cond_select_if_non_zero(long a, long b, long c) {
+ return a != 0 ? c : b;
+}
+
+/* { dg-final { scan-assembler-times {add\t} 2 } } */
+/* { dg-final { scan-assembler-not {or\t} } } */
+