[Bug rtl-optimization/125731] Improve RISC-V sequence for conditional xor with a constant
cvs-commit at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Sun Jul 19 14:13:04 GMT 2026
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125731
--- Comment #4 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jeff Law <law@gcc.gnu.org>:
https://gcc.gnu.org/g:a33f26607eb4f3e3d68e575a0395401c940cf1c7
commit r17-2519-ga33f26607eb4f3e3d68e575a0395401c940cf1c7
Author: Jeff Law <jeffrey.law@oss.qualcomm.com>
Date: Sun Jul 19 08:11:23 2026 -0600
[committed] Improve select across A/A OP C where C is 2^n
Testing for PR125731 exposed a bit of unexpected behavior on loongarch.
Basically the PR125731 patch allows if-conversion to again handle
generating
conditional zero based sequences where one of the two operands in the
original
sequence was a constant integer. Generating a conditional zero based
sequence
usually results in better code than a generalized conditional move.
Discovering those cases better led to a regression on loongarch which seems
to
want to generate even more specialized sequences than a conditional select
across 0,2^n for things like conditional add. Consider this loongarch
assembly:
sltu $r12,$r0,$r12
slli.d $r12,$r12,16
add.d $r14,$r14,$r12
That's a conditional add by 65536. We use the sltu to generate 1/0, shift
that by 16 generating 65536/0, then add that result to the other operand.
With
the work for PR125731 we get this instead:
lu12i.w $r16,16 # 0x10
maskeqz $r12,$r16,$r12
add.d $r14,$r14,$r12
Normally I would prefer the 2nd sequence as the high part load has no
dependencies and can issue whenever is convenient, but loongarch explicitly
prefers the first sequence and I'm willing to assume that was done for a
good
reason. For RISC-V it's probably a toss-up. The first form likely
compresses
better and doesn't rely on zicond, but the second form has one less
incoming
dependency. Barring hard data, I'm going to declare them equivalent and
target
the sequence loongarch wants.
Thankfully this is a class of problems that's been on my radar for a while.
Given a select across A and A OP C where C is 2^N we can left shift the
result
of the SCC to give us a select across 0 and 2^n, then we emit A OP X (where
X
holds the result of that left shift). We can do this add, sub, shifts,
rotates, ior, xor, basically anything where "0" is a neutral operand. That
obviously excludes AND where -1 is the neutral. That's ultimately the same
set
of operators as the condzero arithmetic supports except we'd need to filter
out
AND.
The implementation is structured similar to store_flag_constants, though
simplified where obviously possible.
If we look at a couple subtests within the loongarch
conditional-move-opt-1.c
testcase, but compiling for RISC-V:
extern long lm, lr;
void
test_nez ()
{
if (lm != 0)
lr <<= (1 << 4);
lr += lm;
}
void
test_eqz ()
{
if (lm == 0)
lr >>= (1 << 2);
lr += lm;
}
The relevant conditional move sequences look like this:
slli a3,a5,16
czero.eqz t1,a3,t0
czero.nez t2,a5,t0
add a0,t2,t1
add a1,t0,a0
and:
srai a3,a5,4
czero.nez t1,a3,t0
czero.eqz t2,a5,t0
add a0,t2,t1
add a1,t0,a0
Not bad, but with this patch we clearly do better:
snez a3,t0
slli t1,a3,4
sll t2,a4,t1
add a0,t0,t2
and
seqz a3,t0
slli t1,a3,2
sra t2,a4,t1
add a0,t0,t2
Probably the same performance as the czeros can execute in parallel, but
it's
smaller from an encoding standpoint and doesn't require zicond.
Bootstrapped and regression tested on x86_64, alpha, armv7, loongarch64,
riscv64 (k3, k1 and c920). Probably others as well, though I didn't check
other
natives explicitly to see if it'd picked up the latest version of the
patch.
Interestingly enough this does trigger meaningfully during bootstraps on
various targets as I stumbled across multiple failures due to a couple
logic
errors in earlier versions.
There's still things that could be improved in here. Most obviously AND
handling, cases where STORE_FLAG_VALUE != 1 (which likely work due to
normalization, but our ability to test is limited), exploiting negated
logicals
for things like conditional bit clear, etc. Even with the limitations,
this
seems worthwhile to go forward now.
Pushing to the trunk.
PR target/125731
gcc/
* ifcvt.cc (noce_cond_zero_binary_op_supported): Move earlier.
(noce_try_shifted_store_flag): New function.
(noce_process_if_block): Use it.
gcc/testsuite
* gcc.target/riscv/pr125731-1.c: New test.
* gcc.target/riscv/rvv/vsetvl/vsetvl-15.c: Drop shift count test.
More information about the Gcc-bugs
mailing list