1//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "OrcLazyJIT.h" 11#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h" 12#include "llvm/Support/Debug.h" 13#include "llvm/Support/DynamicLibrary.h" 14#include <cstdio> 15#include <system_error> 16 17using namespace llvm; 18 19namespace { 20 21 enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdErr, 22 DumpModsToDisk }; 23 24 cl::opt<DumpKind> OrcDumpKind("orc-lazy-debug", 25 cl::desc("Debug dumping for the orc-lazy JIT."), 26 cl::init(DumpKind::NoDump), 27 cl::values( 28 clEnumValN(DumpKind::NoDump, "no-dump", 29 "Don't dump anything."), 30 clEnumValN(DumpKind::DumpFuncsToStdOut, 31 "funcs-to-stdout", 32 "Dump function names to stdout."), 33 clEnumValN(DumpKind::DumpModsToStdErr, 34 "mods-to-stderr", 35 "Dump modules to stderr."), 36 clEnumValN(DumpKind::DumpModsToDisk, 37 "mods-to-disk", 38 "Dump modules to the current " 39 "working directory. (WARNING: " 40 "will overwrite existing files)."), 41 clEnumValEnd), 42 cl::Hidden); 43 44 cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs", 45 cl::desc("Try to inline stubs"), 46 cl::init(true), cl::Hidden); 47} 48 49std::unique_ptr<OrcLazyJIT::CompileCallbackMgr> 50OrcLazyJIT::createCompileCallbackMgr(Triple T) { 51 switch (T.getArch()) { 52 default: return nullptr; 53 54 case Triple::x86_64: { 55 typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64> CCMgrT; 56 return llvm::make_unique<CCMgrT>(0); 57 } 58 } 59} 60 61OrcLazyJIT::IndirectStubsManagerBuilder 62OrcLazyJIT::createIndirectStubsMgrBuilder(Triple T) { 63 switch (T.getArch()) { 64 default: return nullptr; 65 66 case Triple::x86_64: 67 return [](){ 68 return llvm::make_unique< 69 orc::LocalIndirectStubsManager<orc::OrcX86_64>>(); 70 }; 71 } 72} 73 74OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { 75 76 switch (OrcDumpKind) { 77 case DumpKind::NoDump: 78 return [](std::unique_ptr<Module> M) { return M; }; 79 80 case DumpKind::DumpFuncsToStdOut: 81 return [](std::unique_ptr<Module> M) { 82 printf("[ "); 83 84 for (const auto &F : *M) { 85 if (F.isDeclaration()) 86 continue; 87 88 if (F.hasName()) { 89 std::string Name(F.getName()); 90 printf("%s ", Name.c_str()); 91 } else 92 printf("<anon> "); 93 } 94 95 printf("]\n"); 96 return M; 97 }; 98 99 case DumpKind::DumpModsToStdErr: 100 return [](std::unique_ptr<Module> M) { 101 dbgs() << "----- Module Start -----\n" << *M 102 << "----- Module End -----\n"; 103 104 return M; 105 }; 106 107 case DumpKind::DumpModsToDisk: 108 return [](std::unique_ptr<Module> M) { 109 std::error_code EC; 110 raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC, 111 sys::fs::F_Text); 112 if (EC) { 113 errs() << "Couldn't open " << M->getModuleIdentifier() 114 << " for dumping.\nError:" << EC.message() << "\n"; 115 exit(1); 116 } 117 Out << *M; 118 return M; 119 }; 120 } 121 llvm_unreachable("Unknown DumpKind"); 122} 123 124// Defined in lli.cpp. 125CodeGenOpt::Level getOptLevel(); 126 127 128template <typename PtrTy> 129static PtrTy fromTargetAddress(orc::TargetAddress Addr) { 130 return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr)); 131} 132 133int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { 134 // Add the program's symbols into the JIT's search space. 135 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { 136 errs() << "Error loading program symbols.\n"; 137 return 1; 138 } 139 140 // Grab a target machine and try to build a factory function for the 141 // target-specific Orc callback manager. 142 EngineBuilder EB; 143 EB.setOptLevel(getOptLevel()); 144 auto TM = std::unique_ptr<TargetMachine>(EB.selectTarget()); 145 auto CompileCallbackMgr = 146 OrcLazyJIT::createCompileCallbackMgr(Triple(TM->getTargetTriple())); 147 148 // If we couldn't build the factory function then there must not be a callback 149 // manager for this target. Bail out. 150 if (!CompileCallbackMgr) { 151 errs() << "No callback manager available for target '" 152 << TM->getTargetTriple().str() << "'.\n"; 153 return 1; 154 } 155 156 auto IndirectStubsMgrBuilder = 157 OrcLazyJIT::createIndirectStubsMgrBuilder(Triple(TM->getTargetTriple())); 158 159 // If we couldn't build a stubs-manager-builder for this target then bail out. 160 if (!IndirectStubsMgrBuilder) { 161 errs() << "No indirect stubs manager available for target '" 162 << TM->getTargetTriple().str() << "'.\n"; 163 return 1; 164 } 165 166 // Everything looks good. Build the JIT. 167 OrcLazyJIT J(std::move(TM), std::move(CompileCallbackMgr), 168 std::move(IndirectStubsMgrBuilder), 169 OrcInlineStubs); 170 171 // Add the module, look up main and run it. 172 auto MainHandle = J.addModule(std::move(M)); 173 auto MainSym = J.findSymbolIn(MainHandle, "main"); 174 175 if (!MainSym) { 176 errs() << "Could not find main function.\n"; 177 return 1; 178 } 179 180 typedef int (*MainFnPtr)(int, char*[]); 181 auto Main = fromTargetAddress<MainFnPtr>(MainSym.getAddress()); 182 return Main(ArgC, ArgV); 183} 184