Index: lib/CodeGen/AtomicExpandPass.cpp |
diff --git a/lib/CodeGen/AtomicExpandPass.cpp b/lib/CodeGen/AtomicExpandPass.cpp |
index fa17108b2a8eb36fcbe24289154c965b7b308c46..c1ede417026f1a4e0a392758816e56956a2216b1 100644 |
--- a/lib/CodeGen/AtomicExpandPass.cpp |
+++ b/lib/CodeGen/AtomicExpandPass.cpp |
@@ -12,6 +12,7 @@ |
// |
//===----------------------------------------------------------------------===// |
+#include "llvm/CodeGen/AtomicExpandUtils.h" |
#include "llvm/CodeGen/Passes.h" |
#include "llvm/IR/Function.h" |
#include "llvm/IR/IRBuilder.h" |
@@ -50,7 +51,6 @@ namespace { |
bool expandAtomicStore(StoreInst *SI); |
bool tryExpandAtomicRMW(AtomicRMWInst *AI); |
bool expandAtomicRMWToLLSC(AtomicRMWInst *AI); |
- bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI); |
bool expandAtomicCmpXchg(AtomicCmpXchgInst *CI); |
bool isIdempotentRMW(AtomicRMWInst *AI); |
bool simplifyIdempotentRMW(AtomicRMWInst *AI); |
@@ -226,6 +226,17 @@ bool AtomicExpand::expandAtomicStore(StoreInst *SI) { |
return tryExpandAtomicRMW(AI); |
} |
+static void createCmpXchgInstFun(IRBuilder<> &Builder, Value *Addr, |
+ Value *Loaded, Value *NewVal, |
+ AtomicOrdering MemOpOrder, |
+ Value *&Success, Value *&NewLoaded) { |
+ Value* Pair = Builder.CreateAtomicCmpXchg( |
+ Addr, Loaded, NewVal, MemOpOrder, |
+ AtomicCmpXchgInst::getStrongestFailureOrdering(MemOpOrder)); |
+ Success = Builder.CreateExtractValue(Pair, 1, "success"); |
+ NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded"); |
+} |
+ |
bool AtomicExpand::tryExpandAtomicRMW(AtomicRMWInst *AI) { |
switch (TLI->shouldExpandAtomicRMWInIR(AI)) { |
case TargetLoweringBase::AtomicRMWExpansionKind::None: |
@@ -239,7 +250,7 @@ bool AtomicExpand::tryExpandAtomicRMW(AtomicRMWInst *AI) { |
return expandAtomicRMWToLLSC(AI); |
} |
case TargetLoweringBase::AtomicRMWExpansionKind::CmpXChg: { |
- return expandAtomicRMWToCmpXchg(AI); |
+ return expandAtomicRMWToCmpXchg(AI, createCmpXchgInstFun); |
} |
} |
llvm_unreachable("Unhandled case in tryExpandAtomicRMW"); |
@@ -337,70 +348,6 @@ bool AtomicExpand::expandAtomicRMWToLLSC(AtomicRMWInst *AI) { |
return true; |
} |
-bool AtomicExpand::expandAtomicRMWToCmpXchg(AtomicRMWInst *AI) { |
- AtomicOrdering MemOpOrder = |
- AI->getOrdering() == Unordered ? Monotonic : AI->getOrdering(); |
- Value *Addr = AI->getPointerOperand(); |
- BasicBlock *BB = AI->getParent(); |
- Function *F = BB->getParent(); |
- LLVMContext &Ctx = F->getContext(); |
- |
- // Given: atomicrmw some_op iN* %addr, iN %incr ordering |
- // |
- // The standard expansion we produce is: |
- // [...] |
- // %init_loaded = load atomic iN* %addr |
- // br label %loop |
- // loop: |
- // %loaded = phi iN [ %init_loaded, %entry ], [ %new_loaded, %loop ] |
- // %new = some_op iN %loaded, %incr |
- // %pair = cmpxchg iN* %addr, iN %loaded, iN %new |
- // %new_loaded = extractvalue { iN, i1 } %pair, 0 |
- // %success = extractvalue { iN, i1 } %pair, 1 |
- // br i1 %success, label %atomicrmw.end, label %loop |
- // atomicrmw.end: |
- // [...] |
- BasicBlock *ExitBB = BB->splitBasicBlock(AI, "atomicrmw.end"); |
- BasicBlock *LoopBB = BasicBlock::Create(Ctx, "atomicrmw.start", F, ExitBB); |
- |
- // This grabs the DebugLoc from AI. |
- IRBuilder<> Builder(AI); |
- |
- // The split call above "helpfully" added a branch at the end of BB (to the |
- // wrong place), but we want a load. It's easiest to just remove |
- // the branch entirely. |
- std::prev(BB->end())->eraseFromParent(); |
- Builder.SetInsertPoint(BB); |
- LoadInst *InitLoaded = Builder.CreateLoad(Addr); |
- // Atomics require at least natural alignment. |
- InitLoaded->setAlignment(AI->getType()->getPrimitiveSizeInBits()); |
- Builder.CreateBr(LoopBB); |
- |
- // Start the main loop block now that we've taken care of the preliminaries. |
- Builder.SetInsertPoint(LoopBB); |
- PHINode *Loaded = Builder.CreatePHI(AI->getType(), 2, "loaded"); |
- Loaded->addIncoming(InitLoaded, BB); |
- |
- Value *NewVal = |
- performAtomicOp(AI->getOperation(), Builder, Loaded, AI->getValOperand()); |
- |
- Value *Pair = Builder.CreateAtomicCmpXchg( |
- Addr, Loaded, NewVal, MemOpOrder, |
- AtomicCmpXchgInst::getStrongestFailureOrdering(MemOpOrder)); |
- Value *NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded"); |
- Loaded->addIncoming(NewLoaded, LoopBB); |
- |
- Value *Success = Builder.CreateExtractValue(Pair, 1, "success"); |
- Builder.CreateCondBr(Success, ExitBB, LoopBB); |
- |
- Builder.SetInsertPoint(ExitBB, ExitBB->begin()); |
- |
- AI->replaceAllUsesWith(NewLoaded); |
- AI->eraseFromParent(); |
- |
- return true; |
-} |
- |
bool AtomicExpand::expandAtomicCmpXchg(AtomicCmpXchgInst *CI) { |
AtomicOrdering SuccessOrder = CI->getSuccessOrdering(); |
AtomicOrdering FailureOrder = CI->getFailureOrdering(); |
@@ -562,3 +509,72 @@ bool AtomicExpand::simplifyIdempotentRMW(AtomicRMWInst* RMWI) { |
} |
return false; |
} |
+ |
+bool llvm::expandAtomicRMWToCmpXchg(AtomicRMWInst *AI, |
+ CreateCmpXchgInstFun CreateCmpXchg) { |
+ assert(AI); |
+ |
+ AtomicOrdering MemOpOrder = |
+ AI->getOrdering() == Unordered ? Monotonic : AI->getOrdering(); |
+ Value *Addr = AI->getPointerOperand(); |
+ BasicBlock *BB = AI->getParent(); |
+ Function *F = BB->getParent(); |
+ LLVMContext &Ctx = F->getContext(); |
+ |
+ // Given: atomicrmw some_op iN* %addr, iN %incr ordering |
+ // |
+ // The standard expansion we produce is: |
+ // [...] |
+ // %init_loaded = load atomic iN* %addr |
+ // br label %loop |
+ // loop: |
+ // %loaded = phi iN [ %init_loaded, %entry ], [ %new_loaded, %loop ] |
+ // %new = some_op iN %loaded, %incr |
+ // %pair = cmpxchg iN* %addr, iN %loaded, iN %new |
+ // %new_loaded = extractvalue { iN, i1 } %pair, 0 |
+ // %success = extractvalue { iN, i1 } %pair, 1 |
+ // br i1 %success, label %atomicrmw.end, label %loop |
+ // atomicrmw.end: |
+ // [...] |
+ BasicBlock *ExitBB = BB->splitBasicBlock(AI, "atomicrmw.end"); |
+ BasicBlock *LoopBB = BasicBlock::Create(Ctx, "atomicrmw.start", F, ExitBB); |
+ |
+ // This grabs the DebugLoc from AI. |
+ IRBuilder<> Builder(AI); |
+ |
+ // The split call above "helpfully" added a branch at the end of BB (to the |
+ // wrong place), but we want a load. It's easiest to just remove |
+ // the branch entirely. |
+ std::prev(BB->end())->eraseFromParent(); |
+ Builder.SetInsertPoint(BB); |
+ LoadInst *InitLoaded = Builder.CreateLoad(Addr); |
+ // Atomics require at least natural alignment. |
+ InitLoaded->setAlignment(AI->getType()->getPrimitiveSizeInBits()); |
+ Builder.CreateBr(LoopBB); |
+ |
+ // Start the main loop block now that we've taken care of the preliminaries. |
+ Builder.SetInsertPoint(LoopBB); |
+ PHINode *Loaded = Builder.CreatePHI(AI->getType(), 2, "loaded"); |
+ Loaded->addIncoming(InitLoaded, BB); |
+ |
+ Value *NewVal = |
+ performAtomicOp(AI->getOperation(), Builder, Loaded, AI->getValOperand()); |
+ |
+ Value *NewLoaded = nullptr; |
+ Value *Success = nullptr; |
+ |
+ CreateCmpXchg(Builder, Addr, Loaded, NewVal, MemOpOrder, |
+ Success, NewLoaded); |
+ assert(Success && NewLoaded); |
+ |
+ Loaded->addIncoming(NewLoaded, LoopBB); |
+ |
+ Builder.CreateCondBr(Success, ExitBB, LoopBB); |
+ |
+ Builder.SetInsertPoint(ExitBB, ExitBB->begin()); |
+ |
+ AI->replaceAllUsesWith(NewLoaded); |
+ AI->eraseFromParent(); |
+ |
+ return true; |
+} |