[V3][RISC-V][PR rtl-optimization/96692] Improve xor+xor+ior sequence when possible

Consider this code:

int f(int a, int b, int c)
{
    return (a ^ b) ^ (a | c);
}

For RISC-V we generate something like this:

        xor     a1,a0,a1
        or      a0,a0,a2
        xor     a0,a1,a0

But this would be better:

        andn    a0,a2,a0
        xor     a0,a0,a1

It looks like Roger tackled this earlier with splitters for x86. I'd have
leaned more towards simplify-rtx, but there may be secondary concerns at play.
So I'll attack in the RISC-V target files in a similar manner.

The patch, but not the testcase, have been in my tester for a while, so it's
been bootstrapped and regression tested on the Pioneer and BPI-F3 board and
regression tested on riscv32-elf and riscv64-elf. Obviously I'll wait for
pre-commit CI before moving forward.

	PR rtl-optimization/96692
gcc/
	* config/riscv/bitmanip.md (xor+xor+ior splitters): New splitters
	that ultimately generate andn+xor when possible.

gcc/testsuite

	* gcc.target/riscv/pr96692.c: New test.
This commit is contained in:
Jeff Law
2026-04-30 21:37:34 -06:00
parent 2a5b03d40e
commit fff26a966b
2 changed files with 35 additions and 0 deletions

View File

@@ -1441,3 +1441,26 @@
operands[3] = gen_lowpart (DImode, operands[3]);
operands[6] = gen_lowpart (SImode, operands[5]);
})
(define_split
[(set (match_operand:X 0 "register_operand")
(xor:X (xor:X (ior:X (match_operand:X 1 "register_operand")
(match_operand:X 2 "register_operand"))
(match_dup 1))
(match_operand:X 3 "register_operand")))
(clobber (match_operand:X 4 "register_operand"))]
"TARGET_ZBB || TARGET_ZBKB"
[(set (match_dup 4) (and:X (not:X (match_dup 1)) (match_dup 2)))
(set (match_dup 0) (xor:X (match_dup 4) (match_dup 3)))])
(define_split
[(set (match_operand:X 0 "register_operand")
(xor:X (xor:X (ior:X (match_operand:X 1 "register_operand")
(match_operand:X 2 "register_operand"))
(match_dup 2))
(match_operand:X 3 "register_operand")))
(clobber (match_operand:X 4 "register_operand"))]
"TARGET_ZBB || TARGET_ZBKB"
[(set (match_dup 4) (and:X (not:X (match_dup 2)) (match_dup 1)))
(set (match_dup 0) (xor:X (match_dup 4) (match_dup 3)))])

View File

@@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-additional-options "-march=rv64gcb_zicond -mabi=lp64d" { target rv64 } } */
/* { dg-additional-options "-march=rv32gcb_zicond -mabi=ilp32" { target rv32 } } */
/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
int f(int a, int b, int c)
{
return (a ^ b) ^ (a | c);
}
/* { dg-final { scan-assembler-times "xor\t" 1 } } */
/* { dg-final { scan-assembler-times "andn\t" 1 } } */