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 "gtest/gtest.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 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 namespace llvm {
22 
23 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
24 
25 class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest {
26 protected:
createTestModule(const Triple & TT)27   std::unique_ptr<Module> createTestModule(const Triple &TT) {
28     ModuleBuilder MB(getGlobalContext(), TT.str(), "");
29     Function *TestFunc = MB.createFunctionDecl<int()>("testFunc");
30     Function *Main = MB.createFunctionDecl<int(int, char*[])>("main");
31 
32     Main->getBasicBlockList().push_back(BasicBlock::Create(getGlobalContext()));
33     IRBuilder<> B(&Main->back());
34     Value* Result = B.CreateCall(TestFunc);
35     B.CreateRet(Result);
36 
37     return MB.takeModule();
38   }
39 
40   typedef int (*MainFnTy)();
41 
myTestFuncImpl()42   static int myTestFuncImpl() {
43     return 42;
44   }
45 
46   static char *testFuncName;
47 
myResolver(const char * Name,void * Ctx)48   static uint64_t myResolver(const char *Name, void *Ctx) {
49     if (!strncmp(Name, testFuncName, 8))
50       return (uint64_t)&myTestFuncImpl;
51     return 0;
52   }
53 
54   struct CompileContext {
CompileContextllvm::OrcCAPIExecutionTest::CompileContext55     CompileContext() : Compiled(false) { }
56 
57     OrcCAPIExecutionTest* APIExecTest;
58     std::unique_ptr<Module> M;
59     LLVMOrcModuleHandle H;
60     bool Compiled;
61   };
62 
myCompileCallback(LLVMOrcJITStackRef JITStack,void * Ctx)63   static LLVMOrcTargetAddress myCompileCallback(LLVMOrcJITStackRef JITStack,
64                                                 void *Ctx) {
65     CompileContext *CCtx = static_cast<CompileContext*>(Ctx);
66     auto *ET = CCtx->APIExecTest;
67     CCtx->M = ET->createTestModule(ET->TM->getTargetTriple());
68     CCtx->H = LLVMOrcAddEagerlyCompiledIR(JITStack, wrap(CCtx->M.get()),
69                                           myResolver, nullptr);
70     CCtx->Compiled = true;
71     LLVMOrcTargetAddress MainAddr = LLVMOrcGetSymbolAddress(JITStack, "main");
72     LLVMOrcSetIndirectStubPointer(JITStack, "foo", MainAddr);
73     return MainAddr;
74   }
75 };
76 
77 char *OrcCAPIExecutionTest::testFuncName = nullptr;
78 
TEST_F(OrcCAPIExecutionTest,TestEagerIRCompilation)79 TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) {
80   if (!TM)
81     return;
82 
83   LLVMOrcJITStackRef JIT =
84     LLVMOrcCreateInstance(wrap(TM.get()));
85 
86   std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
87 
88   LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
89 
90   LLVMOrcModuleHandle H =
91     LLVMOrcAddEagerlyCompiledIR(JIT, wrap(M.get()), myResolver, nullptr);
92   MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main");
93   int Result = MainFn();
94   EXPECT_EQ(Result, 42)
95     << "Eagerly JIT'd code did not return expected result";
96 
97   LLVMOrcRemoveModule(JIT, H);
98 
99   LLVMOrcDisposeMangledSymbol(testFuncName);
100   LLVMOrcDisposeInstance(JIT);
101 }
102 
TEST_F(OrcCAPIExecutionTest,TestLazyIRCompilation)103 TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) {
104   if (!TM)
105     return;
106 
107   LLVMOrcJITStackRef JIT =
108     LLVMOrcCreateInstance(wrap(TM.get()));
109 
110   std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
111 
112   LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
113 
114   LLVMOrcModuleHandle H =
115     LLVMOrcAddLazilyCompiledIR(JIT, wrap(M.get()), myResolver, nullptr);
116   MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main");
117   int Result = MainFn();
118   EXPECT_EQ(Result, 42)
119     << "Lazily JIT'd code did not return expected result";
120 
121   LLVMOrcRemoveModule(JIT, H);
122 
123   LLVMOrcDisposeMangledSymbol(testFuncName);
124   LLVMOrcDisposeInstance(JIT);
125 }
126 
TEST_F(OrcCAPIExecutionTest,TestDirectCallbacksAPI)127 TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) {
128   if (!TM)
129     return;
130 
131   LLVMOrcJITStackRef JIT =
132     LLVMOrcCreateInstance(wrap(TM.get()));
133 
134   LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
135 
136   CompileContext C;
137   C.APIExecTest = this;
138   LLVMOrcCreateIndirectStub(JIT, "foo",
139                             LLVMOrcCreateLazyCompileCallback(JIT,
140                                                              myCompileCallback,
141                                                              &C));
142   MainFnTy FooFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "foo");
143   int Result = FooFn();
144   EXPECT_TRUE(C.Compiled)
145     << "Function wasn't lazily compiled";
146   EXPECT_EQ(Result, 42)
147     << "Direct-callback JIT'd code did not return expected result";
148 
149   C.Compiled = false;
150   FooFn();
151   EXPECT_FALSE(C.Compiled)
152     << "Direct-callback JIT'd code was JIT'd twice";
153 
154   LLVMOrcRemoveModule(JIT, C.H);
155 
156   LLVMOrcDisposeMangledSymbol(testFuncName);
157   LLVMOrcDisposeInstance(JIT);
158 }
159 
160 } // namespace llvm
161