| //===---------------- JIT.cc - Initialize the JIT -------------------------===// |
| // |
| // The Micro Virtual Machine |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <llvm/CallingConv.h> |
| #include <llvm/Constants.h> |
| #include <llvm/DerivedTypes.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/LinkAllPasses.h> |
| #include <llvm/Linker.h> |
| #include <llvm/LLVMContext.h> |
| #include <llvm/Module.h> |
| #include <llvm/PassManager.h> |
| #include <llvm/Type.h> |
| #include <llvm/Analysis/DebugInfo.h> |
| #include <llvm/Analysis/LoopPass.h> |
| #include <llvm/Analysis/Verifier.h> |
| #include <llvm/Assembly/Parser.h> |
| #include <llvm/CodeGen/GCStrategy.h> |
| #include <llvm/Config/config.h> |
| #include <llvm/ExecutionEngine/ExecutionEngine.h> |
| #include "llvm/ExecutionEngine/JITEventListener.h" |
| #include "llvm/Support/CommandLine.h" |
| #include <llvm/Support/Debug.h> |
| #include <llvm/Support/IRReader.h> |
| #include <llvm/Support/MutexGuard.h> |
| #include <llvm/Support/PassNameParser.h> |
| #include <llvm/Support/SourceMgr.h> |
| #include <llvm/Target/TargetData.h> |
| #include <llvm/Target/TargetMachine.h> |
| #include <llvm/Target/TargetOptions.h> |
| #include <llvm/Target/TargetSelect.h> |
| |
| #include "mvm/JIT.h" |
| #include "mvm/Threads/Locks.h" |
| #include "mvm/Threads/Thread.h" |
| #include "mvm/VirtualMachine.h" |
| #include "mvm/GC/GC.h" |
| #include "MutatorThread.h" |
| #include "MvmGC.h" |
| |
| #include <sys/mman.h> |
| |
| using namespace mvm; |
| using namespace llvm; |
| |
| |
| static cl::list<std::string> |
| LoadBytecodeFiles("load-bc", cl::desc("Load bytecode file"), cl::ZeroOrMore, |
| cl::CommaSeparated); |
| |
| namespace mvm { |
| namespace llvm_runtime { |
| #include "LLVMRuntime.inc" |
| } |
| |
| namespace mmtk_runtime { |
| #include "MMTkInline.inc" |
| } |
| void linkVmkitGC(); |
| } |
| |
| const char* MvmModule::getHostTriple() { |
| return LLVM_HOSTTRIPLE; |
| } |
| |
| class MvmJITMethodInfo : public JITMethodInfo { |
| const llvm::Function* Func; |
| public: |
| virtual void print(void* ip, void* addr); |
| MvmJITMethodInfo(llvm::GCFunctionInfo* GFI, const llvm::Function* F) : |
| JITMethodInfo(GFI) { |
| Func = F; |
| MethodType = 0; |
| } |
| }; |
| |
| void MvmJITMethodInfo::print(void* ip, void* addr) { |
| fprintf(stderr, "; %p in %s LLVM method\n", ip, Func->getName().data()); |
| } |
| |
| class MvmJITListener : public llvm::JITEventListener { |
| public: |
| virtual void NotifyFunctionEmitted(const Function &F, |
| void *Code, size_t Size, |
| const EmittedFunctionDetails &Details) { |
| // Functions compiled in the global module are MMTk functions and the |
| // interfaces with VMKit. |
| if (F.getParent() == MvmModule::globalModule) { |
| llvm::GCFunctionInfo* GFI = 0; |
| // We know the last GC info is for this method. |
| if (F.hasGC()) { |
| // Only the interface functions have GC informations. |
| GCStrategy::iterator I = mvm::MvmModule::TheGCStrategy->end(); |
| I--; |
| DEBUG(errs() << (*I)->getFunction().getName() << '\n'); |
| DEBUG(errs() << F.getName() << '\n'); |
| assert(&(*I)->getFunction() == &F && |
| "GC Info and method do not correspond"); |
| GFI = *I; |
| } |
| MethodInfo* MI = |
| new(*MvmModule::Allocator, "MvmJITMethodInfo") MvmJITMethodInfo(GFI, &F); |
| VirtualMachine::SharedRuntimeFunctions.addMethodInfo(MI, Code, |
| (void*)((uintptr_t)Code + Size)); |
| } |
| } |
| }; |
| |
| static MvmJITListener JITListener; |
| |
| void MvmModule::loadBytecodeFile(const std::string& str) { |
| SMDiagnostic Err; |
| Module* M = ParseIRFile(str, Err, globalModule->getContext()); |
| if (M) { |
| M->setTargetTriple(getHostTriple()); |
| Linker::LinkModules(globalModule, M, 0); |
| delete M; |
| } else { |
| Err.Print("load bytecode", errs()); |
| } |
| } |
| |
| typedef void (*BootType)(uintptr_t Plan); |
| typedef void (*BootHeapType)(intptr_t initial, intptr_t max); |
| |
| void MvmModule::initialise(CodeGenOpt::Level level, Module* M, |
| TargetMachine* T) { |
| mvm::linkVmkitGC(); |
| |
| llvm_start_multithreaded(); |
| |
| llvm::NoFramePointerElim = true; |
| llvm::DisablePrettyStackTrace = true; |
| llvm::JITEmitDebugInfo = false; |
| #if DWARF_EXCEPTIONS |
| llvm::DwarfExceptionHandling = true; |
| #else |
| llvm::DwarfExceptionHandling = false; |
| #endif |
| |
| // Disable branch fold for accurate line numbers. |
| char* commands[2] = { (char*)"vmkit", (char*)"-disable-branch-fold" }; |
| llvm::cl::ParseCommandLineOptions(2, commands); |
| |
| if (!M) { |
| globalModule = new Module("bootstrap module", getGlobalContext()); |
| |
| InitializeNativeTarget(); |
| |
| executionEngine = ExecutionEngine::createJIT(globalModule, 0, |
| 0, level, false); |
| |
| Allocator = new BumpPtrAllocator(); |
| executionEngine->RegisterJITEventListener(&JITListener); |
| std::string str = |
| executionEngine->getTargetData()->getStringRepresentation(); |
| globalModule->setDataLayout(str); |
| globalModule->setTargetTriple(getHostTriple()); |
| |
| TheTargetData = executionEngine->getTargetData(); |
| } else { |
| globalModule = M; |
| TheTargetData = T->getTargetData(); |
| } |
| |
| globalFunctionPasses = new FunctionPassManager(globalModule); |
| |
| |
| //LLVMContext& Context = globalModule->getContext(); |
| //MetadataTypeKind = Context.getMDKindID("HighLevelType"); |
| |
| for (std::vector<std::string>::iterator i = LoadBytecodeFiles.begin(), |
| e = LoadBytecodeFiles.end(); i != e; ++i) { |
| loadBytecodeFile(*i); |
| } |
| |
| #ifdef WITH_MMTK |
| llvm::GlobalVariable* GV = globalModule->getGlobalVariable("MMTkCollectorSize", false); |
| if (GV && executionEngine) { |
| // Allocate the memory for MMTk right now, to avoid conflicts with |
| // other allocators. |
| #if defined (__MACH__) |
| uint32 flags = MAP_PRIVATE | MAP_ANON | MAP_FIXED; |
| #else |
| uint32 flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; |
| #endif |
| void* baseAddr = mmap((void*)0x30000000, 0x50000000, PROT_READ | PROT_WRITE, |
| flags, -1, 0); |
| if (baseAddr == MAP_FAILED) { |
| perror("mmap"); |
| abort(); |
| } |
| |
| ConstantInt* C = dyn_cast<ConstantInt>(GV->getInitializer()); |
| uint64_t val = C->getZExtValue(); |
| MutatorThread::MMTkCollectorSize = val; |
| |
| GV = globalModule->getGlobalVariable("MMTkMutatorSize", false); |
| assert(GV && "Could not find MMTkMutatorSize"); |
| C = dyn_cast<ConstantInt>(GV->getInitializer()); |
| val = C->getZExtValue(); |
| MutatorThread::MMTkMutatorSize = val; |
| |
| Function* F = globalModule->getFunction("JnJVM_org_j3_config_Selected_00024Mutator__0003Cinit_0003E__"); |
| assert(F && "Could not find <init> from Mutator"); |
| MutatorThread::MutatorInit = (MutatorThread::MMTkInitType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_MutatorContext_initMutator__I"); |
| assert(F && "Could not find init from Mutator"); |
| MutatorThread::MutatorCallInit = (MutatorThread::MMTkInitIntType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_MutatorContext_deinitMutator__"); |
| assert(F && "Could not find deinit from Mutator"); |
| MutatorThread::MutatorCallDeinit = (MutatorThread::MMTkInitType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| |
| GV = globalModule->getGlobalVariable("org_j3_config_Selected_4Mutator_VT", false); |
| assert(GV && "Could not find VT from Mutator"); |
| MutatorThread::MutatorVT = (VirtualTable*)executionEngine->getPointerToGlobal(GV); |
| |
| F = globalModule->getFunction("JnJVM_org_j3_config_Selected_00024Collector__0003Cinit_0003E__"); |
| assert(F && "Could not find <init> from Collector"); |
| MutatorThread::CollectorInit = (MutatorThread::MMTkInitType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| GV = globalModule->getGlobalVariable("org_j3_config_Selected_4Collector_VT", false); |
| assert(GV && "Could not find VT from Collector"); |
| MutatorThread::CollectorVT = (VirtualTable*)executionEngine->getPointerToGlobal(GV); |
| |
| GlobalAlias* GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkAlloc")); |
| assert(GA && "Could not find MMTkAlloc alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| gc::MMTkGCAllocator = (gc::MMTkAllocType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkPostAlloc")); |
| assert(GA && "Could not find MMTkPostAlloc alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| gc::MMTkGCPostAllocator = (gc::MMTkPostAllocType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkCheckAllocator")); |
| assert(GA && "Could not find MMTkCheckAllocator alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| gc::MMTkCheckAllocator = (gc::MMTkCheckAllocatorType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_utility_heap_HeapGrowthManager_boot__Lorg_vmmagic_unboxed_Extent_2Lorg_vmmagic_unboxed_Extent_2"); |
| assert(F && "Could not find boot from HeapGrowthManager"); |
| BootHeapType BootHeap = (BootHeapType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| BootHeap(128 * 1024 * 1024, 1024 * 1024 * 1024); |
| |
| GV = globalModule->getGlobalVariable("org_j3_config_Selected_4Plan_static", false); |
| assert(GV && "No global plan."); |
| uintptr_t Plan = *((uintptr_t*)executionEngine->getPointerToGlobal(GV)); |
| |
| GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkPlanBoot")); |
| assert(GA && "Could not find MMTkPlanBoot alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| BootType Boot = (BootType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| Boot(Plan); |
| |
| GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkPlanPostBoot")); |
| assert(GA && "Could not find MMTkPlanPostBoot alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| Boot = (BootType)(uintptr_t)executionEngine->getPointerToFunction(F); |
| Boot(Plan); |
| |
| GA = dyn_cast<GlobalAlias>(globalModule->getNamedValue("MMTkPlanFullBoot")); |
| assert(GA && "Could not find MMTkPlanFullBoot alias"); |
| F = dyn_cast<Function>(GA->getAliasee()); |
| Boot = (BootType)(uintptr_t)executionEngine->getPointerToFunction(F); |
| Boot(Plan); |
| |
| F = globalModule->getFunction("Java_org_j3_mmtk_Collection_triggerCollection__I"); |
| assert(F && "Could not find external collect"); |
| gc::MMTkTriggerCollection = (gc::MMTkCollectType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| //===-------------------- TODO: make those virtual. -------------------===// |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_reportDelayedRootEdge__Lorg_vmmagic_unboxed_Address_2"); |
| assert(F && "Could not find reportDelayedRootEdge from TraceLocal"); |
| gc::MMTkDelayedRoot = (gc::MMTkDelayedRootType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_processEdge__Lorg_vmmagic_unboxed_ObjectReference_2Lorg_vmmagic_unboxed_Address_2"); |
| assert(F && "Could not find processEdge from TraceLocal"); |
| gc::MMTkProcessEdge = (gc::MMTkProcessEdgeType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_processRootEdge__Lorg_vmmagic_unboxed_Address_2Z"); |
| assert(F && "Could not find processEdge from TraceLocal"); |
| gc::MMTkProcessRootEdge = (gc::MMTkProcessRootEdgeType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_marksweep_MSTraceLocal_isLive__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkIsLive = (gc::MMTkIsLiveType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_retainForFinalize__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkRetainForFinalize = (gc::MMTkRetainForFinalizeType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_retainReferent__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkRetainReferent = (gc::MMTkRetainReferentType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_getForwardedReference__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkGetForwardedReference = (gc::MMTkGetForwardedReferenceType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_getForwardedReferent__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkGetForwardedReferent = (gc::MMTkGetForwardedReferentType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| F = globalModule->getFunction("JnJVM_org_mmtk_plan_TraceLocal_getForwardedFinalizable__Lorg_vmmagic_unboxed_ObjectReference_2"); |
| assert(F && "Could not find isLive from TraceLocal"); |
| gc::MMTkGetForwardedFinalizable = (gc::MMTkGetForwardedFinalizableType) |
| (uintptr_t)executionEngine->getPointerToFunction(F); |
| |
| } |
| #endif |
| } |
| |
| |
| BaseIntrinsics::BaseIntrinsics(llvm::Module* module) { |
| |
| module->setDataLayout(MvmModule::globalModule->getDataLayout()); |
| module->setTargetTriple(MvmModule::globalModule->getTargetTriple()); |
| LLVMContext& Context = module->getContext(); |
| |
| #ifdef WITH_MMTK |
| if (MutatorThread::MMTkCollectorSize) { |
| // If we have found MMTk, read the gcmalloc function and set the address of |
| // global variables and functions used by gcmalloc. |
| mvm::mmtk_runtime::makeLLVMFunction(module); |
| if (MvmModule::executionEngine) { |
| for (Module::global_iterator i = module->global_begin(), |
| e = module->global_end(); i != e; ++i) { |
| if (i->isDeclaration()) { |
| GlobalVariable* GV = |
| MvmModule::globalModule->getGlobalVariable(i->getName(), true); |
| assert(GV && "GV can not be found"); |
| void* ptr = MvmModule::executionEngine->getPointerToGlobal(GV); |
| MvmModule::executionEngine->updateGlobalMapping(i, ptr); |
| } |
| } |
| for (Module::iterator i = module->begin(), e = module->end(); |
| i != e; ++i) { |
| if (i->isDeclaration() && !i->isIntrinsic()) { |
| Function* F = |
| MvmModule::globalModule->getFunction(i->getName()); |
| assert(F && "Function can not be found"); |
| void* ptr = MvmModule::executionEngine->getPointerToFunction(F); |
| MvmModule::executionEngine->updateGlobalMapping(i, ptr); |
| } |
| } |
| } |
| } |
| #endif |
| mvm::llvm_runtime::makeLLVMModuleContents(module); |
| |
| |
| // Type declaration |
| ptrType = PointerType::getUnqual(Type::getInt8Ty(Context)); |
| ptr32Type = PointerType::getUnqual(Type::getInt32Ty(Context)); |
| ptrPtrType = PointerType::getUnqual(ptrType); |
| pointerSizeType = module->getPointerSize() == Module::Pointer32 ? |
| Type::getInt32Ty(Context) : Type::getInt64Ty(Context); |
| |
| // Constant declaration |
| constantLongMinusOne = ConstantInt::get(Type::getInt64Ty(Context), (uint64_t)-1); |
| constantLongZero = ConstantInt::get(Type::getInt64Ty(Context), 0); |
| constantLongOne = ConstantInt::get(Type::getInt64Ty(Context), 1); |
| constantZero = ConstantInt::get(Type::getInt32Ty(Context), 0); |
| constantInt8Zero = ConstantInt::get(Type::getInt8Ty(Context), 0); |
| constantOne = ConstantInt::get(Type::getInt32Ty(Context), 1); |
| constantTwo = ConstantInt::get(Type::getInt32Ty(Context), 2); |
| constantThree = ConstantInt::get(Type::getInt32Ty(Context), 3); |
| constantFour = ConstantInt::get(Type::getInt32Ty(Context), 4); |
| constantFive = ConstantInt::get(Type::getInt32Ty(Context), 5); |
| constantSix = ConstantInt::get(Type::getInt32Ty(Context), 6); |
| constantSeven = ConstantInt::get(Type::getInt32Ty(Context), 7); |
| constantEight = ConstantInt::get(Type::getInt32Ty(Context), 8); |
| constantMinusOne = ConstantInt::get(Type::getInt32Ty(Context), (uint64_t)-1); |
| constantMinInt = ConstantInt::get(Type::getInt32Ty(Context), MinInt); |
| constantMaxInt = ConstantInt::get(Type::getInt32Ty(Context), MaxInt); |
| constantMinLong = ConstantInt::get(Type::getInt64Ty(Context), MinLong); |
| constantMaxLong = ConstantInt::get(Type::getInt64Ty(Context), MaxLong); |
| constantFloatZero = ConstantFP::get(Type::getFloatTy(Context), 0.0f); |
| constantFloatOne = ConstantFP::get(Type::getFloatTy(Context), 1.0f); |
| constantFloatTwo = ConstantFP::get(Type::getFloatTy(Context), 2.0f); |
| constantDoubleZero = ConstantFP::get(Type::getDoubleTy(Context), 0.0); |
| constantDoubleOne = ConstantFP::get(Type::getDoubleTy(Context), 1.0); |
| constantMaxIntFloat = ConstantFP::get(Type::getFloatTy(Context), MaxIntFloat); |
| constantMinIntFloat = ConstantFP::get(Type::getFloatTy(Context), MinIntFloat); |
| constantMinLongFloat = ConstantFP::get(Type::getFloatTy(Context), MinLongFloat); |
| constantMinLongDouble = ConstantFP::get(Type::getDoubleTy(Context), MinLongDouble); |
| constantMaxLongFloat = ConstantFP::get(Type::getFloatTy(Context), MaxLongFloat); |
| constantMaxIntDouble = ConstantFP::get(Type::getDoubleTy(Context), MaxIntDouble); |
| constantMinIntDouble = ConstantFP::get(Type::getDoubleTy(Context), MinIntDouble); |
| constantMaxLongDouble = ConstantFP::get(Type::getDoubleTy(Context), MaxLongDouble); |
| constantMaxLongDouble = ConstantFP::get(Type::getDoubleTy(Context), MaxLongDouble); |
| constantFloatInfinity = ConstantFP::get(Type::getFloatTy(Context), MaxFloat); |
| constantFloatMinusInfinity = ConstantFP::get(Type::getFloatTy(Context), MinFloat); |
| constantDoubleInfinity = ConstantFP::get(Type::getDoubleTy(Context), MaxDouble); |
| constantDoubleMinusInfinity = ConstantFP::get(Type::getDoubleTy(Context), MinDouble); |
| constantDoubleMinusZero = ConstantFP::get(Type::getDoubleTy(Context), -0.0); |
| constantFloatMinusZero = ConstantFP::get(Type::getFloatTy(Context), -0.0f); |
| constantThreadIDMask = ConstantInt::get(pointerSizeType, mvm::Thread::IDMask); |
| constantStackOverflowMask = |
| ConstantInt::get(pointerSizeType, mvm::Thread::StackOverflowMask); |
| constantFatMask = ConstantInt::get(pointerSizeType, |
| pointerSizeType == Type::getInt32Ty(Context) ? 0x80000000 : 0x8000000000000000LL); |
| constantPtrOne = ConstantInt::get(pointerSizeType, 1); |
| constantPtrZero = ConstantInt::get(pointerSizeType, 0); |
| |
| constantPtrNull = Constant::getNullValue(ptrType); |
| constantPtrLogSize = |
| ConstantInt::get(Type::getInt32Ty(Context), sizeof(void*) == 8 ? 3 : 2); |
| arrayPtrType = PointerType::getUnqual(ArrayType::get(Type::getInt8Ty(Context), 0)); |
| |
| |
| |
| printFloatLLVM = module->getFunction("printFloat"); |
| printDoubleLLVM = module->getFunction("printDouble"); |
| printLongLLVM = module->getFunction("printLong"); |
| printIntLLVM = module->getFunction("printInt"); |
| printObjectLLVM = module->getFunction("printObject"); |
| |
| unwindResume = module->getFunction("_Unwind_Resume_or_Rethrow"); |
| |
| llvmGetException = module->getFunction("llvm.eh.exception"); |
| exceptionSelector = module->getFunction("llvm.eh.selector"); |
| |
| personality = module->getFunction("__gxx_personality_v0"); |
| exceptionEndCatch = module->getFunction("__cxa_end_catch"); |
| exceptionBeginCatch = module->getFunction("__cxa_begin_catch"); |
| |
| func_llvm_sqrt_f64 = module->getFunction("llvm.sqrt.f64"); |
| func_llvm_sin_f64 = module->getFunction("llvm.sin.f64"); |
| func_llvm_cos_f64 = module->getFunction("llvm.cos.f64"); |
| |
| func_llvm_tan_f64 = module->getFunction("tan"); |
| func_llvm_asin_f64 = module->getFunction("asin"); |
| func_llvm_acos_f64 = module->getFunction("acos"); |
| func_llvm_atan_f64 = module->getFunction("atan"); |
| func_llvm_exp_f64 = module->getFunction("exp"); |
| func_llvm_log_f64 = module->getFunction("log"); |
| func_llvm_ceil_f64 = module->getFunction("ceil"); |
| func_llvm_floor_f64 = module->getFunction("floor"); |
| func_llvm_cbrt_f64 = module->getFunction("cbrt"); |
| func_llvm_cosh_f64 = module->getFunction("cosh"); |
| func_llvm_expm1_f64 = module->getFunction("expm1"); |
| func_llvm_log10_f64 = module->getFunction("log10"); |
| func_llvm_log1p_f64 = module->getFunction("log1p"); |
| func_llvm_sinh_f64 = module->getFunction("sinh"); |
| func_llvm_tanh_f64 = module->getFunction("tanh"); |
| func_llvm_fabs_f64 = module->getFunction("fabs"); |
| func_llvm_rint_f64 = module->getFunction("rint"); |
| |
| func_llvm_hypot_f64 = module->getFunction("hypot"); |
| func_llvm_pow_f64 = module->getFunction("pow"); |
| func_llvm_atan2_f64 = module->getFunction("atan2"); |
| |
| func_llvm_fabs_f32 = module->getFunction("fabsf"); |
| |
| setjmpLLVM = module->getFunction("setjmp"); |
| |
| llvm_memcpy_i32 = module->getFunction("llvm.memcpy.i32"); |
| llvm_memset_i32 = module->getFunction("llvm.memset.i32"); |
| llvm_frameaddress = module->getFunction("llvm.frameaddress"); |
| llvm_gc_gcroot = module->getFunction("llvm.gcroot"); |
| |
| llvm_atomic_lcs_i8 = module->getFunction("llvm.atomic.cmp.swap.i8.p0i8"); |
| llvm_atomic_lcs_i16 = module->getFunction("llvm.atomic.cmp.swap.i16.p0i16"); |
| llvm_atomic_lcs_i32 = module->getFunction("llvm.atomic.cmp.swap.i32.p0i32"); |
| llvm_atomic_lcs_i64 = module->getFunction("llvm.atomic.cmp.swap.i64.p0i64"); |
| |
| llvm_atomic_lcs_ptr = pointerSizeType == Type::getInt32Ty(Context) ? llvm_atomic_lcs_i32 : |
| llvm_atomic_lcs_i64; |
| |
| unconditionalSafePoint = module->getFunction("unconditionalSafePoint"); |
| conditionalSafePoint = module->getFunction("conditionalSafePoint"); |
| AllocateFunction = module->getFunction("gcmalloc"); |
| assert(AllocateFunction && "No allocate function"); |
| AllocateUnresolvedFunction = module->getFunction("gcmallocUnresolved"); |
| assert(AllocateUnresolvedFunction && "No allocateUnresolved function"); |
| AddFinalizationCandidate = module->getFunction("addFinalizationCandidate"); |
| assert(AddFinalizationCandidate && "No addFinalizationCandidate function"); |
| |
| MvmModule::copyDefinitions(module, MvmModule::globalModule); |
| } |
| |
| const llvm::TargetData* MvmModule::TheTargetData; |
| llvm::GCStrategy* MvmModule::TheGCStrategy; |
| llvm::Module *MvmModule::globalModule; |
| llvm::FunctionPassManager* MvmModule::globalFunctionPasses; |
| llvm::ExecutionEngine* MvmModule::executionEngine; |
| mvm::LockRecursive MvmModule::protectEngine; |
| mvm::BumpPtrAllocator* MvmModule::Allocator; |
| //unsigned MvmModule::MetadataTypeKind; |
| |
| uint64 MvmModule::getTypeSize(const llvm::Type* type) { |
| return TheTargetData->getTypeAllocSize(type); |
| } |
| |
| void MvmModule::runPasses(llvm::Function* func, |
| llvm::FunctionPassManager* pm) { |
| // Take the lock because the pass manager will call materializeFunction. |
| // Our implementation of materializeFunction requires that the lock is held |
| // by the caller. This is due to LLVM's JIT subsystem where the call to |
| // materializeFunction is guarded. |
| if (executionEngine) executionEngine->lock.acquire(); |
| pm->run(*func); |
| if (executionEngine) executionEngine->lock.release(); |
| } |
| |
| static void addPass(FunctionPassManager *PM, Pass *P) { |
| // Add the pass to the pass manager... |
| PM->add(P); |
| } |
| |
| // This is equivalent to: |
| // opt -simplifycfg -mem2reg -instcombine -jump-threading -simplifycfg |
| // -scalarrepl -instcombine -condprop -simplifycfg -predsimplify |
| // -reassociate -licm -loop-unswitch -indvars -loop-deletion -loop-unroll |
| // -instcombine -gvn -sccp -simplifycfg -instcombine -condprop -dse -adce |
| // -simplifycfg |
| // |
| static void AddStandardCompilePasses(FunctionPassManager* PM) { |
| |
| addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code |
| addPass(PM, createPromoteMemoryToRegisterPass());// Kill useless allocas |
| |
| addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. |
| addPass(PM, createScalarReplAggregatesPass()); // Break up aggregate allocas |
| addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. |
| addPass(PM, createJumpThreadingPass()); // Thread jumps. |
| addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs |
| addPass(PM, createInstructionCombiningPass()); // Combine silly seq's |
| |
| addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs |
| addPass(PM, createReassociatePass()); // Reassociate expressions |
| addPass(PM, createLoopRotatePass()); // Rotate loops. |
| addPass(PM, createLICMPass()); // Hoist loop invariants |
| addPass(PM, createLoopUnswitchPass()); // Unswitch loops. |
| addPass(PM, createInstructionCombiningPass()); |
| addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars |
| addPass(PM, createLoopDeletionPass()); // Delete dead loops |
| addPass(PM, createLoopUnrollPass()); // Unroll small loops*/ |
| addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller |
| addPass(PM, createGVNPass()); // Remove redundancies |
| addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset |
| addPass(PM, createSCCPPass()); // Constant prop with SCCP |
| |
| // Run instcombine after redundancy elimination to exploit opportunities |
| // opened up by them. |
| addPass(PM, createInstructionCombiningPass()); |
| addPass(PM, createJumpThreadingPass()); // Thread jumps |
| addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores |
| addPass(PM, createAggressiveDCEPass()); // Delete dead instructions |
| addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs |
| } |
| |
| static cl::opt<bool> |
| DisableOptimizations("disable-opt", |
| cl::desc("Do not run any optimization passes")); |
| |
| cl::opt<bool> |
| StandardCompileOpts("std-compile-opts", |
| cl::desc("Include the standard compile time optimizations")); |
| |
| // The OptimizationList is automatically populated with registered Passes by the |
| // PassNameParser. |
| // |
| static llvm::cl::list<const llvm::PassInfo*, bool, llvm::PassNameParser> |
| PassList(llvm::cl::desc("Optimizations available:")); |
| |
| namespace mvm { |
| llvm::FunctionPass* createInlineMallocPass(); |
| } |
| |
| void MvmModule::addCommandLinePasses(FunctionPassManager* PM) { |
| addPass(PM, new TargetData(*MvmModule::TheTargetData)); |
| |
| addPass(PM, createVerifierPass()); // Verify that input is correct |
| |
| #ifdef WITH_MMTK |
| addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code |
| addPass(PM, createInlineMallocPass()); |
| #endif |
| |
| // Create a new optimization pass for each one specified on the command line |
| for (unsigned i = 0; i < PassList.size(); ++i) { |
| // Check to see if -std-compile-opts was specified before this option. If |
| // so, handle it. |
| if (StandardCompileOpts && |
| StandardCompileOpts.getPosition() < PassList.getPosition(i)) { |
| if (!DisableOptimizations) AddStandardCompilePasses(PM); |
| StandardCompileOpts = false; |
| } |
| |
| const PassInfo *PassInf = PassList[i]; |
| Pass *P = 0; |
| if (PassInf->getNormalCtor()) |
| P = PassInf->getNormalCtor()(); |
| else |
| errs() << "cannot create pass: " |
| << PassInf->getPassName() << "\n"; |
| if (P) { |
| bool isModulePass = (P->getPassKind() == PT_Module); |
| if (isModulePass) |
| errs() << "vmkit does not support module pass: " |
| << PassInf->getPassName() << "\n"; |
| else addPass(PM, P); |
| |
| } |
| } |
| |
| // If -std-compile-opts was specified at the end of the pass list, add them. |
| if (StandardCompileOpts) { |
| AddStandardCompilePasses(PM); |
| } |
| PM->doInitialization(); |
| } |
| |
| // We protect the creation of IR with the executionEngine lock because |
| // codegen'ing a function may also create IR objects. |
| void MvmModule::protectIR() { |
| if (executionEngine) { |
| protectEngine.lock(); |
| } |
| } |
| |
| void MvmModule::unprotectIR() { |
| if (executionEngine) { |
| protectEngine.unlock(); |
| } |
| } |
| |
| |
| void MvmModule::copyDefinitions(Module* Dst, Module* Src) { |
| Function* SF = Src->getFunction("gcmalloc"); |
| Function* DF = Dst->getFunction("gcmalloc"); |
| if (SF && DF && executionEngine && !SF->isDeclaration()) { |
| void* ptr = executionEngine->getPointerToFunction(SF); |
| executionEngine->updateGlobalMapping(DF, ptr); |
| } |
| |
| SF = Src->getFunction("gcmallocUnresolved"); |
| DF = Dst->getFunction("gcmallocUnresolved"); |
| if (SF && DF && executionEngine && !SF->isDeclaration()) { |
| void* ptr = executionEngine->getPointerToFunction(SF); |
| executionEngine->updateGlobalMapping(DF, ptr); |
| } |
| |
| SF = Src->getFunction("addFinalizationCandidate"); |
| DF = Dst->getFunction("addFinalizationCandidate"); |
| if (SF && DF && executionEngine && !SF->isDeclaration()) { |
| void* ptr = executionEngine->getPointerToFunction(SF); |
| executionEngine->updateGlobalMapping(DF, ptr); |
| } |
| } |
| |
| void JITMethodInfo::scan(void* TL, void* ip, void* addr) { |
| if (GCInfo) { |
| DEBUG(llvm::errs() << GCInfo->getFunction().getName() << '\n'); |
| // All safe points have the same informations currently in LLVM. |
| llvm::GCFunctionInfo::iterator J = GCInfo->begin(); |
| //uintptr_t spaddr = (uintptr_t)addr + GFI->getFrameSize() + sizeof(void*); |
| uintptr_t spaddr = ((uintptr_t*)addr)[0]; |
| for (llvm::GCFunctionInfo::live_iterator K = GCInfo->live_begin(J), |
| KE = GCInfo->live_end(J); K != KE; ++K) { |
| intptr_t obj = *(intptr_t*)(spaddr + K->StackOffset); |
| // Verify that obj does not come from a JSR bytecode. |
| if (!(obj & 1)) Collector::scanObject((void**)(spaddr + K->StackOffset)); |
| } |
| } |
| } |
| |