From d0838f887a929c2c98f85ad874cfda20d60d47e2 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 14 Jul 2015 22:11:10 +0000 Subject: [PATCH] [ExecutionEngine] Re-apply r241962 with fixes for ARM. Patch by Pierre-Andre Saulais. Thanks Pierre-Andre! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242213 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/ExecutionEngine/ExecutionEngine.h | 9 +- unittests/ExecutionEngine/MCJIT/MCJITTest.cpp | 82 +++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index e8af601d83b..821c0181ce8 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace llvm { @@ -89,6 +90,8 @@ public: uint64_t RemoveMapping(StringRef Name); }; +using FunctionCreator = std::function; + /// \brief Abstract interface for implementation execution of LLVM modules, /// designed to support both interpreter and just-in-time (JIT) compiler /// implementations. @@ -147,7 +150,7 @@ protected: /// LazyFunctionCreator - If an unknown function is needed, this function /// pointer is invoked to create it. If this returns null, the JIT will /// abort. - void *(*LazyFunctionCreator)(const std::string &); + FunctionCreator LazyFunctionCreator; /// getMangledName - Get mangled name. std::string getMangledName(const GlobalValue *GV); @@ -470,8 +473,8 @@ public: /// InstallLazyFunctionCreator - If an unknown function is needed, the /// specified function pointer is invoked to create it. If it returns null, /// the JIT will abort. - void InstallLazyFunctionCreator(void* (*P)(const std::string &)) { - LazyFunctionCreator = P; + void InstallLazyFunctionCreator(FunctionCreator C) { + LazyFunctionCreator = C; } protected: diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index f65ec96d944..01e796d9a4e 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/Support/DynamicLibrary.h" #include "MCJITTestBase.h" #include "gtest/gtest.h" @@ -199,4 +200,85 @@ TEST_F(MCJITTest, multiple_decl_lookups) { EXPECT_EQ(A, B) << "Repeat calls to getPointerToFunction fail."; } +typedef void * (*FunctionHandlerPtr)(const std::string &str); + +TEST_F(MCJITTest, lazy_function_creator_pointer) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *Foo = insertExternalReferenceToFunction(M.get(), + "\1Foo"); + startFunction(M.get(), "Parent"); + CallInst *Call = Builder.CreateCall(Foo, {}); + Builder.CreateRet(Call); + + createJIT(std::move(M)); + + // Set up the lazy function creator that records the name of the last + // unresolved external function found in the module. Using a function pointer + // prevents us from capturing local variables, which is why this is static. + static std::string UnresolvedExternal; + FunctionHandlerPtr UnresolvedHandler = [] (const std::string &str) { + // Try to resolve the function in the current process before marking it as + // unresolved. This solves an issue on ARM where '__aeabi_*' function names + // are passed to this handler. + void *symbol = + llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str()); + if (symbol) { + return symbol; + } + + UnresolvedExternal = str; + return (void *)(uintptr_t)-1; + }; + TheJIT->InstallLazyFunctionCreator(UnresolvedHandler); + + // JIT the module. + TheJIT->finalizeObject(); + + // Verify that our handler was called. + EXPECT_EQ(UnresolvedExternal, "Foo"); +} + +TEST_F(MCJITTest, lazy_function_creator_lambda) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *Foo1 = insertExternalReferenceToFunction(M.get(), + "\1Foo1"); + Function *Foo2 = insertExternalReferenceToFunction(M.get(), + "\1Foo2"); + startFunction(M.get(), "Parent"); + CallInst *Call1 = Builder.CreateCall(Foo1, {}); + CallInst *Call2 = Builder.CreateCall(Foo2, {}); + Value *Result = Builder.CreateAdd(Call1, Call2); + Builder.CreateRet(Result); + + createJIT(std::move(M)); + + // Set up the lazy function creator that records the name of unresolved + // external functions in the module. + std::vector UnresolvedExternals; + auto UnresolvedHandler = [&UnresolvedExternals] (const std::string &str) { + // Try to resolve the function in the current process before marking it as + // unresolved. This solves an issue on ARM where '__aeabi_*' function names + // are passed to this handler. + void *symbol = + llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str()); + if (symbol) { + return symbol; + } + UnresolvedExternals.push_back(str); + return (void *)(uintptr_t)-1; + }; + TheJIT->InstallLazyFunctionCreator(UnresolvedHandler); + + // JIT the module. + TheJIT->finalizeObject(); + + // Verify that our handler was called for each unresolved function. + auto I = UnresolvedExternals.begin(), E = UnresolvedExternals.end(); + EXPECT_EQ(UnresolvedExternals.size(), 2u); + EXPECT_FALSE(std::find(I, E, "Foo1") == E); + EXPECT_FALSE(std::find(I, E, "Foo2") == E); +} + } -- 2.34.1