forked from OSchip/llvm-project
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:
parent
b0846b0f51
commit
57e91eaf61
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue