summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2014-03-10 21:35:33 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2014-03-10 21:35:33 +0000
commit938bc1ea843e6e5d64d4d4c33df5ccf40d677344 (patch)
tree820adfbbaa9ea06e26434b68f537e6b391bf5023 /clang/lib/CodeGen
parent02a0dd8dd1ed2c3ff532618290e0040ad70dbbf1 (diff)
downloadbcm5719-llvm-938bc1ea843e6e5d64d4d4c33df5ccf40d677344.tar.gz
bcm5719-llvm-938bc1ea843e6e5d64d4d4c33df5ccf40d677344.zip
IRGen: __c11/__atomic compare-and-exchange should respect the standard
Summary: 'Expected' should only be modified if the operation fails. This fixes PR18899. Reviewers: chandlerc, rsmith, rjmccall CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D2922 llvm-svn: 203493
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp46
1 files changed, 36 insertions, 10 deletions
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index cb92f9ad226..88655774044 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -201,16 +201,42 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
case AtomicExpr::AO__atomic_compare_exchange_n: {
// Note that cmpxchg only supports specifying one ordering and
// doesn't support weak cmpxchg, at least at the moment.
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
- LoadVal2->setAlignment(Align);
- llvm::AtomicCmpXchgInst *CXI =
- CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
- CXI->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
- StoreVal1->setAlignment(Align);
- llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
+
+ llvm::LoadInst *Expected = CGF.Builder.CreateLoad(Val1);
+ Expected->setAlignment(Align);
+ llvm::LoadInst *Desired = CGF.Builder.CreateLoad(Val2);
+ Desired->setAlignment(Align);
+ llvm::AtomicCmpXchgInst *Old =
+ CGF.Builder.CreateAtomicCmpXchg(Ptr, Expected, Desired, Order);
+ Old->setVolatile(E->isVolatile());
+
+ // Cmp holds the result of the compare-exchange operation: true on success,
+ // false on failure.
+ llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(Old, Expected);
+
+ // This basic block is used to hold the store instruction if the operation
+ // failed.
+ llvm::BasicBlock *StoreExpectedBB =
+ CGF.createBasicBlock("cmpxchg.store_expected", CGF.CurFn);
+
+ // This basic block is the exit point of the operation, we should end up
+ // here regardless of whether or not the operation succeeded.
+ llvm::BasicBlock *ContinueBB =
+ CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
+
+ // Update Expected if Expected isn't equal to Old, otherwise branch to the
+ // exit point.
+ CGF.Builder.CreateCondBr(Cmp, ContinueBB, StoreExpectedBB);
+
+ CGF.Builder.SetInsertPoint(StoreExpectedBB);
+ // Update the memory at Expected with Old's value.
+ llvm::StoreInst *StoreExpected = CGF.Builder.CreateStore(Old, Val1);
+ StoreExpected->setAlignment(Align);
+ // Finally, branch to the exit point.
+ CGF.Builder.CreateBr(ContinueBB);
+
+ CGF.Builder.SetInsertPoint(ContinueBB);
+ // Update the memory at Dest with Cmp's value.
CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
return;
}
OpenPOWER on IntegriCloud