blob: 06ecec9503e8ee02fd4963b2fe437947c1b91d6c [file] [log] [blame]
//===------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);
}
}