//===----------------------------------------------------------------------===//
#include "llvm/IR/LLVMContext.h"
+#include "OrcLazyJIT.h"
#include "RemoteMemoryManager.h"
#include "RemoteTarget.h"
#include "RemoteTargetExternal.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
-#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
+#include "llvm/ExecutionEngine/OrcMCJITReplacement.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#define DEBUG_TYPE "lli"
namespace {
+
+ enum class JITKind { MCJIT, OrcMCJITReplacement, OrcLazy };
+
cl::opt<std::string>
InputFile(cl::desc("<input bitcode>"), cl::Positional, cl::init("-"));
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
- cl::opt<bool> UseMCJIT(
- "use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"),
- cl::init(false));
-
- cl::opt<bool> DebugIR(
- "debug-ir", cl::desc("Generate debug information to allow debugging IR."),
- cl::init(false));
+ cl::opt<JITKind> UseJITKind("jit-kind",
+ cl::desc("Choose underlying JIT kind."),
+ cl::init(JITKind::MCJIT),
+ cl::values(
+ clEnumValN(JITKind::MCJIT, "mcjit",
+ "MCJIT"),
+ clEnumValN(JITKind::OrcMCJITReplacement,
+ "orc-mcjit",
+ "Orc-based MCJIT replacement"),
+ clEnumValN(JITKind::OrcLazy,
+ "orc-lazy",
+ "Orc-based lazy JIT."),
+ clEnumValEnd));
// The MCJIT supports building for a target address space separate from
// the JIT compilation process. Use a forked process and a copying
clEnumValN(FloatABI::Hard, "hard",
"Hard float ABI (uses FP registers)"),
clEnumValEnd));
- cl::opt<bool>
-// In debug builds, make this default to true.
-#ifdef NDEBUG
-#define EMIT_DEBUG false
-#else
-#define EMIT_DEBUG true
-#endif
- EmitJitDebugInfo("jit-emit-debug",
- cl::desc("Emit debug information to debugger"),
- cl::init(EMIT_DEBUG));
-#undef EMIT_DEBUG
-
- static cl::opt<bool>
- EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
- cl::Hidden,
- cl::desc("Emit debug info objfiles to disk"),
- cl::init(false));
}
//===----------------------------------------------------------------------===//
this->CacheDir[this->CacheDir.size() - 1] != '/')
this->CacheDir += '/';
}
- virtual ~LLIObjectCache() {}
+ ~LLIObjectCache() override {}
void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
const std::string ModuleID = M->getModuleIdentifier();
if (!getCacheFilename(ModuleID, CacheName))
return;
if (!CacheDir.empty()) { // Create user-defined cache dir.
- SmallString<128> dir(CacheName);
- sys::path::remove_filename(dir);
+ SmallString<128> dir(sys::path::parent_path(CacheName));
sys::fs::create_directories(Twine(dir));
}
std::error_code EC;
// because the file has probably just been mmapped. Instead we make
// a copy. The filed-based buffer will be released when it goes
// out of scope.
- return std::unique_ptr<MemoryBuffer>(
- MemoryBuffer::getMemBufferCopy(IRObjectBuffer.get()->getBuffer()));
+ return MemoryBuffer::getMemBufferCopy(IRObjectBuffer.get()->getBuffer());
}
private:
EE->addModule(std::move(M));
}
+CodeGenOpt::Level getOptLevel() {
+ switch (OptLevel) {
+ default:
+ errs() << "lli: Invalid optimization level.\n";
+ exit(1);
+ case '0': return CodeGenOpt::None;
+ case '1': return CodeGenOpt::Less;
+ case ' ':
+ case '2': return CodeGenOpt::Default;
+ case '3': return CodeGenOpt::Aggressive;
+ }
+ llvm_unreachable("Unrecognized opt level.");
+}
//===----------------------------------------------------------------------===//
// main Driver function
// Load the bitcode...
SMDiagnostic Err;
- std::unique_ptr<Module> Owner(ParseIRFile(InputFile, Err, Context));
+ std::unique_ptr<Module> Owner = parseIRFile(InputFile, Err, Context);
Module *Mod = Owner.get();
if (!Mod) {
Err.print(argv[0], errs());
return 1;
}
+ if (UseJITKind == JITKind::OrcLazy)
+ return runOrcLazyJIT(std::move(Owner), argc, argv);
+
if (EnableCacheManager) {
- if (UseMCJIT) {
- std::string CacheName("file:");
- CacheName.append(InputFile);
- Mod->setModuleIdentifier(CacheName);
- } else
- errs() << "warning: -enable-cache-manager can only be used with MCJIT.";
+ std::string CacheName("file:");
+ CacheName.append(InputFile);
+ Mod->setModuleIdentifier(CacheName);
}
// If not jitting lazily, load the whole bitcode file eagerly too.
}
}
- if (DebugIR) {
- if (!UseMCJIT) {
- errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug"
- << " information will be emitted by the non-MC JIT engine. To see full"
- << " source debug information, enable the flag '-use-mcjit'.\n";
-
- }
- ModulePass *DebugIRPass = createDebugIRPass();
- DebugIRPass->runOnModule(*Mod);
- }
-
std::string ErrorMsg;
EngineBuilder builder(std::move(Owner));
builder.setMArch(MArch);
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
: EngineKind::JIT);
+ builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement);
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
// Enable MCJIT if desired.
RTDyldMemoryManager *RTDyldMM = nullptr;
- if (UseMCJIT && !ForceInterpreter) {
- builder.setUseMCJIT(true);
+ if (!ForceInterpreter) {
if (RemoteMCJIT)
RTDyldMM = new RemoteMemoryManager();
else
RTDyldMM = new SectionMemoryManager();
- builder.setMCJITMemoryManager(RTDyldMM);
- } else {
- if (RemoteMCJIT) {
- errs() << "error: Remote process execution requires -use-mcjit\n";
- exit(1);
- }
- builder.setJITMemoryManager(ForceInterpreter ? nullptr :
- JITMemoryManager::CreateDefaultMemManager());
- }
- CodeGenOpt::Level OLvl = CodeGenOpt::Default;
- switch (OptLevel) {
- default:
- errs() << argv[0] << ": invalid optimization level.\n";
- return 1;
- case ' ': break;
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
+ // Deliberately construct a temp std::unique_ptr to pass in. Do not null out
+ // RTDyldMM: We still use it below, even though we don't own it.
+ builder.setMCJITMemoryManager(
+ std::unique_ptr<RTDyldMemoryManager>(RTDyldMM));
+ } else if (RemoteMCJIT) {
+ errs() << "error: Remote process execution does not work with the "
+ "interpreter.\n";
+ exit(1);
}
- builder.setOptLevel(OLvl);
+
+ builder.setOptLevel(getOptLevel());
TargetOptions Options;
- Options.UseSoftFloat = GenerateSoftFloatCalls;
if (FloatABIForCalls != FloatABI::Default)
Options.FloatABIType = FloatABIForCalls;
- if (GenerateSoftFloatCalls)
- FloatABIForCalls = FloatABI::Soft;
-
- // Remote target execution doesn't handle EH or debug registration.
- if (!RemoteMCJIT) {
- Options.JITEmitDebugInfo = EmitJitDebugInfo;
- Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
- }
builder.setTargetOptions(Options);
// Load any additional modules specified on the command line.
for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) {
- std::unique_ptr<Module> XMod(ParseIRFile(ExtraModules[i], Err, Context));
+ std::unique_ptr<Module> XMod = parseIRFile(ExtraModules[i], Err, Context);
if (!XMod) {
Err.print(argv[0], errs());
return 1;
}
if (EnableCacheManager) {
- if (UseMCJIT) {
- std::string CacheName("file:");
- CacheName.append(ExtraModules[i]);
- XMod->setModuleIdentifier(CacheName);
- }
- // else, we already printed a warning above.
+ std::string CacheName("file:");
+ CacheName.append(ExtraModules[i]);
+ XMod->setModuleIdentifier(CacheName);
}
EE->addModule(std::move(XMod));
}
- std::vector<std::unique_ptr<MemoryBuffer>> Buffers;
for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) {
ErrorOr<object::OwningBinary<object::ObjectFile>> Obj =
object::ObjectFile::createObjectFile(ExtraObjects[i]);
return 1;
}
object::OwningBinary<object::ObjectFile> &O = Obj.get();
- EE->addObjectFile(std::move(O.getBinary()));
- Buffers.push_back(std::move(O.getBuffer()));
+ EE->addObjectFile(std::move(O));
}
for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) {
// If the user specifically requested an argv[0] to pass into the program,
// do it now.
if (!FakeArgv0.empty()) {
- InputFile = FakeArgv0;
+ InputFile = static_cast<std::string>(FakeArgv0);
} else {
// Otherwise, if there is a .bc suffix on the executable strip it off, it
// might confuse the program.
// function later on to make an explicit call, so get the function now.
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
Type::getInt32Ty(Context),
- NULL);
+ nullptr);
// Run static constructors.
- if (UseMCJIT && !ForceInterpreter) {
+ if (!ForceInterpreter) {
// Give MCJIT a chance to apply relocations and set page permissions.
EE->finalizeObject();
}
EE->runStaticConstructorsDestructors(false);
- if (!UseMCJIT && NoLazyCompilation) {
- for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
- Function *Fn = &*I;
- if (Fn != EntryFn && !Fn->isDeclaration())
- EE->getPointerToFunction(Fn);
- }
- }
-
// Trigger compilation separately so code regions that need to be
// invalidated will be known.
(void)EE->getPointerToFunction(EntryFn);