#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Dominators.h"
+#include "llvm/Analysis/MallocFreeHelper.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
-#include "llvm/Support/Compiler.h"
using namespace llvm;
STATISTIC(NumFastStores, "Number of stores deleted");
STATISTIC(NumFastOther , "Number of other instrs removed");
namespace {
- struct VISIBILITY_HIDDEN DSE : public FunctionPass {
+ struct DSE : public FunctionPass {
+ TargetData *TD;
+
static char ID; // Pass identification, replacement for typeid
DSE() : FunctionPass(&ID) {}
}
bool runOnBasicBlock(BasicBlock &BB);
- bool handleFreeWithNonTrivialDependency(FreeInst *F, MemDepResult Dep);
+ bool handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep);
bool handleEndBlock(BasicBlock &BB);
- bool RemoveUndeadPointers(Value* pointer, uint64_t killPointerSize,
+ bool RemoveUndeadPointers(Value* Ptr, uint64_t killPointerSize,
BasicBlock::iterator& BBI,
SmallPtrSet<Value*, 64>& deadPointers);
void DeleteDeadInstruction(Instruction *I,
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<DominatorTree>();
- AU.addRequired<TargetData>();
AU.addRequired<AliasAnalysis>();
AU.addRequired<MemoryDependenceAnalysis>();
AU.addPreserved<DominatorTree>();
bool DSE::runOnBasicBlock(BasicBlock &BB) {
MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
- TargetData &TD = getAnalysis<TargetData>();
+ TD = getAnalysisIfAvailable<TargetData>();
- // Record the last-seen store to this pointer
- DenseMap<Value*, StoreInst*> lastStore;
-
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; ) {
Instruction *Inst = BBI++;
- // If we find a store or a free...
- if (!isa<StoreInst>(Inst) && !isa<FreeInst>(Inst))
+ // If we find a store or a free, get its memory dependence.
+ if (!isa<StoreInst>(Inst) && !isFreeCall(Inst))
continue;
-
- Value* pointer = 0;
- if (StoreInst* S = dyn_cast<StoreInst>(Inst)) {
- if (S->isVolatile())
+
+ // Don't molest volatile stores or do queries that will return "clobber".
+ if (StoreInst *SI = dyn_cast<StoreInst>(Inst))
+ if (SI->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;
+ MemDepResult InstDep = MD.getDependency(Inst);
- // ... and no other memory dependencies are between them....
- while (StoreInst *DepStore = dyn_cast_or_null<StoreInst>(dep.getInst())) {
- if (DepStore != last ||
- TD.getTypeStoreSize(last->getOperand(0)->getType()) >
- TD.getTypeStoreSize(Inst->getOperand(0)->getType())) {
- dep = MD.getDependency(Inst, DepStore);
- continue;
- }
-
+ // Ignore non-local stores.
+ // FIXME: cross-block DSE would be fun. :)
+ if (InstDep.isNonLocal()) continue;
+
+ // Handle frees whose dependencies are non-trivial.
+ if (isFreeCall(Inst)) {
+ MadeChange |= handleFreeWithNonTrivialDependency(Inst, 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 &&
+ TD->getTypeStoreSize(DepStore->getOperand(0)->getType()) <=
+ TD->getTypeStoreSize(SI->getOperand(0)->getType())) {
// Delete the store and now-dead instructions that feed it.
- DeleteDeadInstruction(last);
+ DeleteDeadInstruction(DepStore);
NumFastStores++;
- deletedStore = true;
MadeChange = true;
- break;
- }
-
- // If we deleted a store, reinvestigate this instruction.
- if (deletedStore) {
- if (!isa<TerminatorInst>(BB.begin()))
+
+ // DeleteDeadInstruction can delete the current instruction in loop
+ // cases, reset BBI.
+ BBI = Inst;
+ if (BBI != BB.begin())
--BBI;
continue;
}
- }
- // Handle frees whose dependencies are non-trivial.
- if (FreeInst* F = dyn_cast<FreeInst>(Inst)) {
- MadeChange |= handleFreeWithNonTrivialDependency(F, MD.getDependency(F));
-
- // No known stores after the free.
- last = 0;
- } else {
- StoreInst* S = cast<StoreInst>(Inst);
-
- // If we're storing the same value back to a pointer that we just
- // loaded from, then the store can be removed;
- if (LoadInst* L = dyn_cast<LoadInst>(S->getOperand(0))) {
- // FIXME: Don't do dep query if Parents don't match and other stuff!
- MemDepResult dep = MD.getDependency(S);
- DominatorTree& DT = getAnalysis<DominatorTree>();
+ // If we're storing the same value back to a pointer that we just
+ // loaded from, then the store can be removed.
+ if (LoadInst *DepLoad = dyn_cast<LoadInst>(InstDep.getInst())) {
+ if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
+ SI->getOperand(0) == DepLoad) {
+ // DeleteDeadInstruction can delete the current instruction. Save BBI
+ // in case we need it.
+ WeakVH NextInst(BBI);
- if (!S->isVolatile() && S->getParent() == L->getParent() &&
- S->getPointerOperand() == L->getPointerOperand() &&
- (!dep.isNormal() || DT.dominates(dep.getInst(), L))) {
-
- DeleteDeadInstruction(S);
- if (!isa<TerminatorInst>(BB.begin()))
- --BBI;
- NumFastStores++;
- MadeChange = true;
- } else
- // Update our most-recent-store map.
- last = S;
- } else
- // Update our most-recent-store map.
- last = S;
+ 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;
+ }
}
}
/// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose
/// dependency is a store to a field of that structure.
-bool DSE::handleFreeWithNonTrivialDependency(FreeInst* F, MemDepResult dep) {
- TargetData &TD = getAnalysis<TargetData>();
+bool DSE::handleFreeWithNonTrivialDependency(Instruction *F, MemDepResult Dep) {
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
- StoreInst* dependency = dyn_cast_or_null<StoreInst>(dep.getInst());
- if (!dependency)
- return false;
- else if (dependency->isVolatile())
+ StoreInst *Dependency = dyn_cast_or_null<StoreInst>(Dep.getInst());
+ if (!Dependency || Dependency->isVolatile())
return false;
- Value* depPointer = dependency->getPointerOperand();
- const Type* depType = dependency->getOperand(0)->getType();
- unsigned depPointerSize = TD.getTypeStoreSize(depType);
+ Value *DepPointer = Dependency->getPointerOperand()->getUnderlyingObject();
- // Check for aliasing
- AliasAnalysis::AliasResult A = AA.alias(F->getPointerOperand(), ~0U,
- depPointer, depPointerSize);
-
- if (A != AliasAnalysis::MustAlias)
+ // Check for aliasing.
+ if (AA.alias(F->getOperand(1), 1, DepPointer, 1) !=
+ AliasAnalysis::MustAlias)
return false;
// DCE instructions only used to calculate that store
- DeleteDeadInstruction(dependency);
+ DeleteDeadInstruction(Dependency);
NumFastStores++;
return true;
}
/// store i32 1, i32* %A
/// ret void
bool DSE::handleEndBlock(BasicBlock &BB) {
- TargetData &TD = getAnalysis<TargetData>();
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
bool MadeChange = false;
// Get size information for the alloca
unsigned pointerSize = ~0U;
- if (AllocaInst* A = dyn_cast<AllocaInst>(*I)) {
- if (ConstantInt* C = dyn_cast<ConstantInt>(A->getArraySize()))
- pointerSize = C->getZExtValue() *
- TD.getABITypeSize(A->getAllocatedType());
- } else {
- const PointerType* PT = cast<PointerType>(
- cast<Argument>(*I)->getType());
- pointerSize = TD.getABITypeSize(PT->getElementType());
+ if (TD) {
+ if (AllocaInst* A = dyn_cast<AllocaInst>(*I)) {
+ if (ConstantInt* C = dyn_cast<ConstantInt>(A->getArraySize()))
+ pointerSize = C->getZExtValue() *
+ TD->getTypeAllocSize(A->getAllocatedType());
+ } else {
+ const PointerType* PT = cast<PointerType>(
+ cast<Argument>(*I)->getType());
+ pointerSize = TD->getTypeAllocSize(PT->getElementType());
+ }
}
// See if the call site touches it
bool DSE::RemoveUndeadPointers(Value* killPointer, uint64_t killPointerSize,
BasicBlock::iterator &BBI,
SmallPtrSet<Value*, 64>& deadPointers) {
- TargetData &TD = getAnalysis<TargetData>();
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
// If the kill pointer can be easily reduced to an alloca,
E = deadPointers.end(); I != E; ++I) {
// Get size information for the alloca.
unsigned pointerSize = ~0U;
- if (AllocaInst* A = dyn_cast<AllocaInst>(*I)) {
- if (ConstantInt* C = dyn_cast<ConstantInt>(A->getArraySize()))
- pointerSize = C->getZExtValue() *
- TD.getABITypeSize(A->getAllocatedType());
- } else {
- const PointerType* PT = cast<PointerType>(cast<Argument>(*I)->getType());
- pointerSize = TD.getABITypeSize(PT->getElementType());
+ if (TD) {
+ if (AllocaInst* A = dyn_cast<AllocaInst>(*I)) {
+ if (ConstantInt* C = dyn_cast<ConstantInt>(A->getArraySize()))
+ pointerSize = C->getZExtValue() *
+ TD->getTypeAllocSize(A->getAllocatedType());
+ } else {
+ const PointerType* PT = cast<PointerType>(cast<Argument>(*I)->getType());
+ pointerSize = TD->getTypeAllocSize(PT->getElementType());
+ }
}
// See if this pointer could alias it