On 26/07/2026 15:18, Shivam Gupta wrote:
At -O1, a complemented XOR whose result is masked to bit zero is
currently emitted as:
eor w0, w0, w1
ubfx x0, x0, 0, 1
eor w0, w0, 1
Recognize (and (not (xor ...)) 1) and split it into a complemented
XOR followed by an AND, allowing the complemented XOR to use EON:
eon w0, w0, w1
and w0, w0, 1
Tested on aarch64-unknown-linux-gnu with no regressions.
Thanks for the patch, some suggestions/comments below.
gcc/ChangeLog:
* config/aarch64/aarch64.md (*aarch64_xor_not_and_one): New
define_insn_and_split.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/xor-not-and-one.c: New test.
Signed-off-by: Shivam Gupta <[email protected]>
---
gcc/config/aarch64/aarch64.md | 14 +++++++++++
.../gcc.target/aarch64/xor-not-and-one.c | 23 +++++++++++++++++++
2 files changed, 37 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/xor-not-and-one.c
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index b2185c63819..1a61d7f85ca 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -5263,6 +5263,20 @@
;; Logical operations
;; -------------------------------------------------------------------
+(define_insn_and_split "*aarch64_xor_not_and_one<mode>"
Combine can handle 3->2 patterns without the need for intermediate insn
patterns, so I think this should just be a define_split (with a suitable
scratch clobber operand to hold the intermediate result).
+ [(set (match_operand:GPI 0 "register_operand" "=r")
+ (and:GPI
+ (not:GPI
+ (xor:GPI (match_operand:GPI 1 "register_operand" "r")
+ (match_operand:GPI 2 "register_operand" "r")))
+ (const_int 1)))]
The shape of this pattern is generic (eon + and), so there's no need to
restrict this to a literal 1. In fact, there's no real need for the
split pattern to restrict it to a constant, and operand that is valid
for AND should be OK here.
R.