diff options
author | David Majnemer <david.majnemer@gmail.com> | 2016-05-26 19:24:24 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2016-05-26 19:24:24 +0000 |
commit | d99068d26db69f2cdaba0ad02a6bd92512f04b60 (patch) | |
tree | ef3d5a5ff2988cdfe75cbc90f0cb34972aea0a9a /llvm | |
parent | 23c12ca9226c297771ba5fefa0f047e9e2450d7b (diff) | |
download | bcm5719-llvm-d99068d26db69f2cdaba0ad02a6bd92512f04b60.tar.gz bcm5719-llvm-d99068d26db69f2cdaba0ad02a6bd92512f04b60.zip |
[MemCpyOpt] Don't perform callslot optimization across may-throw calls
An exception could prevent a store from occurring but MemCpyOpt's
callslot optimization would fire anyway, causing the store to occur.
This fixes PR27849.
llvm-svn: 270892
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 14 | ||||
-rw-r--r-- | llvm/test/Transforms/MemCpyOpt/callslot_throw.ll | 34 | ||||
-rw-r--r-- | llvm/test/Transforms/MemCpyOpt/loadstore-sret.ll | 2 |
3 files changed, 48 insertions, 2 deletions
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp index 8976742be40..3c421d2365d 100644 --- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -496,7 +496,7 @@ static unsigned findCommonAlignment(const DataLayout &DL, const StoreInst *SI, // This method try to lift a store instruction before position P. // It will lift the store and its argument + that anything that -// lay alias with these. +// may alias with these. // The method returns true if it was successful. static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P) { // If the store alias this position, early bail out. @@ -675,6 +675,8 @@ bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { if (C) { // Check that nothing touches the dest of the "copy" between // the call and the store. + Value *CpyDest = SI->getPointerOperand()->stripPointerCasts(); + bool CpyDestIsLocal = isa<AllocaInst>(CpyDest); AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); MemoryLocation StoreLoc = MemoryLocation::get(SI); for (BasicBlock::iterator I = --SI->getIterator(), E = C->getIterator(); @@ -683,6 +685,12 @@ bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { C = nullptr; break; } + // The store to dest may never happen if an exception can be thrown + // between the load and the store. + if (I->mayThrow() && !CpyDestIsLocal) { + C = nullptr; + break; + } } } @@ -815,6 +823,10 @@ bool MemCpyOpt::performCallSlotOptzn(Instruction *cpy, if (destSize < srcSize) return false; } else if (Argument *A = dyn_cast<Argument>(cpyDest)) { + // The store to dest may never happen if the call can throw. + if (C->mayThrow()) + return false; + if (A->getDereferenceableBytes() < srcSize) { // If the destination is an sret parameter then only accesses that are // outside of the returned struct type can trap. diff --git a/llvm/test/Transforms/MemCpyOpt/callslot_throw.ll b/llvm/test/Transforms/MemCpyOpt/callslot_throw.ll new file mode 100644 index 00000000000..1aa4c92efc7 --- /dev/null +++ b/llvm/test/Transforms/MemCpyOpt/callslot_throw.ll @@ -0,0 +1,34 @@ +; RUN: opt -S -memcpyopt < %s | FileCheck %s +declare void @may_throw(i32* nocapture %x) + +; CHECK-LABEL: define void @test1( +define void @test1(i32* nocapture noalias dereferenceable(4) %x) { +entry: + %t = alloca i32, align 4 + call void @may_throw(i32* nonnull %t) + %load = load i32, i32* %t, align 4 + store i32 %load, i32* %x, align 4 +; CHECK: %[[t:.*]] = alloca i32, align 4 +; CHECK-NEXT: call void @may_throw(i32* {{.*}} %[[t]]) +; CHECK-NEXT: %[[load:.*]] = load i32, i32* %[[t]], align 4 +; CHECK-NEXT: store i32 %[[load]], i32* %x, align 4 + ret void +} + +declare void @always_throws() + +; CHECK-LABEL: define void @test2( +define void @test2(i32* nocapture noalias dereferenceable(4) %x) { +entry: + %t = alloca i32, align 4 + call void @may_throw(i32* nonnull %t) nounwind + %load = load i32, i32* %t, align 4 + call void @always_throws() + store i32 %load, i32* %x, align 4 +; CHECK: %[[t:.*]] = alloca i32, align 4 +; CHECK-NEXT: call void @may_throw(i32* {{.*}} %[[t]]) +; CHECK-NEXT: %[[load:.*]] = load i32, i32* %[[t]], align 4 +; CHECK-NEXT: call void @always_throws() +; CHECK-NEXT: store i32 %[[load]], i32* %x, align 4 + ret void +} diff --git a/llvm/test/Transforms/MemCpyOpt/loadstore-sret.ll b/llvm/test/Transforms/MemCpyOpt/loadstore-sret.ll index 55cbe59651f..4c6136cf625 100644 --- a/llvm/test/Transforms/MemCpyOpt/loadstore-sret.ll +++ b/llvm/test/Transforms/MemCpyOpt/loadstore-sret.ll @@ -22,4 +22,4 @@ _ZNSt8auto_ptrIiED1Ev.exit: ret void } -declare void @_Z3barv(%"class.std::auto_ptr"* nocapture sret) +declare void @_Z3barv(%"class.std::auto_ptr"* nocapture sret) nounwind |