| //===------EscapeAnalysis.cpp - Simple LLVM escape analysis ---------------===// |
| // |
| // The Micro Virtual Machine |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| #include "llvm/Constants.h" |
| #include "llvm/Pass.h" |
| #include "llvm/Function.h" |
| #include "llvm/Instructions.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Debug.h" |
| |
| #include <map> |
| |
| #include "mvm/GC/GC.h" |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| class VISIBILITY_HIDDEN EscapeAnalysis : public FunctionPass { |
| public: |
| static char ID; |
| EscapeAnalysis(Function* alloc = 0) : |
| FunctionPass((intptr_t)&ID) { |
| Allocator = alloc; |
| } |
| |
| virtual bool runOnFunction(Function &F); |
| private: |
| Function* Allocator; |
| bool processMalloc(Instruction* I, Value* Size, Value* VT); |
| }; |
| char EscapeAnalysis::ID = 0; |
| RegisterPass<EscapeAnalysis> X("EscapeAnalysis", "Escape Analysis Pass"); |
| |
| bool EscapeAnalysis::runOnFunction(Function& F) { |
| bool Changed = false; |
| for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; BI++) { |
| BasicBlock *Cur = BI; |
| |
| for (BasicBlock::iterator II = Cur->begin(), IE = Cur->end(); II != IE;) { |
| Instruction *I = II; |
| II++; |
| if (CallInst *CI = dyn_cast<CallInst>(I)) { |
| if (CI->getOperand(0) == Allocator) { |
| Changed |= processMalloc(CI, CI->getOperand(1), CI->getOperand(2)); |
| } |
| } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) { |
| if (CI->getOperand(0) == Allocator) { |
| Changed |= processMalloc(CI, CI->getOperand(3), CI->getOperand(4)); |
| } |
| } |
| } |
| } |
| return Changed; |
| } |
| |
| |
| |
| |
| static bool escapes(Instruction* Ins, std::map<Instruction*, bool>& visited) { |
| for (Value::use_iterator I = Ins->use_begin(), E = Ins->use_end(); |
| I != E; ++I) { |
| if (Instruction* II = dyn_cast<Instruction>(I)) { |
| if (dyn_cast<CallInst>(II)) return true; |
| else if (dyn_cast<InvokeInst>(II)) return true; |
| else if (dyn_cast<BitCastInst>(II)) { |
| if (escapes(II, visited)) return true; |
| } |
| else if (StoreInst* SI = dyn_cast<StoreInst>(II)) { |
| if (AllocaInst * AI = dyn_cast<AllocaInst>(SI->getOperand(1))) { |
| if (!visited[AI]) { |
| visited[AI] = true; |
| if (escapes(AI, visited)) return true; |
| } |
| } else if (SI->getOperand(0) == Ins) { |
| return true; |
| } |
| } |
| else if (dyn_cast<LoadInst>(II)) { |
| if (isa<PointerType>(II->getType())) { |
| if (escapes(II, visited)) return true; // allocas |
| } |
| } |
| else if (dyn_cast<GetElementPtrInst>(II)) { |
| if (escapes(II, visited)) return true; |
| } |
| else if (dyn_cast<ReturnInst>(II)) return true; |
| else if (dyn_cast<PHINode>(II)) { |
| if (!visited[II]) { |
| visited[II] = true; |
| if (escapes(II, visited)) return true; |
| } |
| } |
| } else { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool EscapeAnalysis::processMalloc(Instruction* I, Value* Size, Value* VT) { |
| Instruction* Alloc = I; |
| |
| ConstantExpr* CE = dyn_cast<ConstantExpr>(VT); |
| if (CE) { |
| ConstantInt* C = (ConstantInt*)CE->getOperand(0); |
| VirtualTable* Table = (VirtualTable*)C->getZExtValue(); |
| // If the class has a finalize method, do not stack allocate the object |
| if (!((void**)Table)[0]) { |
| std::map<Instruction*, bool> visited; |
| if (!(escapes(Alloc, visited))) { |
| AllocaInst* AI = new AllocaInst(Type::Int8Ty, Size, "", Alloc); |
| BitCastInst* BI = new BitCastInst(AI, Alloc->getType(), "", Alloc); |
| DOUT << "escape" << Alloc->getParent()->getParent()->getName() << "\n"; |
| Alloc->replaceAllUsesWith(BI); |
| Alloc->eraseFromParent(); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| } |
| |
| namespace mvm { |
| FunctionPass* createEscapeAnalysisPass(llvm::Function* alloc) { |
| |
| return new EscapeAnalysis(alloc); |
| } |
| } |