blob: 88dd810fa35e3b7c5cda451975de1d45ae80b651 [file] [log] [blame]
#include <dlfcn.h>
#include "vmkit/system.h"
#include "vmkit/compiler.h"
#include "vmkit/thread.h"
#include "vmkit/vmkit.h"
#include "vmkit/safepoint.h"
#include "vmkit/inliner.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/PassManager.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Target/TargetOptions.h"
using namespace vmkit;
void* Symbol::getSymbolAddress() {
Thread::get()->vm()->internalError("implement me: getSymbolAddress");
}
uint64_t Symbol::inlineWeight() {
if(cachedWeight)
return cachedWeight;
if(llvmFunction()->size() > 4)
return cachedWeight = (uint64_t)-1;
uint64_t weight = 0;
for (llvm::Function::iterator bit=llvmFunction()->begin(); bit!=llvmFunction()->end(); bit++)
weight += bit->size();
weight = weight * 256;
return cachedWeight = weight;
}
void Symbol::markAsNeverInline() {
if(llvmFunction())
llvmFunction()->addFnAttr(llvm::Attribute::NoInline);
}
void* CompilationUnit::operator new(size_t n, BumpAllocator* allocator) {
return allocator->allocate(n);
}
void CompilationUnit::operator delete(void* self) {
}
CompilationUnit::CompilationUnit(BumpAllocator* allocator, const char* id, bool runInlinePass, bool onlyAlwaysInline) :
_symbolTable(vmkit::Util::char_less, allocator) {
_allocator = allocator;
pthread_mutex_init(&_mutexSymbolTable, 0);
std::string err;
llvm::TargetOptions opt;
opt.NoFramePointerElim = 1;
_ee = llvm::EngineBuilder(new llvm::Module(id, Thread::get()->vm()->llvmContext()))
.setUseMCJIT(1)
.setMCJITMemoryManager(this)
.setOptLevel(llvm::CodeGenOpt::None) /* Aggressive */
.setTargetOptions(opt)
.setErrorStr(&err)
.create();
if (!ee())
Thread::get()->vm()->internalError("Error while creating execution engine: %s\n", err.c_str());
ee()->finalizeObject();
pm = new llvm::PassManager();
//pm->add(new llvm::TargetData(*ee->getTargetData()));
#if 0
pm->add(llvm::createBasicAliasAnalysisPass());
#endif
if(runInlinePass || onlyAlwaysInline)
pm->add(vmkit::createFunctionInlinerPass(this, onlyAlwaysInline));
#if 0
pm->add(llvm::createCFGSimplificationPass()); // Clean up disgusting code
pm->add(llvm::createPromoteMemoryToRegisterPass());// Kill useless allocas
pm->add(llvm::createInstructionCombiningPass()); // Cleanup for scalarrepl.
pm->add(llvm::createScalarReplAggregatesPass()); // Break up aggregate allocas
pm->add(llvm::createInstructionCombiningPass()); // Cleanup for scalarrepl.
pm->add(llvm::createJumpThreadingPass()); // Thread jumps.
pm->add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
pm->add(llvm::createInstructionCombiningPass()); // Combine silly seq's
pm->add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
pm->add(llvm::createReassociatePass()); // Reassociate expressions
pm->add(llvm::createLoopRotatePass()); // Rotate loops.
pm->add(llvm::createLICMPass()); // Hoist loop invariants
pm->add(llvm::createLoopUnswitchPass()); // Unswitch loops.
pm->add(llvm::createInstructionCombiningPass());
pm->add(llvm::createIndVarSimplifyPass()); // Canonicalize indvars
pm->add(llvm::createLoopDeletionPass()); // Delete dead loops
pm->add(llvm::createLoopUnrollPass()); // Unroll small loops*/
pm->add(llvm::createInstructionCombiningPass()); // Clean up after the unroller
pm->add(llvm::createGVNPass()); // Remove redundancies
pm->add(llvm::createMemCpyOptPass()); // Remove memcpy / form memset
pm->add(llvm::createSCCPPass()); // Constant prop with SCCP
// Run instcombine after redundancy elimination to exploit opportunities
// opened up by them.
pm->add(llvm::createInstructionCombiningPass());
pm->add(llvm::createJumpThreadingPass()); // Thread jumps
pm->add(llvm::createDeadStoreEliminationPass()); // Delete dead stores
pm->add(llvm::createAggressiveDCEPass()); // Delete dead instructions
pm->add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
#endif
}
CompilationUnit::~CompilationUnit() {
delete pm;
delete _ee;
}
void CompilationUnit::destroy(CompilationUnit* unit) {
delete unit;
BumpAllocator::destroy(unit->allocator());
}
void CompilationUnit::addSymbol(const char* id, vmkit::Symbol* symbol) {
pthread_mutex_lock(&_mutexSymbolTable);
_symbolTable[id] = symbol;
pthread_mutex_unlock(&_mutexSymbolTable);
}
Symbol* CompilationUnit::getSymbol(const char* id, bool error) {
pthread_mutex_lock(&_mutexSymbolTable);
std::map<const char*, vmkit::Symbol*>::iterator it = _symbolTable.find(id);
vmkit::Symbol* res = 0;
if(it == _symbolTable.end()) {
uint8_t* addr = (uint8_t*)dlsym(SELF_HANDLE, id);
//fprintf(stderr, "lookup: %s => %p\n", id, addr);
if(!addr) {
if(error)
Thread::get()->vm()->internalError("unable to resolve native symbol: %s", id);
} else {
res = new(allocator()) vmkit::NativeSymbol(0, addr);
size_t len = strlen(id);
char* buf = (char*)allocator()->allocate(len+1);
memcpy(buf, id, len+1);
_symbolTable[buf] = res;
}
} else
res = it->second;
pthread_mutex_unlock(&_mutexSymbolTable);
return res;
}
uint64_t CompilationUnit::getSymbolAddress(const std::string &Name) {
return (uint64_t)(uintptr_t)getSymbol(System::mcjitSymbol(Name.c_str()))->getSymbolAddress();
}
void CompilationUnit::prepareModule(llvm::Module* module) {
pm->run(*module);
}
void CompilationUnit::compileModule(llvm::Module* module) {
ee()->addModule(module);
ee()->finalizeObject();
vmkit::Safepoint* sf = Safepoint::get(this, module);
VMKit* vm = Thread::get()->vm();
if(!sf)
vm->internalError("unable to find safepoints");
while(sf->addr()) {
sf->setUnit(this);
vm->addSafepoint(sf);
//Thread::get()->vm()->getSafepoint(sf->addr())->dump();
sf = sf->getNext();
}
}