[llvm] [X86] Fix XOR folding in EmitCmp (PR #216134)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 13 11:03:10 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: AZero13 (AZero13)
<details>
<summary>Changes</summary>
Prevent redundant xors from being emitted.
---
Full diff: https://github.com/llvm/llvm-project/pull/216134.diff
2 Files Affected:
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+29)
- (modified) llvm/test/CodeGen/X86/cmp-xor.ll (+48)
``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index eed9416741c17..37eb3715809d0 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -59481,6 +59481,34 @@ static SDValue combineX86AddSub(SDNode *N, SelectionDAG &DAG,
/*ZeroSecondOpOnly*/ true);
}
+static SDValue combineX86XOR(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI) {
+ assert(N->getOpcode() == X86ISD::XOR && "Expected X86ISD::XOR");
+
+ SDLoc DL(N);
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ MVT VT = LHS.getSimpleValueType();
+
+ // If we don't use the flag result, simplify back to a generic op.
+ if (!N->hasAnyUseOfValue(1)) {
+ SDValue Res = DAG.getNode(ISD::XOR, DL, VT, LHS, RHS);
+ return DAG.getMergeValues({Res, DAG.getConstant(0, DL, MVT::i32)}, DL);
+ }
+
+ // Fold any matching generic 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(ISD::XOR, VTs, Ops))
+ DCI.CombineTo(Generic, SDValue(N, 0));
+ };
+ MatchGeneric(LHS, RHS);
+ MatchGeneric(RHS, LHS);
+
+ return SDValue();
+}
+
static SDValue combineSBB(SDNode *N, SelectionDAG &DAG) {
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
@@ -63240,6 +63268,7 @@ 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::XOR: return combineX86XOR(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 a8a7da4871ba9..b49c6dc386a12 100644
--- a/llvm/test/CodeGen/X86/cmp-xor.ll
+++ b/llvm/test/CodeGen/X86/cmp-xor.ll
@@ -54,3 +54,51 @@ 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: xorl $7, (%eax)
+; X86-NEXT: setne %al
+; X86-NEXT: retl
+;
+; X64-LABEL: xor_cmp_rmw_i32:
+; X64: # %bb.0:
+; X64-NEXT: xorl $7, (%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
+}
+
+define i32 @xor_cmp_multiuse(i32 %a, i32 %b, ptr %p) {
+; X86-LABEL: xor_cmp_multiuse:
+; X86: # %bb.0:
+; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT: xorl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT: movl %ecx, (%eax)
+; X86-NEXT: movl $42, %eax
+; X86-NEXT: je .LBB3_2
+; X86-NEXT: # %bb.1:
+; X86-NEXT: movl %ecx, %eax
+; X86-NEXT: .LBB3_2:
+; X86-NEXT: retl
+;
+; X64-LABEL: xor_cmp_multiuse:
+; X64: # %bb.0:
+; X64-NEXT: xorl %esi, %edi
+; X64-NEXT: movl %edi, (%rdx)
+; X64-NEXT: movl $42, %eax
+; X64-NEXT: cmovnel %edi, %eax
+; X64-NEXT: retq
+ %xor = xor i32 %a, %b
+ store i32 %xor, ptr %p
+ %cmp = icmp eq i32 %a, %b
+ %sel = select i1 %cmp, i32 42, i32 %xor
+ ret i32 %sel
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/216134
More information about the llvm-commits
mailing list