[llvm] [X86] lock opt ptr const inconsistencies (PR #185195)

Takashi Idobe via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 12 06:07:54 PDT 2026


https://github.com/Takashiidobe updated https://github.com/llvm/llvm-project/pull/185195

>From 91eff3735662a9ca7ae7609c1ede30b25fd26981 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 12 Apr 2026 08:25:40 -0400
Subject: [PATCH 1/3] Add tests for atomicrmw and with zero/nonzero comparisons

---
 .../X86/atomic-lock-and-setcc-folded.ll       | 97 +++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll

diff --git a/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll b/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll
new file mode 100644
index 0000000000000..c2e2c64d4f988
--- /dev/null
+++ b/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll
@@ -0,0 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
+
+; When InstCombine sees (atomicrmw and ptr, C) followed by a comparison of the
+; result against zero, it can fold the intermediate 'and' away when -C is a
+; power of two.  The algebraic equivalence:
+;
+;   (old & C) == 0  <=>  old ult -C  ->  ZF=1
+;   (old & C) != 0  <=>  old ugt ~C  ->  ZF=0
+;
+; holds because C = ~(2^k - 1) means AND clears the bottom k bits, so the
+; result is zero iff old < 2^k = -C.  The lock and instruction still sets ZF
+; on (old & C), so no CAS loop is needed.
+
+; (old & -2) != 0 -> icmp ugt old, 1 should fold
+define i1 @lock_and_setne_folded(ptr %p) nounwind {
+; CHECK-LABEL: lock_and_setne_folded:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq (%rdi), %rax
+; CHECK-NEXT:    .p2align 4
+; CHECK-NEXT:  .LBB0_1: # %atomicrmw.start
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    andq $-2, %rcx
+; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
+; CHECK-NEXT:    jne .LBB0_1
+; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
+; CHECK-NEXT:    cmpq $2, %rax
+; CHECK-NEXT:    setae %al
+; CHECK-NEXT:    retq
+  %old = atomicrmw and ptr %p, i64 -2 seq_cst
+  %r = icmp ugt i64 %old, 1
+  ret i1 %r
+}
+
+; (old & -2) == 0 -> icmp ult old, 2 should fold
+define i1 @lock_and_sete_folded(ptr %p) nounwind {
+; CHECK-LABEL: lock_and_sete_folded:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq (%rdi), %rax
+; CHECK-NEXT:    .p2align 4
+; CHECK-NEXT:  .LBB1_1: # %atomicrmw.start
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    andq $-2, %rcx
+; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
+; CHECK-NEXT:    jne .LBB1_1
+; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
+; CHECK-NEXT:    cmpq $2, %rax
+; CHECK-NEXT:    setb %al
+; CHECK-NEXT:    retq
+  %old = atomicrmw and ptr %p, i64 -2 seq_cst
+  %r = icmp ult i64 %old, 2
+  ret i1 %r
+}
+
+; Different C: C=-4, -C=4=2^2. Fold holds for any k, not just k=1.
+define i1 @lock_and_setne_folded_c4(ptr %p) nounwind {
+; CHECK-LABEL: lock_and_setne_folded_c4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq (%rdi), %rax
+; CHECK-NEXT:    .p2align 4
+; CHECK-NEXT:  .LBB2_1: # %atomicrmw.start
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    andq $-4, %rcx
+; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
+; CHECK-NEXT:    jne .LBB2_1
+; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
+; CHECK-NEXT:    cmpq $4, %rax
+; CHECK-NEXT:    setae %al
+; CHECK-NEXT:    retq
+  %old = atomicrmw and ptr %p, i64 -4 seq_cst
+  %r = icmp ugt i64 %old, 3
+  ret i1 %r
+}
+
+; Negative test: -C=3 is not a power of 2, lower to CAS loop.
+define i1 @lock_and_setne_not_folded(ptr %p) nounwind {
+; CHECK-LABEL: lock_and_setne_not_folded:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq (%rdi), %rax
+; CHECK-NEXT:    .p2align 4
+; CHECK-NEXT:  .LBB3_1: # %atomicrmw.start
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    movq %rax, %rcx
+; CHECK-NEXT:    andq $-3, %rcx
+; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
+; CHECK-NEXT:    jne .LBB3_1
+; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
+; CHECK-NEXT:    cmpq $3, %rax
+; CHECK-NEXT:    setae %al
+; CHECK-NEXT:    retq
+  %old = atomicrmw and ptr %p, i64 -3 seq_cst
+  %r = icmp ugt i64 %old, 2
+  ret i1 %r
+}

>From df184db6adf9f6bb103b030f75edb16731ac4c73 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 12 Apr 2026 08:25:45 -0400
Subject: [PATCH 2/3] Fold InstCombine-canonicalized lock and with zero/nonzero
 tests

---
 llvm/lib/Target/X86/X86ISelLowering.cpp       | 230 ++++++++++++------
 .../X86/atomic-lock-and-setcc-folded.ll       |  39 +--
 2 files changed, 167 insertions(+), 102 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index cb701814154ff..a25e99e8e6177 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -32562,68 +32562,175 @@ void X86TargetLowering::emitBitTestAtomicRMWIntrinsic(AtomicRMWInst *AI) const {
   AI->eraseFromParent();
 }
 
-static bool shouldExpandCmpArithRMWInIR(const AtomicRMWInst *AI) {
+static X86::CondCode matchSignedNewValueCC(const Instruction *I) {
   using namespace llvm::PatternMatch;
-  if (!AI->hasOneUse())
-    return false;
+  if (match(I->user_back(),
+            m_SpecificICmp(CmpInst::ICMP_SLT, m_Value(), m_ZeroInt())))
+    return X86::COND_S;
+  if (match(I->user_back(),
+            m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
+    return X86::COND_NS;
+  return X86::COND_INVALID;
+}
 
+static X86::CondCode matchAddCC(const AtomicRMWInst *AI, const Instruction *I) {
+  using namespace llvm::PatternMatch;
   Value *Op = AI->getOperand(1);
   CmpPredicate Pred;
-  const Instruction *I = AI->user_back();
-  AtomicRMWInst::BinOp Opc = AI->getOperation();
-  if (Opc == AtomicRMWInst::Add) {
-    if (match(I, m_c_ICmp(Pred, m_Sub(m_ZeroInt(), m_Specific(Op)), m_Value())))
-      return Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE;
-    if (match(I, m_OneUse(m_c_Add(m_Specific(Op), m_Value())))) {
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SLT, m_Value(), m_ZeroInt())))
-        return true;
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
-        return true;
-    }
-    return false;
+
+  // InstCombine-folded ZF form: icmp eq/ne (old + Op), 0  ->  icmp eq/ne old,
+  // -Op lock add sets ZF on the new value; old + Op == 0  <=>  old == -Op  [ZF]
+  if (match(I, m_c_ICmp(Pred, m_Sub(m_ZeroInt(), m_Specific(Op)), m_Value()))) {
+    if (Pred == CmpInst::ICMP_EQ)
+      return X86::COND_E;
+    if (Pred == CmpInst::ICMP_NE)
+      return X86::COND_NE;
   }
-  if (Opc == AtomicRMWInst::Sub) {
-    if (match(I, m_c_ICmp(Pred, m_Specific(Op), m_Value())))
-      return Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE;
-    if (match(I, m_OneUse(m_Sub(m_Value(), m_Specific(Op))))) {
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SLT, m_Value(), m_ZeroInt())))
-        return true;
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
-        return true;
-    }
-    return false;
+
+  // Non-folded SF form: %new = add %old, Op; icmp slt/sgt %new, 0/-1
+  // lock add sets SF on the new value directly.
+  if (match(I, m_OneUse(m_c_Add(m_Specific(Op), m_Value()))))
+    return matchSignedNewValueCC(I);
+
+  return X86::COND_INVALID;
+}
+
+static X86::CondCode matchSubCC(const AtomicRMWInst *AI, const Instruction *I) {
+  using namespace llvm::PatternMatch;
+  Value *Op = AI->getOperand(1);
+  CmpPredicate Pred;
+
+  // InstCombine-folded ZF form: icmp eq/ne (old - Op), 0  ->  icmp eq/ne old,
+  // Op lock sub sets ZF on the new value; old - Op == 0  <=>  old == Op  [ZF]
+  if (match(I, m_c_ICmp(Pred, m_Specific(Op), m_Value()))) {
+    if (Pred == CmpInst::ICMP_EQ)
+      return X86::COND_E;
+    if (Pred == CmpInst::ICMP_NE)
+      return X86::COND_NE;
   }
-  if ((Opc == AtomicRMWInst::Or &&
-       match(I, m_OneUse(m_c_Or(m_Specific(Op), m_Value())))) ||
-      (Opc == AtomicRMWInst::And &&
-       match(I, m_OneUse(m_c_And(m_Specific(Op), m_Value()))))) {
-    if (match(I->user_back(), m_ICmp(Pred, m_Value(), m_ZeroInt())))
-      return Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE ||
-             Pred == CmpInst::ICMP_SLT;
+
+  // Non-folded SF form: %new = sub %old, Op; icmp slt/sgt %new, 0/-1
+  // lock sub sets SF on the new value directly.
+  if (match(I, m_OneUse(m_Sub(m_Value(), m_Specific(Op)))))
+    return matchSignedNewValueCC(I);
+
+  return X86::COND_INVALID;
+}
+
+static X86::CondCode matchOrCC(const AtomicRMWInst *AI, const Instruction *I) {
+  using namespace llvm::PatternMatch;
+  Value *Op = AI->getOperand(1);
+  CmpPredicate Pred;
+
+  // Non-folded form: %new = or %old, Op; icmp P %new, 0/-1
+  // lock or sets ZF/SF on the new value directly.
+  if (!match(I, m_OneUse(m_c_Or(m_Specific(Op), m_Value()))))
+    return X86::COND_INVALID;
+
+  if (match(I->user_back(), m_ICmp(Pred, m_Value(), m_ZeroInt()))) {
+    if (Pred == CmpInst::ICMP_EQ)
+      return X86::COND_E;
+    if (Pred == CmpInst::ICMP_NE)
+      return X86::COND_NE;
+    if (Pred == CmpInst::ICMP_SLT)
+      return X86::COND_S;
+  }
+  if (match(I->user_back(),
+            m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
+    return X86::COND_NS;
+
+  return X86::COND_INVALID;
+}
+
+static X86::CondCode matchAndCC(const AtomicRMWInst *AI, const Instruction *I) {
+  using namespace llvm::PatternMatch;
+  Value *Op = AI->getOperand(1);
+  CmpPredicate Pred;
+
+  // Non-folded form: %new = and %old, Op; icmp P %new, 0/-1
+  // lock and sets ZF/SF on the new value directly.
+  if (match(I, m_OneUse(m_c_And(m_Specific(Op), m_Value())))) {
+    if (match(I->user_back(), m_ICmp(Pred, m_Value(), m_ZeroInt()))) {
+      if (Pred == CmpInst::ICMP_EQ)
+        return X86::COND_E;
+      if (Pred == CmpInst::ICMP_NE)
+        return X86::COND_NE;
+      if (Pred == CmpInst::ICMP_SLT)
+        return X86::COND_S;
+    }
     if (match(I->user_back(),
               m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
-      return true;
-    return false;
+      return X86::COND_NS;
+    return X86::COND_INVALID;
+  }
+
+  // When -C is a power of 2, the intermediate and is eliminated and the icmp
+  // can just compare old directly. lock and still sets ZF on (old & C), so:
+  //   (old & C) == 0 <=> old ult -C -> ZF == 1
+  //   (old & C) != 0 <=> old ugt ~C -> ZF == 0
+  auto *CI = dyn_cast<ConstantInt>(Op);
+  if (!CI)
+    return X86::COND_INVALID;
+  const APInt &C = CI->getValue();
+  const APInt *K;
+  if (!(-C).isPowerOf2() ||
+      !match(I, m_c_ICmp(Pred, m_Specific(AI), m_APInt(K))))
+    return X86::COND_INVALID;
+  if (Pred == ICmpInst::ICMP_ULT && *K == -C)
+    return X86::COND_E;
+  if (Pred == ICmpInst::ICMP_UGT && *K == ~C)
+    return X86::COND_NE;
+  return X86::COND_INVALID;
+}
+
+static X86::CondCode matchXorCC(const AtomicRMWInst *AI, const Instruction *I) {
+  using namespace llvm::PatternMatch;
+  Value *Op = AI->getOperand(1);
+  CmpPredicate Pred;
+
+  // InstCombine-folded ZF form: icmp eq/ne (old ^ Op), 0  ->  icmp eq/ne old,
+  // Op lock xor sets ZF = (old ^ Op == 0) = (old == Op).
+  if (match(I, m_c_ICmp(Pred, m_Specific(Op), m_Value()))) {
+    if (Pred == CmpInst::ICMP_EQ)
+      return X86::COND_E;
+    if (Pred == CmpInst::ICMP_NE)
+      return X86::COND_NE;
   }
-  if (Opc == AtomicRMWInst::Xor) {
-    if (match(I, m_c_ICmp(Pred, m_Specific(Op), m_Value())))
-      return Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE;
-    if (match(I, m_OneUse(m_c_Xor(m_Specific(Op), m_Value())))) {
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SLT, m_Value(), m_ZeroInt())))
-        return true;
-      if (match(I->user_back(),
-                m_SpecificICmp(CmpInst::ICMP_SGT, m_Value(), m_AllOnes())))
-        return true;
-    }
-    return false;
+
+  // Non-folded SF form: %new = xor %old, Op; icmp slt/sgt %new, 0/-1
+  // lock xor sets SF on the new value directly.
+  if (match(I, m_OneUse(m_c_Xor(m_Specific(Op), m_Value()))))
+    return matchSignedNewValueCC(I);
+
+  return X86::COND_INVALID;
+}
+
+/// Return the X86 condition code for a CmpArith atomic RMW pattern that can
+/// be lowered to a lock instruction + setcc, or COND_INVALID if the pattern
+/// is not recognised.
+static X86::CondCode getCmpArithCC(const AtomicRMWInst *AI) {
+  if (!AI->hasOneUse())
+    return X86::COND_INVALID;
+
+  const Instruction *I = AI->user_back();
+  switch (AI->getOperation()) {
+  case AtomicRMWInst::Add:
+    return matchAddCC(AI, I);
+  case AtomicRMWInst::Sub:
+    return matchSubCC(AI, I);
+  case AtomicRMWInst::Or:
+    return matchOrCC(AI, I);
+  case AtomicRMWInst::And:
+    return matchAndCC(AI, I);
+  case AtomicRMWInst::Xor:
+    return matchXorCC(AI, I);
+  default:
+    return X86::COND_INVALID;
   }
+}
 
-  return false;
+static bool shouldExpandCmpArithRMWInIR(const AtomicRMWInst *AI) {
+  return getCmpArithCC(AI) != X86::COND_INVALID;
 }
 
 void X86TargetLowering::emitCmpArithAtomicRMWIntrinsic(
@@ -32638,24 +32745,9 @@ void X86TargetLowering::emitCmpArithAtomicRMWIntrinsic(
     assert(TempI->hasOneUse() && "Must have one use");
     ICI = cast<ICmpInst>(TempI->user_back());
   }
-  X86::CondCode CC = X86::COND_INVALID;
-  ICmpInst::Predicate Pred = ICI->getPredicate();
-  switch (Pred) {
-  default:
-    llvm_unreachable("Not supported Pred");
-  case CmpInst::ICMP_EQ:
-    CC = X86::COND_E;
-    break;
-  case CmpInst::ICMP_NE:
-    CC = X86::COND_NE;
-    break;
-  case CmpInst::ICMP_SLT:
-    CC = X86::COND_S;
-    break;
-  case CmpInst::ICMP_SGT:
-    CC = X86::COND_NS;
-    break;
-  }
+  X86::CondCode CC = getCmpArithCC(AI);
+  assert(CC != X86::COND_INVALID && "emitCmpArithAtomicRMWIntrinsic called "
+                                    "without a recognised pattern");
   Intrinsic::ID IID = Intrinsic::not_intrinsic;
   switch (AI->getOperation()) {
   default:
diff --git a/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll b/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll
index c2e2c64d4f988..ee0b3b9caa2e7 100644
--- a/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll
+++ b/llvm/test/CodeGen/X86/atomic-lock-and-setcc-folded.ll
@@ -16,17 +16,8 @@
 define i1 @lock_and_setne_folded(ptr %p) nounwind {
 ; CHECK-LABEL: lock_and_setne_folded:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq (%rdi), %rax
-; CHECK-NEXT:    .p2align 4
-; CHECK-NEXT:  .LBB0_1: # %atomicrmw.start
-; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    andq $-2, %rcx
-; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
-; CHECK-NEXT:    jne .LBB0_1
-; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
-; CHECK-NEXT:    cmpq $2, %rax
-; CHECK-NEXT:    setae %al
+; CHECK-NEXT:    lock andq $-2, (%rdi)
+; CHECK-NEXT:    setne %al
 ; CHECK-NEXT:    retq
   %old = atomicrmw and ptr %p, i64 -2 seq_cst
   %r = icmp ugt i64 %old, 1
@@ -37,17 +28,8 @@ define i1 @lock_and_setne_folded(ptr %p) nounwind {
 define i1 @lock_and_sete_folded(ptr %p) nounwind {
 ; CHECK-LABEL: lock_and_sete_folded:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq (%rdi), %rax
-; CHECK-NEXT:    .p2align 4
-; CHECK-NEXT:  .LBB1_1: # %atomicrmw.start
-; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    andq $-2, %rcx
-; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
-; CHECK-NEXT:    jne .LBB1_1
-; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
-; CHECK-NEXT:    cmpq $2, %rax
-; CHECK-NEXT:    setb %al
+; CHECK-NEXT:    lock andq $-2, (%rdi)
+; CHECK-NEXT:    sete %al
 ; CHECK-NEXT:    retq
   %old = atomicrmw and ptr %p, i64 -2 seq_cst
   %r = icmp ult i64 %old, 2
@@ -58,17 +40,8 @@ define i1 @lock_and_sete_folded(ptr %p) nounwind {
 define i1 @lock_and_setne_folded_c4(ptr %p) nounwind {
 ; CHECK-LABEL: lock_and_setne_folded_c4:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq (%rdi), %rax
-; CHECK-NEXT:    .p2align 4
-; CHECK-NEXT:  .LBB2_1: # %atomicrmw.start
-; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    movq %rax, %rcx
-; CHECK-NEXT:    andq $-4, %rcx
-; CHECK-NEXT:    lock cmpxchgq %rcx, (%rdi)
-; CHECK-NEXT:    jne .LBB2_1
-; CHECK-NEXT:  # %bb.2: # %atomicrmw.end
-; CHECK-NEXT:    cmpq $4, %rax
-; CHECK-NEXT:    setae %al
+; CHECK-NEXT:    lock andq $-4, (%rdi)
+; CHECK-NEXT:    setne %al
 ; CHECK-NEXT:    retq
   %old = atomicrmw and ptr %p, i64 -4 seq_cst
   %r = icmp ugt i64 %old, 3

>From 4d1fc072d944015dedebb76dac8dfae1cd09e648 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 12 Apr 2026 09:07:39 -0400
Subject: [PATCH 3/3] code review feedback: sub(0 - X) replaced with neg(X) to
 match the and ZF power of two optimization

---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index a25e99e8e6177..4a0491d53485b 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -32580,7 +32580,7 @@ static X86::CondCode matchAddCC(const AtomicRMWInst *AI, const Instruction *I) {
 
   // InstCombine-folded ZF form: icmp eq/ne (old + Op), 0  ->  icmp eq/ne old,
   // -Op lock add sets ZF on the new value; old + Op == 0  <=>  old == -Op  [ZF]
-  if (match(I, m_c_ICmp(Pred, m_Sub(m_ZeroInt(), m_Specific(Op)), m_Value()))) {
+  if (match(I, m_c_ICmp(Pred, m_Neg(m_Specific(Op)), m_Value()))) {
     if (Pred == CmpInst::ICMP_EQ)
       return X86::COND_E;
     if (Pred == CmpInst::ICMP_NE)



More information about the llvm-commits mailing list