diff options
author | Owen Anderson <resistor@mac.com> | 2009-10-28 07:05:35 +0000 |
---|---|---|
committer | Owen Anderson <resistor@mac.com> | 2009-10-28 07:05:35 +0000 |
commit | b62f792e78df12a43029352eb4c7cde9d456c67e (patch) | |
tree | e2b4de6c1ad567c76b6038fe67a424b787a509f1 | |
parent | 40cc524edee857eab238338200d2cc80f840f52f (diff) |
Treat lifetime begin/end markers as allocations/frees respectively for the
purposes for GVN/DSE.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85383 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Analysis/MemoryDependenceAnalysis.cpp | 18 | ||||
-rw-r--r-- | lib/Transforms/Scalar/DeadStoreElimination.cpp | 20 | ||||
-rw-r--r-- | lib/Transforms/Scalar/GVN.cpp | 21 | ||||
-rw-r--r-- | test/Transforms/DeadStoreElimination/lifetime-simple.ll | 18 | ||||
-rw-r--r-- | test/Transforms/GVN/lifetime-simple.ll | 20 |
5 files changed, 94 insertions, 3 deletions
diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index be5f9c1ae0..0ec0e74233 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -185,10 +185,9 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, if (invariantTag == Inst) { invariantTag = 0; continue; - - // If we pass an invariant-end marker, then we've just entered an invariant - // region and can start ignoring dependencies. } else if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(Inst)) { + // If we pass an invariant-end marker, then we've just entered an + // invariant region and can start ignoring dependencies. if (II->getIntrinsicID() == Intrinsic::invariant_end) { uint64_t invariantSize = ~0ULL; if (ConstantInt* CI = dyn_cast<ConstantInt>(II->getOperand(2))) @@ -200,6 +199,19 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, invariantTag = II->getOperand(1); continue; } + + // If we reach a lifetime begin or end marker, then the query ends here + // because the value is undefined. + } else if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) { + uint64_t invariantSize = ~0ULL; + if (ConstantInt* CI = dyn_cast<ConstantInt>(II->getOperand(1))) + invariantSize = CI->getZExtValue(); + + AliasAnalysis::AliasResult R = + AA->alias(II->getOperand(2), invariantSize, MemPtr, MemSize); + if (R == AliasAnalysis::MustAlias) + return MemDepResult::getDef(II); } } diff --git a/lib/Transforms/Scalar/DeadStoreElimination.cpp b/lib/Transforms/Scalar/DeadStoreElimination.cpp index e3f43372ec..60b12fd867 100644 --- a/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -154,6 +154,26 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) { continue; } } + + // If this is a lifetime end marker, we can throw away the store. + if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(InstDep.getInst())) { + if (II->getIntrinsicID() == Intrinsic::lifetime_end) { + // Delete the store and now-dead instructions that feed it. + // DeleteDeadInstruction can delete the current instruction. Save BBI + // in case we need it. + WeakVH NextInst(BBI); + + DeleteDeadInstruction(SI); + + if (NextInst == 0) // Next instruction deleted. + BBI = BB.begin(); + else if (BBI != BB.begin()) // Revisit this instruction if possible. + --BBI; + NumFastStores++; + MadeChange = true; + continue; + } + } } // If this block ends in a return, unwind, or unreachable, all allocas are diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 32d027aa36..dd8859b5e8 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -1248,6 +1248,15 @@ bool GVN::processNonLocalLoad(LoadInst *LI, UndefValue::get(LI->getType()))); continue; } + + // Loading immediately after lifetime begin or end -> undef. + if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(DepInst)) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) { + ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB, + UndefValue::get(LI->getType()))); + } + } if (StoreInst *S = dyn_cast<StoreInst>(DepInst)) { // Reject loads and stores that are to the same address but are of @@ -1591,6 +1600,18 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) { NumGVNLoad++; return true; } + + // If this load occurs either right after a lifetime begin or a lifetime end, + // then the loaded value is undefined. + if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(DepInst)) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) { + L->replaceAllUsesWith(UndefValue::get(L->getType())); + toErase.push_back(L); + NumGVNLoad++; + return true; + } + } return false; } diff --git a/test/Transforms/DeadStoreElimination/lifetime-simple.ll b/test/Transforms/DeadStoreElimination/lifetime-simple.ll new file mode 100644 index 0000000000..430e700635 --- /dev/null +++ b/test/Transforms/DeadStoreElimination/lifetime-simple.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -dse -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin7" + +define i8 @test2(i8* %P) nounwind { +; CHECK: @test2 +; CHECK-NOT: store i8 1 +; CHECK: ret i8 0 +entry: + call void @llvm.lifetime.start(i64 32, i8* %P) + call void @llvm.lifetime.end(i64 32, i8* %P) + store i8 1, i8* %P + ret i8 0 +} + +declare {}* @llvm.lifetime.start(i64 %S, i8* nocapture %P) readonly +declare void @llvm.lifetime.end(i64 %S, i8* nocapture %P)
\ No newline at end of file diff --git a/test/Transforms/GVN/lifetime-simple.ll b/test/Transforms/GVN/lifetime-simple.ll new file mode 100644 index 0000000000..00a0c2907c --- /dev/null +++ b/test/Transforms/GVN/lifetime-simple.ll @@ -0,0 +1,20 @@ +; RUN: opt < %s -gvn -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin7" + +define i8 @test(i8* %P) nounwind { +; CHECK: @test +; CHECK-NOT: load +; CHECK: ret i8 undef +entry: + call void @llvm.lifetime.start(i64 32, i8* %P) + %0 = load i8* %P + store i8 1, i8* %P + call void @llvm.lifetime.end(i64 32, i8* %P) + %1 = load i8* %P + ret i8 %1 +} + +declare {}* @llvm.lifetime.start(i64 %S, i8* nocapture %P) readonly +declare void @llvm.lifetime.end(i64 %S, i8* nocapture %P)
\ No newline at end of file |