From: Reid Kleckner Date: Sat, 18 Jul 2009 00:42:18 +0000 (+0000) Subject: Add EngineBuilder to ExecutionEngine in favor of the five optional argument EE::create(). X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=4b1511b027ce0b648b3379f2891816c25b46f515;hp=016de81177ec5c950f1668be4a48992bc1ee0d75 Add EngineBuilder to ExecutionEngine in favor of the five optional argument EE::create(). Also a test commit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76276 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/bindings/ocaml/executionengine/llvm_executionengine.mli b/bindings/ocaml/executionengine/llvm_executionengine.mli index 17da1dffe55..32e2fdf6545 100644 --- a/bindings/ocaml/executionengine/llvm_executionengine.mli +++ b/bindings/ocaml/executionengine/llvm_executionengine.mli @@ -89,14 +89,14 @@ module ExecutionEngine: sig module provider [mp] if successful. Creates a JIT if possible, else falls back to an interpreter. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with - [dispose ee]. See the function [llvm::ExecutionEngine::create]. *) + [dispose ee]. See the function [llvm::EngineBuilder::create]. *) val create: Llvm.llmoduleprovider -> t (** [create_interpreter mp] creates a new interpreter, taking ownership of the module provider [mp] if successful. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. - See the function [llvm::ExecutionEngine::create]. *) + See the function [llvm::EngineBuilder::create]. *) val create_interpreter: Llvm.llmoduleprovider -> t (** [create_jit mp] creates a new JIT (just-in-time compiler), taking @@ -104,7 +104,7 @@ module ExecutionEngine: sig a JIT which favors code quality over compilation speed. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. - See the function [llvm::ExecutionEngine::create]. *) + See the function [llvm::EngineBuilder::create]. *) val create_jit: Llvm.llmoduleprovider -> t (** [create_fast_jit mp] creates a new JIT (just-in-time compiler) which @@ -112,7 +112,7 @@ module ExecutionEngine: sig module provider [mp] if successful. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. - See the function [llvm::ExecutionEngine::create]. *) + See the function [llvm::EngineBuilder::create]. *) val create_fast_jit: Llvm.llmoduleprovider -> t (** [dispose ee] releases the memory used by the execution engine and must be diff --git a/docs/CMake.html b/docs/CMake.html index 1f50d397f00..2d4f4ef8c88 100644 --- a/docs/CMake.html +++ b/docs/CMake.html @@ -352,7 +352,7 @@

to your linker options. This is required for adding the relevant LLVM object code to the executable. Not doing this will result on - some methods returning NULL (ExecutionEngine::create, for + some methods returning NULL (EngineBuilder::create, for instance).

diff --git a/docs/tutorial/LangImpl4.html b/docs/tutorial/LangImpl4.html index ca5968273e1..41f3a2cd85e 100644 --- a/docs/tutorial/LangImpl4.html +++ b/docs/tutorial/LangImpl4.html @@ -299,7 +299,7 @@ by adding a global variable and a call in main:

int main() { .. // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); .. } @@ -1078,7 +1078,7 @@ int main() { TheModule = new Module("my cool jit", getGlobalContext()); // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); { ExistingModuleProvider OurModuleProvider(TheModule); diff --git a/docs/tutorial/LangImpl5.html b/docs/tutorial/LangImpl5.html index cad05f70454..5f50cb28c5b 100644 --- a/docs/tutorial/LangImpl5.html +++ b/docs/tutorial/LangImpl5.html @@ -1712,7 +1712,7 @@ int main() { TheModule = new Module("my cool jit", getGlobalContext()); // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); { ExistingModuleProvider OurModuleProvider(TheModule); diff --git a/docs/tutorial/LangImpl6.html b/docs/tutorial/LangImpl6.html index b10a15f6353..9fffb53398b 100644 --- a/docs/tutorial/LangImpl6.html +++ b/docs/tutorial/LangImpl6.html @@ -1751,7 +1751,7 @@ int main() { TheModule = new Module("my cool jit", getGlobalContext()); // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); { ExistingModuleProvider OurModuleProvider(TheModule); diff --git a/docs/tutorial/LangImpl7.html b/docs/tutorial/LangImpl7.html index 9424223fd77..27a30f73439 100644 --- a/docs/tutorial/LangImpl7.html +++ b/docs/tutorial/LangImpl7.html @@ -2103,7 +2103,7 @@ int main() { TheModule = new Module("my cool jit", getGlobalContext()); // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); { ExistingModuleProvider OurModuleProvider(TheModule); diff --git a/examples/BrainF/BrainFDriver.cpp b/examples/BrainF/BrainFDriver.cpp index 021b9510ce4..fba79cfbd55 100644 --- a/examples/BrainF/BrainFDriver.cpp +++ b/examples/BrainF/BrainFDriver.cpp @@ -141,8 +141,7 @@ int main(int argc, char **argv) { InitializeNativeTarget(); std::cout << "------- Running JIT -------\n"; - ExistingModuleProvider *mp = new ExistingModuleProvider(mod); - ExecutionEngine *ee = ExecutionEngine::create(mp, false); + ExecutionEngine *ee = EngineBuilder(mod).create(); std::vector args; Function *brainf_func = mod->getFunction("brainf"); GenericValue gv = ee->runFunction(brainf_func, args); diff --git a/examples/Fibonacci/fibonacci.cpp b/examples/Fibonacci/fibonacci.cpp index d637d4dea17..c5c8f0de89e 100644 --- a/examples/Fibonacci/fibonacci.cpp +++ b/examples/Fibonacci/fibonacci.cpp @@ -100,8 +100,7 @@ int main(int argc, char **argv) { Function *FibF = CreateFibFunction(M, Context); // Now we going to create JIT - ExistingModuleProvider *MP = new ExistingModuleProvider(M); - ExecutionEngine *EE = ExecutionEngine::create(MP, false); + ExecutionEngine *EE = EngineBuilder(M).create(); errs() << "verifying... "; if (verifyModule(*M)) { diff --git a/examples/HowToUseJIT/HowToUseJIT.cpp b/examples/HowToUseJIT/HowToUseJIT.cpp index 6d43cb47ced..8a788491fd1 100644 --- a/examples/HowToUseJIT/HowToUseJIT.cpp +++ b/examples/HowToUseJIT/HowToUseJIT.cpp @@ -104,8 +104,7 @@ int main() { ReturnInst::Create(Add1CallRes, BB); // Now we create the JIT. - ExistingModuleProvider* MP = new ExistingModuleProvider(M); - ExecutionEngine* EE = ExecutionEngine::create(MP, false); + ExecutionEngine* EE = EngineBuilder(M).create(); outs() << "We just constructed this LLVM module:\n\n" << *M; outs() << "\n\nRunning foo: "; diff --git a/examples/Kaleidoscope/toy.cpp b/examples/Kaleidoscope/toy.cpp index 4fd80a93634..abcd412f077 100644 --- a/examples/Kaleidoscope/toy.cpp +++ b/examples/Kaleidoscope/toy.cpp @@ -1103,7 +1103,7 @@ int main() { TheModule = new Module("my cool jit", Context); // Create the JIT. - TheExecutionEngine = ExecutionEngine::create(TheModule); + TheExecutionEngine = EngineBuilder(TheModule).create(); { ExistingModuleProvider OurModuleProvider(TheModule); @@ -1138,4 +1138,3 @@ int main() { return 0; } - diff --git a/examples/ParallelJIT/ParallelJIT.cpp b/examples/ParallelJIT/ParallelJIT.cpp index d82a6be81db..464bd22e8ff 100644 --- a/examples/ParallelJIT/ParallelJIT.cpp +++ b/examples/ParallelJIT/ParallelJIT.cpp @@ -242,8 +242,7 @@ int main() { Function* fibF = CreateFibFunction( M ); // Now we create the JIT. - ExistingModuleProvider* MP = new ExistingModuleProvider(M); - ExecutionEngine* EE = ExecutionEngine::create(MP, false); + ExecutionEngine* EE = EngineBuilder(M).create(); //~ std::cout << "We just constructed this LLVM module:\n\n" << *M; //~ std::cout << "\n\nRunning foo: " << std::flush; diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index cb24d916fc0..1dc9d1dee5e 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -71,6 +71,8 @@ class ExecutionEngine { bool SymbolSearchingDisabled; bool DlsymStubsEnabled; + friend class EngineBuilder; // To allow access to JITCtor and InterpCtor. + protected: /// Modules - This is a list of ModuleProvider's that we are JIT'ing from. We /// use a smallvector to optimize for the case where there is only one module. @@ -86,10 +88,13 @@ protected: // To avoid having libexecutionengine depend on the JIT and interpreter // libraries, the JIT and Interpreter set these functions to ctor pointers // at startup time if they are linked in. - typedef ExecutionEngine *(*EECtorFn)(ModuleProvider*, std::string*, - CodeGenOpt::Level OptLevel, - bool GVsWithCode); - static EECtorFn JITCtor, InterpCtor; + static ExecutionEngine *(*JITCtor)(ModuleProvider *MP, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode); + static ExecutionEngine *(*InterpCtor)(ModuleProvider *MP, + std::string *ErrorStr); /// LazyFunctionCreator - If an unknown function is needed, this function /// pointer is invoked to create it. If this returns null, the JIT will abort. @@ -372,6 +377,96 @@ protected: const Type *Ty); }; +namespace EngineKind { + // These are actually bitmasks that get or-ed together. + enum Kind { + JIT = 0x1, + Interpreter = 0x2 + }; + const static Kind Either = (Kind)(JIT | Interpreter); +} + +/// EngineBuilder - Builder class for ExecutionEngines. Use this by +/// stack-allocating a builder, chaining the various set* methods, and +/// terminating it with a .create() call. +class EngineBuilder { + + private: + ModuleProvider *MP; + EngineKind::Kind WhichEngine; + std::string *ErrorStr; + CodeGenOpt::Level OptLevel; + JITMemoryManager *JMM; + bool AllocateGVsWithCode; + + /// InitEngine - Does the common initialization of default options. + /// + void InitEngine() { + WhichEngine = EngineKind::Either; + ErrorStr = NULL; + OptLevel = CodeGenOpt::Default; + JMM = NULL; + AllocateGVsWithCode = false; + } + + public: + /// EngineBuilder - Constructor for EngineBuilder. If create() is called and + /// is successful, the created engine takes ownership of the module + /// provider. + EngineBuilder(ModuleProvider *mp) : MP(mp) { + InitEngine(); + } + + /// EngineBuilder - Overloaded constructor that automatically creates an + /// ExistingModuleProvider for an existing module. + EngineBuilder(Module *m); + + /// setEngineKind - Controls whether the user wants the interpreter, the JIT, + /// or whichever engine works. This option defaults to EngineKind::Either. + EngineBuilder &setEngineKind(EngineKind::Kind w) { + WhichEngine = w; + return *this; + } + + /// setJITMemoryManager - Sets the memory manager to use. This allows + /// clients to customize their memory allocation policies. If create() is + /// called and is successful, the created engine takes ownership of the + /// memory manager. This option defaults to NULL. + EngineBuilder &setJITMemoryManager(JITMemoryManager *jmm) { + JMM = jmm; + return *this; + } + + /// setErrorStr - Set the error string to write to on error. This option + /// defaults to NULL. + EngineBuilder &setErrorStr(std::string *e) { + ErrorStr = e; + return *this; + } + + /// setOptLevel - Set the optimization level for the JIT. This option + /// defaults to CodeGenOpt::Default. + EngineBuilder &setOptLevel(CodeGenOpt::Level l) { + OptLevel = l; + return *this; + } + + /// setAllocateGVsWithCode - Sets whether global values should be allocated + /// into the same buffer as code. For most applications this should be set + /// to false. Allocating globals with code breaks freeMachineCodeForFunction + /// and is probably unsafe and bad for performance. However, we have clients + /// who depend on this behavior, so we must support it. This option defaults + /// to false so that users of the new API can safely use the new memory + /// manager and free machine code. + EngineBuilder &setAllocateGVsWithCode(bool a) { + AllocateGVsWithCode = a; + return *this; + } + + ExecutionEngine *create(); + +}; + } // End llvm namespace #endif diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 9f27338195a..ee4b0b232f5 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -35,8 +35,13 @@ using namespace llvm; STATISTIC(NumInitBytes, "Number of bytes of global vars initialized"); STATISTIC(NumGlobals , "Number of global vars initialized"); -ExecutionEngine::EECtorFn ExecutionEngine::JITCtor = 0; -ExecutionEngine::EECtorFn ExecutionEngine::InterpCtor = 0; +ExecutionEngine *(*ExecutionEngine::JITCtor)(ModuleProvider *MP, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode) = 0; +ExecutionEngine *(*ExecutionEngine::InterpCtor)(ModuleProvider *MP, + std::string *ErrorStr) = 0; ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0; @@ -382,26 +387,60 @@ ExecutionEngine *ExecutionEngine::create(ModuleProvider *MP, std::string *ErrorStr, CodeGenOpt::Level OptLevel, bool GVsWithCode) { - ExecutionEngine *EE = 0; + return EngineBuilder(MP) + .setEngineKind(ForceInterpreter + ? EngineKind::Interpreter + : EngineKind::JIT) + .setErrorStr(ErrorStr) + .setOptLevel(OptLevel) + .setAllocateGVsWithCode(GVsWithCode) + .create(); +} + +ExecutionEngine *ExecutionEngine::create(Module *M) { + return EngineBuilder(M).create(); +} +/// EngineBuilder - Overloaded constructor that automatically creates an +/// ExistingModuleProvider for an existing module. +EngineBuilder::EngineBuilder(Module *m) : MP(new ExistingModuleProvider(m)) { + InitEngine(); +} + +ExecutionEngine *EngineBuilder::create() { // Make sure we can resolve symbols in the program as well. The zero arg // to the function tells DynamicLibrary to load the program, not a library. if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr)) return 0; - // Unless the interpreter was explicitly selected, try making a JIT. - if (!ForceInterpreter && JITCtor) - EE = JITCtor(MP, ErrorStr, OptLevel, GVsWithCode); + // If the user specified a memory manager but didn't specify which engine to + // create, we assume they only want the JIT, and we fail if they only want + // the interpreter. + if (JMM) { + if (WhichEngine & EngineKind::JIT) { + WhichEngine = EngineKind::JIT; + } else { + *ErrorStr = "Cannot create an interpreter with a memory manager."; + } + } - // If we can't make a JIT, make an interpreter instead. - if (EE == 0 && InterpCtor) - EE = InterpCtor(MP, ErrorStr, OptLevel, GVsWithCode); + ExecutionEngine *EE = 0; - return EE; -} + // Unless the interpreter was explicitly selected or the JIT is not linked, + // try making a JIT. + if (WhichEngine & EngineKind::JIT && ExecutionEngine::JITCtor) { + EE = ExecutionEngine::JITCtor(MP, ErrorStr, JMM, OptLevel, + AllocateGVsWithCode); + } -ExecutionEngine *ExecutionEngine::create(Module *M) { - return create(new ExistingModuleProvider(M)); + // If we can't make a JIT and we didn't request one specifically, try making + // an interpreter instead. + if (WhichEngine & EngineKind::Interpreter && EE == 0 && + ExecutionEngine::InterpCtor) { + EE = ExecutionEngine::InterpCtor(MP, ErrorStr); + } + + return EE; } /// getPointerToGlobal - This returns the address of the specified global diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp index 4ee26229420..5901cd757dc 100644 --- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp +++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp @@ -91,7 +91,10 @@ int LLVMCreateExecutionEngine(LLVMExecutionEngineRef *OutEE, LLVMModuleProviderRef MP, char **OutError) { std::string Error; - if (ExecutionEngine *EE = ExecutionEngine::create(unwrap(MP), false, &Error)){ + EngineBuilder builder(unwrap(MP)); + builder.setEngineKind(EngineKind::Either) + .setErrorStr(&Error); + if (ExecutionEngine *EE = builder.create()){ *OutEE = wrap(EE); return 0; } @@ -103,8 +106,10 @@ int LLVMCreateInterpreter(LLVMExecutionEngineRef *OutInterp, LLVMModuleProviderRef MP, char **OutError) { std::string Error; - if (ExecutionEngine *Interp = - ExecutionEngine::create(unwrap(MP), true, &Error)) { + EngineBuilder builder(unwrap(MP)); + builder.setEngineKind(EngineKind::Interpreter) + .setErrorStr(&Error); + if (ExecutionEngine *Interp = builder.create()) { *OutInterp = wrap(Interp); return 0; } @@ -117,9 +122,11 @@ int LLVMCreateJITCompiler(LLVMExecutionEngineRef *OutJIT, unsigned OptLevel, char **OutError) { std::string Error; - if (ExecutionEngine *JIT = - ExecutionEngine::create(unwrap(MP), false, &Error, - (CodeGenOpt::Level)OptLevel)) { + EngineBuilder builder(unwrap(MP)); + builder.setEngineKind(EngineKind::JIT) + .setErrorStr(&Error) + .setOptLevel((CodeGenOpt::Level)OptLevel); + if (ExecutionEngine *JIT = builder.create()) { *OutJIT = wrap(JIT); return 0; } diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.cpp b/lib/ExecutionEngine/Interpreter/Interpreter.cpp index 902f6768dc8..9be6a9265d6 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.cpp +++ b/lib/ExecutionEngine/Interpreter/Interpreter.cpp @@ -33,9 +33,7 @@ extern "C" void LLVMLinkInInterpreter() { } /// create - Create a new interpreter object. This can never fail. /// -ExecutionEngine *Interpreter::create(ModuleProvider *MP, std::string* ErrStr, - CodeGenOpt::Level OptLevel, /*unused*/ - bool GVsWithCode /* unused */) { +ExecutionEngine *Interpreter::create(ModuleProvider *MP, std::string* ErrStr) { // Tell this ModuleProvide to materialize and release the module if (!MP->materializeModule(ErrStr)) // We got an error, just return 0 diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index 01771cfe9eb..10e53e9a143 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -108,9 +108,7 @@ public: /// create - Create an interpreter ExecutionEngine. This can never fail. /// - static ExecutionEngine *create(ModuleProvider *M, std::string *ErrorStr = 0, - CodeGenOpt::Level = CodeGenOpt::Default, - bool GVsWithCode = true); + static ExecutionEngine *create(ModuleProvider *M, std::string *ErrorStr = 0); /// run - Start execution with the specified function and arguments. /// diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 58ff71b8460..81be38bce51 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -199,14 +199,31 @@ ExecutionEngine *ExecutionEngine::createJIT(ModuleProvider *MP, JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, bool GVsWithCode) { - ExecutionEngine *EE = JIT::createJIT(MP, ErrorStr, JMM, OptLevel, - GVsWithCode); - if (!EE) return 0; - + return JIT::createJIT(MP, ErrorStr, JMM, OptLevel, GVsWithCode); +} + +ExecutionEngine *JIT::createJIT(ModuleProvider *MP, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode) { // Make sure we can resolve symbols in the program as well. The zero arg // to the function tells DynamicLibrary to load the program, not a library. - sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr); - return EE; + if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr)) + return 0; + + // Pick a target either via -march or by guessing the native arch. + TargetMachine *TM = JIT::selectTarget(MP, ErrorStr); + if (!TM || (ErrorStr && ErrorStr->length() > 0)) return 0; + + // If the target supports JIT code generation, create a the JIT. + if (TargetJITInfo *TJ = TM->getJITInfo()) { + return new JIT(MP, *TM, *TJ, JMM, OptLevel, GVsWithCode); + } else { + if (ErrorStr) + *ErrorStr = "target does not support JIT code generation"; + return 0; + } } JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji, diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 1ad54f37807..e3ab9e21c9e 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -79,11 +79,13 @@ public: /// create - Create an return a new JIT compiler if there is one available /// for the current target. Otherwise, return null. /// - static ExecutionEngine *create(ModuleProvider *MP, std::string *Err, + static ExecutionEngine *create(ModuleProvider *MP, + std::string *Err, + JITMemoryManager *JMM, CodeGenOpt::Level OptLevel = CodeGenOpt::Default, - bool AllocateGVsWithCode = true) { - return createJIT(MP, Err, 0, OptLevel, AllocateGVsWithCode); + bool GVsWithCode = true) { + return ExecutionEngine::createJIT(MP, Err, JMM, OptLevel, GVsWithCode); } virtual void addModuleProvider(ModuleProvider *MP); @@ -152,18 +154,22 @@ public: /// addPendingFunction - while jitting non-lazily, a called but non-codegen'd /// function was encountered. Add it to a pending list to be processed after /// the current function. - /// + /// void addPendingFunction(Function *F); - + /// getCodeEmitter - Return the code emitter this JIT is emitting into. + /// JITCodeEmitter *getCodeEmitter() const { return JCE; } - + + /// selectTarget - Pick a target either via -march or by guessing the native + /// arch. Add any CPU features specified via -mcpu or -mattr. + static TargetMachine *selectTarget(ModuleProvider *MP, std::string *Err); + static ExecutionEngine *createJIT(ModuleProvider *MP, - std::string *Err, + std::string *ErrorStr, JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, - bool AllocateGVsWithCode); - + bool GVsWithCode); // Run the JIT on F and return information about the generated code void runJITOnFunction(Function *F, MachineCodeInfo *MCI = 0); diff --git a/lib/ExecutionEngine/JIT/TargetSelect.cpp b/lib/ExecutionEngine/JIT/TargetSelect.cpp index 598b867a3f9..2b80e7e2bd1 100644 --- a/lib/ExecutionEngine/JIT/TargetSelect.cpp +++ b/lib/ExecutionEngine/JIT/TargetSelect.cpp @@ -38,13 +38,9 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); -/// createInternal - Create an return a new JIT compiler if there is one -/// available for the current target. Otherwise, return null. -/// -ExecutionEngine *JIT::createJIT(ModuleProvider *MP, std::string *ErrorStr, - JITMemoryManager *JMM, - CodeGenOpt::Level OptLevel, - bool AllocateGVsWithCode) { +/// selectTarget - Pick a target either via -march or by guessing the native +/// arch. Add any CPU features specified via -mcpu or -mattr. +TargetMachine *JIT::selectTarget(ModuleProvider *MP, std::string *ErrorStr) { const Target *TheTarget = 0; if (MArch.empty()) { std::string Error; @@ -90,12 +86,5 @@ ExecutionEngine *JIT::createJIT(ModuleProvider *MP, std::string *ErrorStr, TargetMachine *Target = TheTarget->createTargetMachine(*MP->getModule(), FeaturesStr); assert(Target && "Could not allocate target machine!"); - - // If the target supports JIT code generation, return a new JIT now. - if (TargetJITInfo *TJ = Target->getJITInfo()) - return new JIT(MP, *Target, *TJ, JMM, OptLevel, AllocateGVsWithCode); - - if (ErrorStr) - *ErrorStr = "target does not support JIT code generation"; - return 0; + return Target; } diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 8afdbcad95b..12f91558247 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -131,6 +131,12 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } + EngineBuilder builder(MP); + builder.setErrorStr(&ErrorMsg) + .setEngineKind(ForceInterpreter + ? EngineKind::Interpreter + : EngineKind::JIT); + // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) Mod->setTargetTriple(TargetTriple); @@ -146,8 +152,9 @@ int main(int argc, char **argv, char * const *envp) { case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } - - EE = ExecutionEngine::create(MP, ForceInterpreter, &ErrorMsg, OLvl); + builder.setOptLevel(OLvl); + + EE = builder.create(); if (!EE) { if (!ErrorMsg.empty()) errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n"; diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp index 8fa5c4c107d..7e2104ef8e0 100644 --- a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp @@ -66,7 +66,9 @@ class JITEventListenerTest : public testing::Test { protected: JITEventListenerTest() : M(new Module("module", getGlobalContext())), - EE(ExecutionEngine::createJIT(new ExistingModuleProvider(M))) { + EE(EngineBuilder(M) + .setEngineToCreate(EngineBuilder::ENG_JIT) + .create()) { } Module *M; @@ -232,7 +234,7 @@ TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) { class JITEnvironment : public testing::Environment { virtual void SetUp() { - // Required for ExecutionEngine::createJIT to create a JIT. + // Required to create a JIT. InitializeNativeTarget(); } }; diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index 211b6adf47d..b46ff8adf63 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -1,4 +1,4 @@ -//===- JITEmitter.cpp - Unit tests for the JIT code emitter ---------------===// +//===- JITTest.cpp - Unit tests for the JIT -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -18,6 +18,7 @@ #include "llvm/Function.h" #include "llvm/GlobalValue.h" #include "llvm/GlobalVariable.h" +#include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/Support/IRBuilder.h" @@ -60,12 +61,13 @@ TEST(JIT, GlobalInFunction) { // memory is more easily tested. MemMgr->setPoisonMemory(true); std::string Error; - OwningPtr JIT(ExecutionEngine::createJIT( - MP, - &Error, - MemMgr, - CodeGenOpt::Default, - false)); // This last argument enables the fix. + OwningPtr JIT(EngineBuilder(MP) + .setEnginePreference(EngineBuilder::JITONLY) + .setErrorStr(&Error) + .setJITMemoryManager(MemMgr) + // The next line enables the fix: + .setAllocateGVsWithCode(false) + .create()); ASSERT_EQ(Error, ""); // Create a global variable. @@ -115,11 +117,12 @@ TEST(JIT, GlobalInFunction) { EXPECT_EQ(3, *GPtr); } -// TODO(rnk): This seems to only run once for both tests, which is unexpected. -// That works just fine, but we shouldn't duplicate the code. +// This code is copied from JITEventListenerTest, but it only runs once for all +// the tests in this directory. Everything seems fine, but that's strange +// behavior. class JITEnvironment : public testing::Environment { virtual void SetUp() { - // Required for ExecutionEngine::createJIT to create a JIT. + // Required to create a JIT. InitializeNativeTarget(); } };