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