From: Jeff Law Date: Fri, 1 May 2026 03:37:34 +0000 (-0600) Subject: [V3][RISC-V][PR rtl-optimization/96692] Improve xor+xor+ior sequence when possible X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fff26a966b9f686bbdfb1baaac757bd9352af7fd;p=thirdparty%2Fgcc.git [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. --- diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index c9561b0b622..79ab17b6a60 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -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)))]) + diff --git a/gcc/testsuite/gcc.target/riscv/pr96692.c b/gcc/testsuite/gcc.target/riscv/pr96692.c new file mode 100644 index 00000000000..650f4f0f80d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr96692.c @@ -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 } } */