InstCombine: Rely on cmpxchg's return code when it's strong
authorDavid Majnemer <david.majnemer@gmail.com>
Thu, 6 Nov 2014 23:23:30 +0000 (23:23 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Thu, 6 Nov 2014 23:23:30 +0000 (23:23 +0000)
Comparing the result of a cmpxchg instruction can be replaced with an
extractvalue of the cmpxchg success indicator.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221498 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/InstCombine/InstCombineCompares.cpp
test/Transforms/InstCombine/icmp.ll

index f7eb16cbb96dd5f985f0103db2db646176e2d4b8..399f1c3175578a9686d1b632f381a81259ba8490 100644 (file)
@@ -3418,6 +3418,22 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) {
     }
   }
 
+  // The 'cmpxchg' instruction returns an aggregate containing the old value and
+  // an i1 which indicates whether or not we successfully did the swap.
+  //
+  // Replace comparisons between the old value and the expected value with the
+  // indicator that 'cmpxchg' returns.
+  //
+  // N.B.  This transform is only valid when the 'cmpxchg' is not permitted to
+  // spuriously fail.  In those cases, the old value may equal the expected
+  // value but it is possible for the swap to not occur.
+  if (I.getPredicate() == ICmpInst::ICMP_EQ)
+    if (auto *EVI = dyn_cast<ExtractValueInst>(Op0))
+      if (auto *ACXI = dyn_cast<AtomicCmpXchgInst>(EVI->getAggregateOperand()))
+        if (EVI->getIndices()[0] == 0 && ACXI->getCompareOperand() == Op1 &&
+            !ACXI->isWeak())
+          return ExtractValueInst::Create(ACXI, 1);
+
   {
     Value *X; ConstantInt *Cst;
     // icmp X+Cst, X
index 8c65d9cefc8301705adf66104283883f7b324704..279d86d405191315da163a5a3e6c1725ad08048f 100644 (file)
@@ -1511,3 +1511,14 @@ define i1 @icmp_sle_zero_add_nsw(i32 %a) {
  %cmp = icmp sle i32 %add, 0
  ret i1 %cmp
 }
+
+; CHECK-LABEL: @icmp_cmpxchg_strong
+; CHECK-NEXT: %[[xchg:.*]] = cmpxchg i32* %sc, i32 %old_val, i32 %new_val seq_cst seq_cst
+; CHECK-NEXT: %[[icmp:.*]] = extractvalue { i32, i1 } %[[xchg]], 1
+; CHECK-NEXT: ret i1 %[[icmp]]
+define zeroext i1 @icmp_cmpxchg_strong(i32* %sc, i32 %old_val, i32 %new_val) {
+  %xchg = cmpxchg i32* %sc, i32 %old_val, i32 %new_val seq_cst seq_cst
+  %xtrc = extractvalue { i32, i1 } %xchg, 0
+  %icmp = icmp eq i32 %xtrc, %old_val
+  ret i1 %icmp
+}