diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h index 8f4fca0effc..4428bb65f9f 100644 --- a/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -38,7 +38,8 @@ class MemoryDependenceAnalysis : public FunctionPass { Instruction* getCallSiteDependency(CallSite C, Instruction* start, bool local = true); - SmallPtrSet nonLocalHelper(Instruction* query, BasicBlock* block); + bool nonLocalHelper(Instruction* query, BasicBlock* block, + DenseMap& resp); public: static Instruction* NonLocal; @@ -67,7 +68,8 @@ class MemoryDependenceAnalysis : public FunctionPass { Instruction* getDependency(Instruction* query, Instruction* start = 0, BasicBlock* block = 0); - SmallPtrSet getNonLocalDependency(Instruction* query); + bool getNonLocalDependency(Instruction* query, + DenseMap& resp); /// removeInstruction - Remove an instruction from the dependence analysis, /// updating the dependence of instructions that previously depended on it. diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index 34c43484bfe..ae26c26dad0 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -26,8 +26,8 @@ using namespace llvm; char MemoryDependenceAnalysis::ID = 0; -Instruction* MemoryDependenceAnalysis::NonLocal = (Instruction*)0; -Instruction* MemoryDependenceAnalysis::None = (Instruction*)(~0 - 1); +Instruction* MemoryDependenceAnalysis::NonLocal = (Instruction*)-2; +Instruction* MemoryDependenceAnalysis::None = (Instruction*)-3; // Register this pass... static RegisterPass X("memdep", @@ -101,52 +101,49 @@ Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C, Instruc return NonLocal; } -SmallPtrSet MemoryDependenceAnalysis::nonLocalHelper(Instruction* query, - BasicBlock* block) { - SmallPtrSet ret; +bool MemoryDependenceAnalysis::nonLocalHelper(Instruction* query, + BasicBlock* block, + DenseMap& resp) { + if (resp.count(block)) + return resp[block] != None; - Instruction* localDep = getDependency(query, block->end(), block); + Instruction* localDep = getDependency(query, 0, block); if (localDep != NonLocal) { - ret.insert(localDep); - return ret; + resp.insert(std::make_pair(block, localDep)); + return true; } + bool inserted = false; for (pred_iterator PI = pred_begin(block), PE = pred_end(block); - PI != PE; ++PI) { - SmallPtrSet pred_deps = nonLocalHelper(query, *PI); - for (SmallPtrSet::iterator I = pred_deps.begin(), - E = pred_deps.end(); I != E; ++I) - ret.insert(*I); - } + PI != PE; ++PI) + inserted |= nonLocalHelper(query, *PI, resp); - if (ret.empty()) - ret.insert(None); + if (!inserted) + resp.insert(std::make_pair(block, None)); - return ret; + return inserted; } -SmallPtrSet MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query) { - SmallPtrSet ret; - +bool MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query, + DenseMap& resp) { Instruction* localDep = getDependency(query); if (localDep != NonLocal) { - ret.insert(localDep); - return ret; + resp.insert(std::make_pair(query->getParent(), localDep)); + return true; } + bool inserted = false; + BasicBlock* parent = query->getParent(); for (pred_iterator PI = pred_begin(parent), PE = pred_end(parent); PI != PE; ++PI) { - SmallPtrSet pred_deps = nonLocalHelper(query, *PI); - for (SmallPtrSet::iterator I = pred_deps.begin(), - E = pred_deps.end(); I != E; ++I) - ret.insert(*I); + inserted |= nonLocalHelper(query, *PI, resp); } - if (ret.empty()) - ret.insert(None); + if (!inserted) + resp.insert(std::make_pair(query->getParent(), None)); - return ret; + return inserted; } /// getDependency - Return the instruction on which a memory operation @@ -163,12 +160,14 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, // If we have a _confirmed_ cached entry, return it if (cachedResult.second) return cachedResult.first; - else if (cachedResult.first != NonLocal) + else if (cachedResult.first && cachedResult.first != NonLocal) // If we have an unconfirmed cached entry, we can start our search from there QI = cachedResult.first; if (start) QI = start; + else if (!start && block) + QI = block->end(); AliasAnalysis& AA = getAnalysis(); TargetData& TD = getAnalysis(); @@ -212,7 +211,7 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, if (StoreInst* S = dyn_cast(QI)) { // All volatile loads/stores depend on each other if (queryIsVolatile && S->isVolatile()) { - if (!start) { + if (!start || block) { depGraphLocal.insert(std::make_pair(query, std::make_pair(S, true))); reverseDep.insert(std::make_pair(S, query)); } @@ -225,7 +224,7 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, } else if (LoadInst* L = dyn_cast(QI)) { // All volatile loads/stores depend on each other if (queryIsVolatile && L->isVolatile()) { - if (!start) { + if (!start || block) { depGraphLocal.insert(std::make_pair(query, std::make_pair(L, true))); reverseDep.insert(std::make_pair(L, query)); } @@ -253,7 +252,7 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, // Call insts need special handling. Check is they can modify our pointer if (AA.getModRefInfo(CallSite::get(QI), dependee, dependeeSize) != AliasAnalysis::NoModRef) { - if (!start) { + if (!start || block) { depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true))); reverseDep.insert(std::make_pair(QI, query)); } @@ -270,7 +269,7 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, dependee, dependeeSize); if (R != AliasAnalysis::NoAlias) { - if (!start) { + if (!start || block) { depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true))); reverseDep.insert(std::make_pair(QI, query)); } @@ -281,7 +280,7 @@ Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query, } // If we found nothing, return the non-local flag - if (!start) { + if (!start || block) { depGraphLocal.insert(std::make_pair(query, std::make_pair(NonLocal, true))); reverseDep.insert(std::make_pair(NonLocal, query)); diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 555a9f352cc..3b8adef4aa7 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -15,6 +15,7 @@ #define DEBUG_TYPE "gvn" #include "llvm/Value.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/BasicBlock.h" #include "llvm/Instructions.h" #include "llvm/Function.h" #include "llvm/DerivedTypes.h" @@ -648,6 +649,10 @@ namespace { ValueNumberedSet& currAvail, DenseMap& lastSeenLoad, SmallVector& toErase); + bool processNonLocalLoad(LoadInst* L, SmallVector& toErase); + Value *performPHIConstruction(BasicBlock *BB, LoadInst* orig, + DenseMap &Phis); + void dump(DenseMap& d); }; char GVN::ID = 0; @@ -687,6 +692,88 @@ void GVN::val_insert(ValueNumberedSet& s, Value* v) { s.insert(v); } +void GVN::dump(DenseMap& d) { + printf("{\n"); + for (DenseMap::iterator I = d.begin(), + E = d.end(); I != E; ++I) { + if (I->second == MemoryDependenceAnalysis::None) + printf("None\n"); + else + I->second->dump(); + } + printf("}\n"); +} + + +Value *GVN::performPHIConstruction(BasicBlock *BB, LoadInst* orig, + DenseMap &Phis) { + DenseMap::iterator DI = Phis.find(BB); + if (DI != Phis.end()) + return DI->second; + + unsigned numPreds = std::distance(pred_begin(BB), pred_end(BB)); + + if (numPreds == 1) { + Phis[BB] = Phis[*pred_begin(BB)]; + return Phis[BB]; + } else { + PHINode *PN = new PHINode(orig->getType(), orig->getName()+".rle", BB->begin()); + PN->reserveOperandSpace(numPreds); + + // Fill in the incoming values for the block. + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + PN->addIncoming(performPHIConstruction(*PI, orig, Phis), *PI); + + bool all_same = PN->getNumIncomingValues() != 1; + Value* first = PN->getIncomingValue(0); + for (unsigned i = 1; i < PN->getNumIncomingValues(); ++i) + all_same &= (PN->getIncomingValue(i) == first); + + if (all_same) { + PN->eraseFromParent(); + return first; + } else { + return PN; + } + } +} + +bool GVN::processNonLocalLoad(LoadInst* L, SmallVector& toErase) { + MemoryDependenceAnalysis& MD = getAnalysis(); + + DenseMap deps; + bool ret = MD.getNonLocalDependency(L, deps); + if (!ret) + return false; + + DenseMap repl; + for (DenseMap::iterator I = deps.begin(), E = deps.end(); + I != E; ++I) + if (I->second == MemoryDependenceAnalysis::None) { + return false; + } else if (StoreInst* S = dyn_cast(I->second)) { + if (S->getPointerOperand() == L->getPointerOperand()) + repl.insert(std::make_pair(I->first, S->getOperand(0))); + else + return false; + } else if (LoadInst* LD = dyn_cast(I->second)) { + if (LD->getPointerOperand() == L->getPointerOperand()) + repl.insert(std::make_pair(I->first, LD)); + else + return false; + } else { + return false; + } + + Value* v = performPHIConstruction(L->getParent(), L, repl); + + MD.removeInstruction(L); + L->replaceAllUsesWith(v); + toErase.push_back(L); + + return true; +} + bool GVN::processLoad(LoadInst* L, DenseMap& lastLoad, SmallVector& toErase) { @@ -701,6 +788,9 @@ bool GVN::processLoad(LoadInst* L, // ... to a pointer that has been loaded from before... MemoryDependenceAnalysis& MD = getAnalysis(); Instruction* dep = MD.getDependency(L); + if (dep == MemoryDependenceAnalysis::NonLocal && + L->getParent() != &L->getParent()->getParent()->getEntryBlock()) + processNonLocalLoad(L, toErase); bool deletedLoad = false; while (dep != MemoryDependenceAnalysis::None && @@ -802,15 +892,17 @@ bool GVN::runOnFunction(Function &F) { for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) { - processInstruction(BI, currAvail, lastSeenLoad, toErase); + changed_function |= processInstruction(BI, currAvail, lastSeenLoad, toErase); + + NumGVNInstr += toErase.size(); + + for (SmallVector::iterator I = toErase.begin(), + E = toErase.end(); I != E; ++I) + (*I)->eraseFromParent(); + + toErase.clear(); } } - NumGVNInstr = toErase.size(); - - for (SmallVector::iterator I = toErase.begin(), - E = toErase.end(); I != E; ++I) - (*I)->eraseFromParent(); - return changed_function; } diff --git a/test/Transforms/GVN/dominated.ll b/test/Transforms/GVN/dominated.ll new file mode 100644 index 00000000000..4a9e97517e4 --- /dev/null +++ b/test/Transforms/GVN/dominated.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s | opt -gvn | llvm-dis | not grep DEAD + +define i32 @main(i32** %p) { +block1: + %z = load i32** %p + br i1 true, label %block2, label %block3 + +block2: + %a = load i32** %p + br label %block4 + +block3: + %b = load i32** %p + br label %block4 + +block4: + %DEAD = load i32** %p + %c = load i32* %DEAD + ret i32 %c +} \ No newline at end of file diff --git a/test/Transforms/GVN/nonlocal.ll b/test/Transforms/GVN/nonlocal.ll new file mode 100644 index 00000000000..7e5ef910b54 --- /dev/null +++ b/test/Transforms/GVN/nonlocal.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | opt -gvn | llvm-dis | not grep {DEAD =} + +define i32 @main(i32** %p) { +block1: + br i1 true, label %block2, label %block3 + +block2: + %a = load i32** %p + br label %block4 + +block3: + %b = load i32** %p + br label %block4 + +block4: + %DEAD = load i32** %p + %c = load i32* %DEAD + ret i32 %c +} \ No newline at end of file diff --git a/test/Transforms/GVN/semidominated.ll b/test/Transforms/GVN/semidominated.ll new file mode 100644 index 00000000000..89eac46d9c4 --- /dev/null +++ b/test/Transforms/GVN/semidominated.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | opt -gvn | llvm-dis | not grep {DEAD =} + +define i32 @main(i32* %p) { +block1: + %z = load i32* %p + br i1 true, label %block2, label %block3 + +block2: + br label %block4 + +block3: + %b = bitcast i32 0 to i32 + store i32 %b, i32* %p + br label %block4 + +block4: + %DEAD = load i32* %p + ret i32 %DEAD +} \ No newline at end of file