[llvm] [X86] Fix XOR folding in EmitCmp (PR #216134)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 10:55:59 PDT 2026


https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/216134

Prevent redundant xors from being emitted.

>From 542ca8dc7d83462312b3f4027ce676eb2f4eb4e6 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Thu, 13 Aug 2026 13:26:33 -0400
Subject: [PATCH 1/2] Pre-commit test

---
 llvm/test/CodeGen/X86/cmp-xor.ll | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/llvm/test/CodeGen/X86/cmp-xor.ll b/llvm/test/CodeGen/X86/cmp-xor.ll
index a8a7da4871ba9..1012c9b4c4a45 100644
--- a/llvm/test/CodeGen/X86/cmp-xor.ll
+++ b/llvm/test/CodeGen/X86/cmp-xor.ll
@@ -54,3 +54,26 @@ define i32 @cmp_xor_i32_commute(i32 %a, i32 %b, i32 %c)
   ret i32 %sel
 }
 
+define zeroext i1 @xor_cmp_rmw_i32(ptr %x) {
+; X86-LABEL: xor_cmp_rmw_i32:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl (%eax), %ecx
+; X86-NEXT:    xorl $7, %ecx
+; X86-NEXT:    movl %ecx, (%eax)
+; X86-NEXT:    setne %al
+; X86-NEXT:    retl
+;
+; X64-LABEL: foo:
+; X64:       # %bb.0:
+; X64-NEXT:    movl (%rdi), %eax
+; X64-NEXT:    xorl $7, %eax
+; X64-NEXT:    movl %eax, (%rdi)
+; X64-NEXT:    setne %al
+; X64-NEXT:    retq
+  %load = load i32, ptr %x
+  %xor = xor i32 %load, 7
+  store i32 %xor, ptr %x
+  %cmp = icmp ne i32 %load, 7
+  ret i1 %cmp
+}

>From 7591ef135837f68c681661e05ffd84408b61b5df Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Thu, 13 Aug 2026 13:41:54 -0400
Subject: [PATCH 2/2] [X86] Fix XOR folding in EmitCmp

Prevent redundant folds from being emitted.
---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 49 +++++++++++++++++++++++++
 llvm/test/CodeGen/X86/cmp-xor.ll        | 10 ++---
 2 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index eed9416741c17..5f8043c80047a 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -59481,6 +59481,52 @@ static SDValue combineX86AddSub(SDNode *N, SelectionDAG &DAG,
                                    /*ZeroSecondOpOnly*/ true);
 }
 
+static SDValue combineX86Logic(SDNode *N, SelectionDAG &DAG,
+                               TargetLowering::DAGCombinerInfo &DCI) {
+  assert((X86ISD::AND == N->getOpcode() || X86ISD::OR == N->getOpcode() ||
+          X86ISD::XOR == N->getOpcode()) &&
+         "Expected X86ISD::AND, X86ISD::OR, or X86ISD::XOR");
+
+  SDLoc DL(N);
+  SDValue LHS = N->getOperand(0);
+  SDValue RHS = N->getOperand(1);
+  MVT VT = LHS.getSimpleValueType();
+
+  unsigned GenericOpc;
+  switch (N->getOpcode()) {
+  case X86ISD::AND:
+    GenericOpc = ISD::AND;
+    break;
+  case X86ISD::OR:
+    GenericOpc = ISD::OR;
+    break;
+  case X86ISD::XOR:
+    GenericOpc = ISD::XOR;
+    break;
+  default:
+    llvm_unreachable("unexpected opcode");
+  }
+
+  // If we don't use the flag result, simplify back to a generic op.
+  if (!N->hasAnyUseOfValue(1)) {
+    SDValue Res = DAG.getNode(GenericOpc, DL, VT, LHS, RHS);
+    return DAG.getMergeValues({Res, DAG.getConstant(0, DL, MVT::i32)}, DL);
+  }
+
+  // Fold any matching generic ISD::AND/OR/XOR nodes to reuse this node.
+  auto MatchGeneric = [&](SDValue N0, SDValue N1) {
+    SDValue Ops[] = {N0, N1};
+    SDVTList VTs = DAG.getVTList(N->getValueType(0));
+    if (SDNode *Generic = DAG.getNodeIfExists(GenericOpc, VTs, Ops))
+      DCI.CombineTo(Generic, SDValue(N, 0));
+  };
+  MatchGeneric(LHS, RHS);
+  // AND/OR/XOR are commutative, so check the reversed operand order too.
+  MatchGeneric(RHS, LHS);
+
+  return SDValue();
+}
+
 static SDValue combineSBB(SDNode *N, SelectionDAG &DAG) {
   SDValue LHS = N->getOperand(0);
   SDValue RHS = N->getOperand(1);
@@ -63240,6 +63286,9 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::SUB:            return combineSub(N, DAG, DCI, Subtarget);
   case X86ISD::ADD:
   case X86ISD::SUB:         return combineX86AddSub(N, DAG, DCI, Subtarget);
+  case X86ISD::AND:
+  case X86ISD::OR:
+  case X86ISD::XOR:         return combineX86Logic(N, DAG, DCI);
   case ISD::SADDSAT:
   case ISD::SSUBSAT:        return combineToHorizontalAddSub(N, DAG, Subtarget);
   case X86ISD::CLOAD:
diff --git a/llvm/test/CodeGen/X86/cmp-xor.ll b/llvm/test/CodeGen/X86/cmp-xor.ll
index 1012c9b4c4a45..eed1951898b1d 100644
--- a/llvm/test/CodeGen/X86/cmp-xor.ll
+++ b/llvm/test/CodeGen/X86/cmp-xor.ll
@@ -58,17 +58,13 @@ define zeroext i1 @xor_cmp_rmw_i32(ptr %x) {
 ; X86-LABEL: xor_cmp_rmw_i32:
 ; X86:       # %bb.0:
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    movl (%eax), %ecx
-; X86-NEXT:    xorl $7, %ecx
-; X86-NEXT:    movl %ecx, (%eax)
+; X86-NEXT:    xorl $7, (%eax)
 ; X86-NEXT:    setne %al
 ; X86-NEXT:    retl
 ;
-; X64-LABEL: foo:
+; X64-LABEL: xor_cmp_rmw_i32:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl (%rdi), %eax
-; X64-NEXT:    xorl $7, %eax
-; X64-NEXT:    movl %eax, (%rdi)
+; X64-NEXT:    xorl $7, (%rdi)
 ; X64-NEXT:    setne %al
 ; X64-NEXT:    retq
   %load = load i32, ptr %x



More information about the llvm-commits mailing list