1 //===--------------- OrcCAPITest.cpp - Unit tests Orc C API ---------------===//
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 "OrcTestCommon.h"
11 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
12 #include "llvm-c/Core.h"
13 #include "llvm-c/OrcBindings.h"
14 #include "llvm-c/Target.h"
15 #include "llvm-c/TargetMachine.h"
16 #include "gtest/gtest.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 namespace llvm {
23
24 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
25
26 class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest {
27 protected:
createTestModule(const Triple & TT)28 std::unique_ptr<Module> createTestModule(const Triple &TT) {
29 ModuleBuilder MB(Context, TT.str(), "");
30 Type *IntTy = Type::getScalarTy<int>(Context);
31 Function *TestFunc =
32 MB.createFunctionDecl(FunctionType::get(IntTy, {}, false), "testFunc");
33 Function *Main = MB.createFunctionDecl(
34 FunctionType::get(
35 IntTy,
36 {IntTy, Type::getInt8PtrTy(Context)->getPointerTo()},
37 false),
38 "main");
39
40 Main->getBasicBlockList().push_back(BasicBlock::Create(Context));
41 IRBuilder<> B(&Main->back());
42 Value* Result = B.CreateCall(TestFunc);
43 B.CreateRet(Result);
44
45 return MB.takeModule();
46 }
47
createTestObject()48 std::unique_ptr<MemoryBuffer> createTestObject() {
49 orc::SimpleCompiler IRCompiler(*TM);
50 auto M = createTestModule(TM->getTargetTriple());
51 M->setDataLayout(TM->createDataLayout());
52 return IRCompiler(*M);
53 }
54
55 typedef int (*MainFnTy)();
56
myTestFuncImpl()57 static int myTestFuncImpl() {
58 return 42;
59 }
60
61 static char *testFuncName;
62
myResolver(const char * Name,void * Ctx)63 static uint64_t myResolver(const char *Name, void *Ctx) {
64 if (!strncmp(Name, testFuncName, 8))
65 return (uint64_t)&myTestFuncImpl;
66 return 0;
67 }
68
69 struct CompileContext {
CompileContextllvm::OrcCAPIExecutionTest::CompileContext70 CompileContext() : Compiled(false) { }
71
72 OrcCAPIExecutionTest* APIExecTest;
73 std::unique_ptr<Module> M;
74 LLVMOrcModuleHandle H;
75 bool Compiled;
76 };
77
myCompileCallback(LLVMOrcJITStackRef JITStack,void * Ctx)78 static LLVMOrcTargetAddress myCompileCallback(LLVMOrcJITStackRef JITStack,
79 void *Ctx) {
80 CompileContext *CCtx = static_cast<CompileContext*>(Ctx);
81 auto *ET = CCtx->APIExecTest;
82 CCtx->M = ET->createTestModule(ET->TM->getTargetTriple());
83 LLVMOrcAddEagerlyCompiledIR(JITStack, &CCtx->H, wrap(CCtx->M.release()),
84 myResolver, nullptr);
85 CCtx->Compiled = true;
86 LLVMOrcTargetAddress MainAddr;
87 LLVMOrcGetSymbolAddress(JITStack, &MainAddr, "main");
88 LLVMOrcSetIndirectStubPointer(JITStack, "foo", MainAddr);
89 return MainAddr;
90 }
91 };
92
93 char *OrcCAPIExecutionTest::testFuncName = nullptr;
94
TEST_F(OrcCAPIExecutionTest,TestEagerIRCompilation)95 TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) {
96 if (!SupportsJIT)
97 return;
98
99 LLVMOrcJITStackRef JIT =
100 LLVMOrcCreateInstance(wrap(TM.get()));
101
102 std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
103
104 LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
105
106 LLVMOrcModuleHandle H;
107 LLVMOrcAddEagerlyCompiledIR(JIT, &H, wrap(M.release()), myResolver, nullptr);
108
109 // get symbol address searching the entire stack
110 {
111 LLVMOrcTargetAddress MainAddr;
112 LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main");
113 MainFnTy MainFn = (MainFnTy)MainAddr;
114 int Result = MainFn();
115 EXPECT_EQ(Result, 42)
116 << "Eagerly JIT'd code did not return expected result";
117 }
118
119 // and then just searching a single handle
120 {
121 LLVMOrcTargetAddress MainAddr;
122 LLVMOrcGetSymbolAddressIn(JIT, &MainAddr, H, "main");
123 MainFnTy MainFn = (MainFnTy)MainAddr;
124 int Result = MainFn();
125 EXPECT_EQ(Result, 42)
126 << "Eagerly JIT'd code did not return expected result";
127 }
128
129 LLVMOrcRemoveModule(JIT, H);
130
131 LLVMOrcDisposeMangledSymbol(testFuncName);
132 LLVMOrcDisposeInstance(JIT);
133 }
134
TEST_F(OrcCAPIExecutionTest,TestLazyIRCompilation)135 TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) {
136 if (!SupportsIndirection)
137 return;
138
139 LLVMOrcJITStackRef JIT =
140 LLVMOrcCreateInstance(wrap(TM.get()));
141
142 std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
143
144 LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
145
146 LLVMOrcModuleHandle H;
147 LLVMOrcAddLazilyCompiledIR(JIT, &H, wrap(M.release()), myResolver, nullptr);
148 LLVMOrcTargetAddress MainAddr;
149 LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main");
150 MainFnTy MainFn = (MainFnTy)MainAddr;
151 int Result = MainFn();
152 EXPECT_EQ(Result, 42)
153 << "Lazily JIT'd code did not return expected result";
154
155 LLVMOrcRemoveModule(JIT, H);
156
157 LLVMOrcDisposeMangledSymbol(testFuncName);
158 LLVMOrcDisposeInstance(JIT);
159 }
160
TEST_F(OrcCAPIExecutionTest,TestAddObjectFile)161 TEST_F(OrcCAPIExecutionTest, TestAddObjectFile) {
162 if (!SupportsJIT)
163 return;
164
165 auto ObjBuffer = createTestObject();
166
167 LLVMOrcJITStackRef JIT =
168 LLVMOrcCreateInstance(wrap(TM.get()));
169 LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
170
171 LLVMOrcModuleHandle H;
172 LLVMOrcAddObjectFile(JIT, &H, wrap(ObjBuffer.release()), myResolver, nullptr);
173 LLVMOrcTargetAddress MainAddr;
174 LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main");
175 MainFnTy MainFn = (MainFnTy)MainAddr;
176 int Result = MainFn();
177 EXPECT_EQ(Result, 42)
178 << "Lazily JIT'd code did not return expected result";
179
180 LLVMOrcRemoveModule(JIT, H);
181
182 LLVMOrcDisposeMangledSymbol(testFuncName);
183 LLVMOrcDisposeInstance(JIT);
184 }
185
TEST_F(OrcCAPIExecutionTest,TestDirectCallbacksAPI)186 TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) {
187 if (!SupportsIndirection)
188 return;
189
190 LLVMOrcJITStackRef JIT =
191 LLVMOrcCreateInstance(wrap(TM.get()));
192
193 LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
194
195 CompileContext C;
196 C.APIExecTest = this;
197 LLVMOrcTargetAddress CCAddr;
198 LLVMOrcCreateLazyCompileCallback(JIT, &CCAddr, myCompileCallback, &C);
199 LLVMOrcCreateIndirectStub(JIT, "foo", CCAddr);
200 LLVMOrcTargetAddress MainAddr;
201 LLVMOrcGetSymbolAddress(JIT, &MainAddr, "foo");
202 MainFnTy FooFn = (MainFnTy)MainAddr;
203 int Result = FooFn();
204 EXPECT_TRUE(C.Compiled)
205 << "Function wasn't lazily compiled";
206 EXPECT_EQ(Result, 42)
207 << "Direct-callback JIT'd code did not return expected result";
208
209 C.Compiled = false;
210 FooFn();
211 EXPECT_FALSE(C.Compiled)
212 << "Direct-callback JIT'd code was JIT'd twice";
213
214 LLVMOrcRemoveModule(JIT, C.H);
215
216 LLVMOrcDisposeMangledSymbol(testFuncName);
217 LLVMOrcDisposeInstance(JIT);
218 }
219
220 } // namespace llvm
221