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