aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOwen Anderson <resistor@mac.com>2008-10-10 08:36:25 +0000
committerOwen Anderson <resistor@mac.com>2008-10-10 08:36:25 +0000
commit8f28c78e952b3943f4bb714254e802f126505e7a (patch)
treed9e0161c2d3d08d01c5a4832bb687c65f5260ead
parent1c341c8462a208ccc5ba4b4e030cdc989ce38818 (diff)
downloadexternal_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.h59
-rw-r--r--lib/Analysis/EscapeAnalysis.cpp131
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