diff options
author | Owen Anderson <resistor@mac.com> | 2008-10-10 08:36:25 +0000 |
---|---|---|
committer | Owen Anderson <resistor@mac.com> | 2008-10-10 08:36:25 +0000 |
commit | 8f28c78e952b3943f4bb714254e802f126505e7a (patch) | |
tree | d9e0161c2d3d08d01c5a4832bb687c65f5260ead | |
parent | 1c341c8462a208ccc5ba4b4e030cdc989ce38818 (diff) | |
download | external_llvm-8f28c78e952b3943f4bb714254e802f126505e7a.zip external_llvm-8f28c78e952b3943f4bb714254e802f126505e7a.tar.gz external_llvm-8f28c78e952b3943f4bb714254e802f126505e7a.tar.bz2 |
Add a basic intra-procedural escape analysis. This hasn't be extensively tested yet, but feedback is welcome.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57342 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Analysis/EscapeAnalysis.h | 59 | ||||
-rw-r--r-- | lib/Analysis/EscapeAnalysis.cpp | 131 |
2 files changed, 190 insertions, 0 deletions
diff --git a/include/llvm/Analysis/EscapeAnalysis.h b/include/llvm/Analysis/EscapeAnalysis.h new file mode 100644 index 0000000..085028d --- /dev/null +++ b/include/llvm/Analysis/EscapeAnalysis.h @@ -0,0 +1,59 @@ +//===------------- EscapeAnalysis.h - Pointer escape analysis -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for the pointer escape analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LOOPVR_H +#define LLVM_ANALYSIS_LOOPVR_H + +#include "llvm/Pass.h" +#include "llvm/Instructions.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Target/TargetData.h" +#include <set> +#include <vector> + +namespace llvm { + +/// EscapeAnalysis - This class determines whether an allocation (a MallocInst +/// or an AllocaInst) can escape from the current function. It performs some +/// precomputation, with the rest of the work happening on-demand. +class EscapeAnalysis : public FunctionPass { +private: + std::set<Instruction*> EscapePoints; + +public: + static char ID; // Class identification, replacement for typeinfo + + EscapeAnalysis() : FunctionPass(intptr_t(&ID)) {} + + bool runOnFunction(Function &F); + + void releaseMemory() { + EscapePoints.clear(); + } + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequiredTransitive<TargetData>(); + AU.addRequiredTransitive<AliasAnalysis>(); + AU.setPreservesAll(); + } + + //===--------------------------------------------------------------------- + // Client API + + /// escapes - returns true if the AllocationInst can escape. + bool escapes(AllocationInst* A); +}; + +} // end llvm namespace + +#endif diff --git a/lib/Analysis/EscapeAnalysis.cpp b/lib/Analysis/EscapeAnalysis.cpp new file mode 100644 index 0000000..07f4761 --- /dev/null +++ b/lib/Analysis/EscapeAnalysis.cpp @@ -0,0 +1,131 @@ +//===------------- EscapeAnalysis.h - Pointer escape analysis -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the implementation of the pointer escape analysis. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "escape-analysis" +#include "llvm/Analysis/EscapeAnalysis.h" +#include "llvm/Module.h" +#include "llvm/Support/InstIterator.h" +#include "llvm/ADT/SmallPtrSet.h" +using namespace llvm; + +char EscapeAnalysis::ID = 0; +static RegisterPass<EscapeAnalysis> X("escape-analysis", + "Pointer Escape Analysis", true, true); + + +/// runOnFunction - Precomputation for escape analysis. This collects all know +/// "escape points" in the def-use graph of the function. These are +/// instructions which allow their inputs to escape from the current function. +bool EscapeAnalysis::runOnFunction(Function& F) { + EscapePoints.clear(); + + TargetData& TD = getAnalysis<TargetData>(); + AliasAnalysis& AA = getAnalysis<AliasAnalysis>(); + Module* M = F.getParent(); + + // Walk through all instructions in the function, identifying those that + // may allow their inputs to escape. + for(inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE; ++II) { + Instruction* I = &*II; + + // The most obvious case is stores. Any store that may write to global + // memory or to a function argument potentially allows its input to escape. + if (StoreInst* S = dyn_cast<StoreInst>(I)) { + const Type* StoreType = S->getOperand(0)->getType(); + unsigned StoreSize = TD.getTypeStoreSize(StoreType); + Value* Pointer = S->getPointerOperand(); + + bool inserted = false; + for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); + AI != AE; ++AI) { + AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, AI, ~0UL); + if (R != AliasAnalysis::NoAlias) { + EscapePoints.insert(S); + inserted = true; + break; + } + } + + if (inserted) + continue; + + for (Module::global_iterator GI = M->global_begin(), GE = M->global_end(); + GI != GE; ++GI) { + AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, GI, ~0UL); + if (R != AliasAnalysis::NoAlias) { + EscapePoints.insert(S); + break; + } + } + + // Calls and invokes potentially allow their parameters to escape. + // FIXME: This can and should be refined. Intrinsics have known escape + // behavior, and alias analysis may be able to tell us more about callees. + } else if (isa<CallInst>(I) || isa<InvokeInst>(I)) { + EscapePoints.insert(I); + + // Returns allow the return value to escape. This is mostly important + // for malloc to alloca promotion. + } else if (isa<ReturnInst>(I)) { + EscapePoints.insert(I); + } + + // FIXME: Are there any other possible escape points? + } + + return false; +} + +/// escapes - Determines whether the passed allocation can escape from the +/// current function. It does this by using a simple worklist algorithm to +/// search for a path in the def-use graph from the allocation to an +/// escape point. +/// FIXME: Once we've discovered a path, it would be a good idea to memoize it, +/// and all of its subpaths, to amortize the cost of future queries. +bool EscapeAnalysis::escapes(AllocationInst* A) { + std::vector<Value*> worklist; + worklist.push_back(A); + + SmallPtrSet<Value*, 8> visited; + while (!worklist.empty()) { + Value* curr = worklist.back(); + worklist.pop_back(); + + visited.insert(curr); + + if (Instruction* CurrInst = dyn_cast<Instruction>(curr)) + if (EscapePoints.count(CurrInst)) + return true; + + for (Instruction::use_iterator UI = curr->use_begin(), UE = curr->use_end(); + UI != UE; ++UI) + if (Instruction* U = dyn_cast<Instruction>(UI)) + if (!visited.count(U)) + if (StoreInst* S = dyn_cast<StoreInst>(U)) { + // We know this must be an instruction, because constant gep's would + // have been found to alias a global, so stores to them would have + // been in EscapePoints. + worklist.push_back(cast<Instruction>(S->getPointerOperand())); + } else if (isa<BranchInst>(U) || isa<SwitchInst>(U)) { + // Because branches on the pointer value can hide data dependencies, + // we need to track values that were generated by branching on the + // pointer (or some derived value). To do that, we push the block, + // whose uses will be the PHINodes that generate information based + // one it. + worklist.push_back(U->getParent()); + } else + worklist.push_back(U); + } + + return false; +}
\ No newline at end of file |