summaryrefslogtreecommitdiff
path: root/lib/CodeGen/AtomicExpandLoadLinkedPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/AtomicExpandLoadLinkedPass.cpp')
-rw-r--r--lib/CodeGen/AtomicExpandLoadLinkedPass.cpp53
1 files changed, 28 insertions, 25 deletions
diff --git a/lib/CodeGen/AtomicExpandLoadLinkedPass.cpp b/lib/CodeGen/AtomicExpandLoadLinkedPass.cpp
index fbb6e9662d..6f93ced85b 100644
--- a/lib/CodeGen/AtomicExpandLoadLinkedPass.cpp
+++ b/lib/CodeGen/AtomicExpandLoadLinkedPass.cpp
@@ -299,41 +299,44 @@ bool AtomicExpandLoadLinked::expandAtomicCmpXchg(AtomicCmpXchgInst *CI) {
// Setup the builder so we can create any PHIs we need.
Builder.SetInsertPoint(FailureBB, FailureBB->begin());
BasicBlock *SuccessBB = FailureOrder == Monotonic ? BarrierBB : TryStoreBB;
- PHINode *Success = nullptr, *Failure = nullptr;
+ PHINode *Success = Builder.CreatePHI(Type::getInt1Ty(Ctx), 2);
+ Success->addIncoming(ConstantInt::getTrue(Ctx), SuccessBB);
+ Success->addIncoming(ConstantInt::getFalse(Ctx), LoopBB);
// Look for any users of the cmpxchg that are just comparing the loaded value
// against the desired one, and replace them with the CFG-derived version.
+ SmallVector<ExtractValueInst *, 2> PrunedInsts;
for (auto User : CI->users()) {
- ICmpInst *ICmp = dyn_cast<ICmpInst>(User);
- if (!ICmp)
+ ExtractValueInst *EV = dyn_cast<ExtractValueInst>(User);
+ if (!EV)
continue;
- // Because we know ICmp uses CI, we only need one operand to be the old
- // value.
- if (ICmp->getOperand(0) != CI->getCompareOperand() &&
- ICmp->getOperand(1) != CI->getCompareOperand())
- continue;
+ assert(EV->getNumIndices() == 1 && EV->getIndices()[0] <= 1 &&
+ "weird extraction from { iN, i1 }");
- if (ICmp->getPredicate() == CmpInst::ICMP_EQ) {
- if (!Success) {
- Success = Builder.CreatePHI(Type::getInt1Ty(Ctx), 2);
- Success->addIncoming(ConstantInt::getTrue(Ctx), SuccessBB);
- Success->addIncoming(ConstantInt::getFalse(Ctx), LoopBB);
- }
- ICmp->replaceAllUsesWith(Success);
- } else if (ICmp->getPredicate() == CmpInst::ICMP_NE) {
- if (!Failure) {
- Failure = Builder.CreatePHI(Type::getInt1Ty(Ctx), 2);
- Failure->addIncoming(ConstantInt::getFalse(Ctx), SuccessBB);
- Failure->addIncoming(ConstantInt::getTrue(Ctx), LoopBB);
- }
- ICmp->replaceAllUsesWith(Failure);
- }
+ if (EV->getIndices()[0] == 0)
+ EV->replaceAllUsesWith(Loaded);
+ else
+ EV->replaceAllUsesWith(Success);
+
+ PrunedInsts.push_back(EV);
}
- CI->replaceAllUsesWith(Loaded);
- CI->eraseFromParent();
+ // We can remove the instructions now we're no longer iterating through them.
+ for (auto EV : PrunedInsts)
+ EV->eraseFromParent();
+ if (!CI->use_empty()) {
+ // Some use of the full struct return that we don't understand has happened,
+ // so we've got to reconstruct it properly.
+ Value *Res;
+ Res = Builder.CreateInsertValue(UndefValue::get(CI->getType()), Loaded, 0);
+ Res = Builder.CreateInsertValue(Res, Success, 1);
+
+ CI->replaceAllUsesWith(Res);
+ }
+
+ CI->eraseFromParent();
return true;
}