| //===--------------- OrcCAPITest.cpp - Unit tests Orc C API ---------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "OrcTestCommon.h" |
| #include "llvm/ExecutionEngine/Orc/CompileUtils.h" |
| #include "llvm-c/Core.h" |
| #include "llvm-c/OrcBindings.h" |
| #include "llvm-c/Target.h" |
| #include "llvm-c/TargetMachine.h" |
| #include "gtest/gtest.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| namespace llvm { |
| |
| DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) |
| |
| class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest { |
| protected: |
| std::unique_ptr<Module> createTestModule(const Triple &TT) { |
| ModuleBuilder MB(Context, TT.str(), ""); |
| Function *TestFunc = MB.createFunctionDecl<int()>("testFunc"); |
| Function *Main = MB.createFunctionDecl<int(int, char*[])>("main"); |
| |
| Main->getBasicBlockList().push_back(BasicBlock::Create(Context)); |
| IRBuilder<> B(&Main->back()); |
| Value* Result = B.CreateCall(TestFunc); |
| B.CreateRet(Result); |
| |
| return MB.takeModule(); |
| } |
| |
| std::unique_ptr<MemoryBuffer> createTestObject() { |
| orc::SimpleCompiler IRCompiler(*TM); |
| auto M = createTestModule(TM->getTargetTriple()); |
| M->setDataLayout(TM->createDataLayout()); |
| return IRCompiler(*M); |
| } |
| |
| typedef int (*MainFnTy)(); |
| |
| static int myTestFuncImpl() { |
| return 42; |
| } |
| |
| static char *testFuncName; |
| |
| static uint64_t myResolver(const char *Name, void *Ctx) { |
| if (!strncmp(Name, testFuncName, 8)) |
| return (uint64_t)&myTestFuncImpl; |
| return 0; |
| } |
| |
| struct CompileContext { |
| CompileContext() : Compiled(false) { } |
| |
| OrcCAPIExecutionTest* APIExecTest; |
| std::unique_ptr<Module> M; |
| LLVMOrcModuleHandle H; |
| bool Compiled; |
| }; |
| |
| static LLVMOrcTargetAddress myCompileCallback(LLVMOrcJITStackRef JITStack, |
| void *Ctx) { |
| CompileContext *CCtx = static_cast<CompileContext*>(Ctx); |
| auto *ET = CCtx->APIExecTest; |
| CCtx->M = ET->createTestModule(ET->TM->getTargetTriple()); |
| LLVMOrcAddEagerlyCompiledIR(JITStack, &CCtx->H, wrap(CCtx->M.release()), |
| myResolver, nullptr); |
| CCtx->Compiled = true; |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddress(JITStack, &MainAddr, "main"); |
| LLVMOrcSetIndirectStubPointer(JITStack, "foo", MainAddr); |
| return MainAddr; |
| } |
| }; |
| |
| char *OrcCAPIExecutionTest::testFuncName = nullptr; |
| |
| TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) { |
| if (!SupportsJIT) |
| return; |
| |
| LLVMOrcJITStackRef JIT = |
| LLVMOrcCreateInstance(wrap(TM.get())); |
| |
| std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple()); |
| |
| LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); |
| |
| LLVMOrcModuleHandle H; |
| LLVMOrcAddEagerlyCompiledIR(JIT, &H, wrap(M.release()), myResolver, nullptr); |
| |
| // get symbol address searching the entire stack |
| { |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); |
| MainFnTy MainFn = (MainFnTy)MainAddr; |
| int Result = MainFn(); |
| EXPECT_EQ(Result, 42) |
| << "Eagerly JIT'd code did not return expected result"; |
| } |
| |
| // and then just searching a single handle |
| { |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddressIn(JIT, &MainAddr, H, "main"); |
| MainFnTy MainFn = (MainFnTy)MainAddr; |
| int Result = MainFn(); |
| EXPECT_EQ(Result, 42) |
| << "Eagerly JIT'd code did not return expected result"; |
| } |
| |
| LLVMOrcRemoveModule(JIT, H); |
| |
| LLVMOrcDisposeMangledSymbol(testFuncName); |
| LLVMOrcDisposeInstance(JIT); |
| } |
| |
| TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) { |
| if (!SupportsIndirection) |
| return; |
| |
| LLVMOrcJITStackRef JIT = |
| LLVMOrcCreateInstance(wrap(TM.get())); |
| |
| std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple()); |
| |
| LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); |
| |
| LLVMOrcModuleHandle H; |
| LLVMOrcAddLazilyCompiledIR(JIT, &H, wrap(M.release()), myResolver, nullptr); |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); |
| MainFnTy MainFn = (MainFnTy)MainAddr; |
| int Result = MainFn(); |
| EXPECT_EQ(Result, 42) |
| << "Lazily JIT'd code did not return expected result"; |
| |
| LLVMOrcRemoveModule(JIT, H); |
| |
| LLVMOrcDisposeMangledSymbol(testFuncName); |
| LLVMOrcDisposeInstance(JIT); |
| } |
| |
| TEST_F(OrcCAPIExecutionTest, TestAddObjectFile) { |
| if (!SupportsJIT) |
| return; |
| |
| auto ObjBuffer = createTestObject(); |
| |
| LLVMOrcJITStackRef JIT = |
| LLVMOrcCreateInstance(wrap(TM.get())); |
| LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); |
| |
| LLVMOrcModuleHandle H; |
| LLVMOrcAddObjectFile(JIT, &H, wrap(ObjBuffer.release()), myResolver, nullptr); |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); |
| MainFnTy MainFn = (MainFnTy)MainAddr; |
| int Result = MainFn(); |
| EXPECT_EQ(Result, 42) |
| << "Lazily JIT'd code did not return expected result"; |
| |
| LLVMOrcRemoveModule(JIT, H); |
| |
| LLVMOrcDisposeMangledSymbol(testFuncName); |
| LLVMOrcDisposeInstance(JIT); |
| } |
| |
| TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) { |
| if (!SupportsIndirection) |
| return; |
| |
| LLVMOrcJITStackRef JIT = |
| LLVMOrcCreateInstance(wrap(TM.get())); |
| |
| LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); |
| |
| CompileContext C; |
| C.APIExecTest = this; |
| LLVMOrcTargetAddress CCAddr; |
| LLVMOrcCreateLazyCompileCallback(JIT, &CCAddr, myCompileCallback, &C); |
| LLVMOrcCreateIndirectStub(JIT, "foo", CCAddr); |
| LLVMOrcTargetAddress MainAddr; |
| LLVMOrcGetSymbolAddress(JIT, &MainAddr, "foo"); |
| MainFnTy FooFn = (MainFnTy)MainAddr; |
| int Result = FooFn(); |
| EXPECT_TRUE(C.Compiled) |
| << "Function wasn't lazily compiled"; |
| EXPECT_EQ(Result, 42) |
| << "Direct-callback JIT'd code did not return expected result"; |
| |
| C.Compiled = false; |
| FooFn(); |
| EXPECT_FALSE(C.Compiled) |
| << "Direct-callback JIT'd code was JIT'd twice"; |
| |
| LLVMOrcRemoveModule(JIT, C.H); |
| |
| LLVMOrcDisposeMangledSymbol(testFuncName); |
| LLVMOrcDisposeInstance(JIT); |
| } |
| |
| } // namespace llvm |