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

Alexander Coffin via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 18 19:03:51 PDT 2026


https://github.com/GreenBeard updated https://github.com/llvm/llvm-project/pull/210546

>From 21bd35d21932eff8c9426b3f3fc7994bf9163fec Mon Sep 17 00:00:00 2001
From: Alexander Coffin <alexcoffin1999 at gmail.com>
Date: Sat, 18 Jul 2026 11:44:58 -0700
Subject: [PATCH 1/3] [X86] Add XOR read, modify, write folding test

---
 llvm/test/CodeGen/X86/xor-fold.ll | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/xor-fold.ll

diff --git a/llvm/test/CodeGen/X86/xor-fold.ll b/llvm/test/CodeGen/X86/xor-fold.ll
new file mode 100644
index 0000000000000..e52a17789537b
--- /dev/null
+++ b/llvm/test/CodeGen/X86/xor-fold.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefixes=X86
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefixes=X64
+
+define zeroext i1 @foo(ptr %x) {
+; X86-LABEL: foo:
+; 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
+  %1 = load i32, ptr %x
+  %2 = xor i32 %1, 7
+  store i32 %2, ptr %x
+  %tobool.not = icmp ne i32 %1, 7
+  ret i1 %tobool.not
+}

>From ab732b9e7c15a3f16852a4ff8806ec8cdf7d2e8a Mon Sep 17 00:00:00 2001
From: Alexander Coffin <alexcoffin1999 at gmail.com>
Date: Sat, 18 Jul 2026 10:55:03 -0700
Subject: [PATCH 2/3] [X86] Fix XOR folding in EmitCmp

---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 12 ++++++++++--
 llvm/test/CodeGen/X86/xor-fold.ll       |  8 ++------
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 791e04deb9583..79b3e3bc5d9af 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -24077,13 +24077,21 @@ static SDValue EmitCmp(SDValue Op0, SDValue Op1, X86::CondCode X86CC,
   // If we already have an XOR of the ops, use that to check for equality.
   // Else use SUB instead of CMP to enable CSE between SUB and CMP.
   unsigned X86Opc = X86ISD::SUB;
+  SDNode *IsdNode = nullptr;
   if ((X86CC == X86::COND_E || X86CC == X86::COND_NE) &&
-      (DAG.doesNodeExist(ISD::XOR, DAG.getVTList({CmpVT}), {Op0, Op1}) ||
-       DAG.doesNodeExist(ISD::XOR, DAG.getVTList({CmpVT}), {Op1, Op0})))
+      ((IsdNode = DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}),
+                                      {Op0, Op1})) ||
+       (IsdNode =
+            DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}), {Op1, Op0}))))
     X86Opc = X86ISD::XOR;
 
   SDVTList VTs = DAG.getVTList(CmpVT, MVT::i32);
   SDValue CmpOp = DAG.getNode(X86Opc, dl, VTs, Op0, Op1);
+
+  if (IsdNode != nullptr) {
+    DAG.ReplaceAllUsesWith(IsdNode, &CmpOp);
+  }
+
   return CmpOp.getValue(1);
 }
 
diff --git a/llvm/test/CodeGen/X86/xor-fold.ll b/llvm/test/CodeGen/X86/xor-fold.ll
index e52a17789537b..d57326a98637d 100644
--- a/llvm/test/CodeGen/X86/xor-fold.ll
+++ b/llvm/test/CodeGen/X86/xor-fold.ll
@@ -6,17 +6,13 @@ define zeroext i1 @foo(ptr %x) {
 ; X86-LABEL: foo:
 ; 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:       # %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
   %1 = load i32, ptr %x

>From 6fe02f305dfc36ca0b037ea7630b609ae388c6cb Mon Sep 17 00:00:00 2001
From: Alexander Coffin <alexcoffin1999 at gmail.com>
Date: Sat, 18 Jul 2026 14:24:07 -0700
Subject: [PATCH 3/3] address pr comments

---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 29 +++++++++++++------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 79b3e3bc5d9af..c996b92d031b8 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -24074,24 +24074,25 @@ static SDValue EmitCmp(SDValue Op0, SDValue Op1, X86::CondCode X86CC,
     return Add.getValue(1);
   }
 
-  // If we already have an XOR of the ops, use that to check for equality.
-  // Else use SUB instead of CMP to enable CSE between SUB and CMP.
-  unsigned X86Opc = X86ISD::SUB;
-  SDNode *IsdNode = nullptr;
-  if ((X86CC == X86::COND_E || X86CC == X86::COND_NE) &&
-      ((IsdNode = DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}),
-                                      {Op0, Op1})) ||
-       (IsdNode =
-            DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}), {Op1, Op0}))))
-    X86Opc = X86ISD::XOR;
-
   SDVTList VTs = DAG.getVTList(CmpVT, MVT::i32);
-  SDValue CmpOp = DAG.getNode(X86Opc, dl, VTs, Op0, Op1);
 
-  if (IsdNode != nullptr) {
-    DAG.ReplaceAllUsesWith(IsdNode, &CmpOp);
+  // If we already have an XOR of the ops, use that to check for equality.
+  // Else use SUB instead of CMP to enable CSE between SUB and CMP.
+  if (X86CC == X86::COND_E || X86CC == X86::COND_NE) {
+    SDNode *IsdNode =
+        DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}), {Op0, Op1});
+    if (IsdNode == nullptr) {
+      IsdNode =
+          DAG.getNodeIfExists(ISD::XOR, DAG.getVTList({CmpVT}), {Op1, Op0});
+    }
+    if (IsdNode != nullptr) {
+      SDValue CmpOp = DAG.getNode(X86ISD::XOR, dl, VTs, Op0, Op1);
+      DAG.ReplaceAllUsesOfValueWith(SDValue(IsdNode, 0), CmpOp);
+      return CmpOp.getValue(1);
+    }
   }
 
+  SDValue CmpOp = DAG.getNode(X86ISD::SUB, dl, VTs, Op0, Op1);
   return CmpOp.getValue(1);
 }
 



More information about the llvm-commits mailing list