Reimplement the inner loop of DSE. It now uniformly uses getDependence(),

doesn't do its own local caching, and is slightly more aggressive about
free/store dse (see testcase).  This eliminates the last external client 
of MemDep::getDependenceFrom().

llvm-svn: 60619
This commit is contained in:
Chris Lattner 2008-12-06 00:53:22 +00:00
parent b0846b0f51
commit 57e91eaf61
2 changed files with 52 additions and 85 deletions

View File

@ -50,7 +50,7 @@ namespace {
bool runOnBasicBlock(BasicBlock &BB); bool runOnBasicBlock(BasicBlock &BB);
bool handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep); bool handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep);
bool handleEndBlock(BasicBlock &BB); bool handleEndBlock(BasicBlock &BB);
bool RemoveUndeadPointers(Value* pointer, uint64_t killPointerSize, bool RemoveUndeadPointers(Value* Ptr, uint64_t killPointerSize,
BasicBlock::iterator& BBI, BasicBlock::iterator& BBI,
SmallPtrSet<Value*, 64>& deadPointers); SmallPtrSet<Value*, 64>& deadPointers);
void DeleteDeadInstruction(Instruction *I, void DeleteDeadInstruction(Instruction *I,
@ -81,93 +81,60 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>(); MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
TargetData &TD = getAnalysis<TargetData>(); TargetData &TD = getAnalysis<TargetData>();
// Record the last-seen store to this pointer
DenseMap<Value*, StoreInst*> lastStore;
bool MadeChange = false; bool MadeChange = false;
// Do a top-down walk on the BB // Do a top-down walk on the BB
for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) { for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) {
Instruction *Inst = BBI++; Instruction *Inst = BBI++;
// If we find a store or a free... // If we find a store or a free, get it's memory dependence.
if (!isa<StoreInst>(Inst) && !isa<FreeInst>(Inst)) if (!isa<StoreInst>(Inst) && !isa<FreeInst>(Inst))
continue; continue;
Value* pointer = 0; MemDepResult InstDep = MD.getDependency(Inst);
if (StoreInst* S = dyn_cast<StoreInst>(Inst)) {
if (S->isVolatile())
continue;
pointer = S->getPointerOperand();
} else {
pointer = cast<FreeInst>(Inst)->getPointerOperand();
}
pointer = pointer->stripPointerCasts();
StoreInst *&last = lastStore[pointer];
// ... to a pointer that has been stored to before...
if (last) {
MemDepResult dep = MD.getDependency(Inst);
bool deletedStore = false;
// ... and no other memory dependencies are between them.... // Ignore non-local stores.
while (StoreInst *DepStore = dyn_cast_or_null<StoreInst>(dep.getInst())) { // FIXME: cross-block DSE would be fun. :)
if (DepStore != last || if (InstDep.isNonLocal()) continue;
TD.getTypeStoreSize(last->getOperand(0)->getType()) >
TD.getTypeStoreSize(Inst->getOperand(0)->getType())) { // Handle frees whose dependencies are non-trivial.
dep = MD.getDependencyFrom(Inst, DepStore, DepStore->getParent()); if (FreeInst *FI = dyn_cast<FreeInst>(Inst)) {
continue; MadeChange |= handleFreeWithNonTrivialDependency(FI, InstDep);
} continue;
}
StoreInst *SI = cast<StoreInst>(Inst);
// If not a definite must-alias dependency, ignore it.
if (!InstDep.isDef())
continue;
// If this is a store-store dependence, then the previous store is dead so
// long as this store is at least as big as it.
if (StoreInst *DepStore = dyn_cast<StoreInst>(InstDep.getInst()))
if (TD.getTypeStoreSize(DepStore->getOperand(0)->getType()) <=
TD.getTypeStoreSize(SI->getOperand(0)->getType())) {
// Delete the store and now-dead instructions that feed it. // Delete the store and now-dead instructions that feed it.
DeleteDeadInstruction(last); DeleteDeadInstruction(DepStore);
NumFastStores++; NumFastStores++;
deletedStore = true;
MadeChange = true; MadeChange = true;
break;
}
// If we deleted a store, reinvestigate this instruction.
if (deletedStore) {
if (BBI != BB.begin()) if (BBI != BB.begin())
--BBI; --BBI;
continue; continue;
} }
}
// Handle frees whose dependencies are non-trivial. // If we're storing the same value back to a pointer that we just
if (FreeInst* F = dyn_cast<FreeInst>(Inst)) { // loaded from, then the store can be removed.
MadeChange |= handleFreeWithNonTrivialDependency(F, MD.getDependency(F)); if (LoadInst *DepLoad = dyn_cast<LoadInst>(InstDep.getInst())) {
if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
// No known stores after the free. SI->getOperand(0) == DepLoad) {
last = 0; DeleteDeadInstruction(SI);
} else { if (BBI != BB.begin())
StoreInst* S = cast<StoreInst>(Inst); --BBI;
NumFastStores++;
// If we're storing the same value back to a pointer that we just MadeChange = true;
// loaded from, then the store can be removed; continue;
if (LoadInst* L = dyn_cast<LoadInst>(S->getOperand(0))) {
if (!S->isVolatile() && S->getParent() == L->getParent() &&
S->getPointerOperand() == L->getPointerOperand()) {
MemDepResult dep = MD.getDependency(S);
if (dep.isDef() && dep.getInst() == L) {
DeleteDeadInstruction(S);
if (BBI != BB.begin())
--BBI;
NumFastStores++;
MadeChange = true;
} else {
// Update our most-recent-store map.
last = S;
}
} else {
// Update our most-recent-store map.
last = S;
}
} else {
// Update our most-recent-store map.
last = S;
} }
} }
} }
@ -182,29 +149,22 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
/// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose /// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose
/// dependency is a store to a field of that structure. /// dependency is a store to a field of that structure.
bool DSE::handleFreeWithNonTrivialDependency(FreeInst* F, MemDepResult dep) { bool DSE::handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep) {
TargetData &TD = getAnalysis<TargetData>();
AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
StoreInst* dependency = dyn_cast_or_null<StoreInst>(dep.getInst()); StoreInst *Dependency = dyn_cast_or_null<StoreInst>(Dep.getInst());
if (!dependency) if (!Dependency || Dependency->isVolatile())
return false;
else if (dependency->isVolatile())
return false; return false;
Value* depPointer = dependency->getPointerOperand(); Value *DepPointer = Dependency->getPointerOperand()->getUnderlyingObject();
const Type* depType = dependency->getOperand(0)->getType();
unsigned depPointerSize = TD.getTypeStoreSize(depType);
// Check for aliasing // Check for aliasing.
AliasAnalysis::AliasResult A = AA.alias(F->getPointerOperand(), ~0U, if (AA.alias(F->getPointerOperand(), 1, DepPointer, 1) !=
depPointer, depPointerSize); AliasAnalysis::MustAlias)
if (A != AliasAnalysis::MustAlias)
return false; return false;
// DCE instructions only used to calculate that store // DCE instructions only used to calculate that store
DeleteDeadInstruction(dependency); DeleteDeadInstruction(Dependency);
NumFastStores++; NumFastStores++;
return true; return true;
} }

View File

@ -6,3 +6,10 @@ define void @test(i32* %Q, i32* %P) {
free i32* %P free i32* %P
ret void ret void
} }
define void @test2({i32, i32}* %P) {
%Q = getelementptr {i32, i32} *%P, i32 0, i32 1
store i32 4, i32* %Q
free {i32,i32}* %P
ret void
}