1 //===--------------- OrcCAPITest.cpp - Unit tests Orc C API ---------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "OrcTestCommon.h"
10 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
11 #include "llvm-c/Core.h"
12 #include "llvm-c/OrcBindings.h"
13 #include "llvm-c/Target.h"
14 #include "llvm-c/TargetMachine.h"
15 #include "gtest/gtest.h"
23 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine
, LLVMTargetMachineRef
)
25 class OrcCAPIExecutionTest
: public testing::Test
, public OrcExecutionTest
{
27 std::unique_ptr
<Module
> createTestModule(const Triple
&TT
) {
28 ModuleBuilder
MB(Context
, TT
.str(), "");
29 Type
*IntTy
= Type::getScalarTy
<int>(Context
);
31 MB
.createFunctionDecl(FunctionType::get(IntTy
, {}, false), "testFunc");
32 Function
*Main
= MB
.createFunctionDecl(
35 {IntTy
, Type::getInt8PtrTy(Context
)->getPointerTo()},
39 Main
->getBasicBlockList().push_back(BasicBlock::Create(Context
));
40 IRBuilder
<> B(&Main
->back());
41 Value
* Result
= B
.CreateCall(TestFunc
);
44 return MB
.takeModule();
47 std::unique_ptr
<MemoryBuffer
> createTestObject() {
48 orc::SimpleCompiler
IRCompiler(*TM
);
49 auto M
= createTestModule(TM
->getTargetTriple());
50 M
->setDataLayout(TM
->createDataLayout());
51 return IRCompiler(*M
);
54 typedef int (*MainFnTy
)();
56 static int myTestFuncImpl() {
60 static char *testFuncName
;
62 static uint64_t myResolver(const char *Name
, void *Ctx
) {
63 if (!strncmp(Name
, testFuncName
, 8))
64 return (uint64_t)&myTestFuncImpl
;
68 struct CompileContext
{
69 CompileContext() : Compiled(false) { }
71 OrcCAPIExecutionTest
* APIExecTest
;
72 std::unique_ptr
<Module
> M
;
73 LLVMOrcModuleHandle H
;
77 static LLVMOrcTargetAddress
myCompileCallback(LLVMOrcJITStackRef JITStack
,
79 CompileContext
*CCtx
= static_cast<CompileContext
*>(Ctx
);
80 auto *ET
= CCtx
->APIExecTest
;
81 CCtx
->M
= ET
->createTestModule(ET
->TM
->getTargetTriple());
82 LLVMOrcAddEagerlyCompiledIR(JITStack
, &CCtx
->H
, wrap(CCtx
->M
.release()),
84 CCtx
->Compiled
= true;
85 LLVMOrcTargetAddress MainAddr
;
86 LLVMOrcGetSymbolAddress(JITStack
, &MainAddr
, "main");
87 LLVMOrcSetIndirectStubPointer(JITStack
, "foo", MainAddr
);
92 char *OrcCAPIExecutionTest::testFuncName
= nullptr;
94 TEST_F(OrcCAPIExecutionTest
, TestEagerIRCompilation
) {
98 LLVMOrcJITStackRef JIT
=
99 LLVMOrcCreateInstance(wrap(TM
.get()));
101 std::unique_ptr
<Module
> M
= createTestModule(TM
->getTargetTriple());
103 LLVMOrcGetMangledSymbol(JIT
, &testFuncName
, "testFunc");
105 LLVMOrcModuleHandle H
;
106 LLVMOrcAddEagerlyCompiledIR(JIT
, &H
, wrap(M
.release()), myResolver
, nullptr);
108 // get symbol address searching the entire stack
110 LLVMOrcTargetAddress MainAddr
;
111 LLVMOrcGetSymbolAddress(JIT
, &MainAddr
, "main");
112 MainFnTy MainFn
= (MainFnTy
)MainAddr
;
113 int Result
= MainFn();
114 EXPECT_EQ(Result
, 42)
115 << "Eagerly JIT'd code did not return expected result";
118 // and then just searching a single handle
120 LLVMOrcTargetAddress MainAddr
;
121 LLVMOrcGetSymbolAddressIn(JIT
, &MainAddr
, H
, "main");
122 MainFnTy MainFn
= (MainFnTy
)MainAddr
;
123 int Result
= MainFn();
124 EXPECT_EQ(Result
, 42)
125 << "Eagerly JIT'd code did not return expected result";
128 LLVMOrcRemoveModule(JIT
, H
);
130 LLVMOrcDisposeMangledSymbol(testFuncName
);
131 LLVMOrcDisposeInstance(JIT
);
134 TEST_F(OrcCAPIExecutionTest
, TestLazyIRCompilation
) {
135 if (!SupportsIndirection
)
138 LLVMOrcJITStackRef JIT
=
139 LLVMOrcCreateInstance(wrap(TM
.get()));
141 std::unique_ptr
<Module
> M
= createTestModule(TM
->getTargetTriple());
143 LLVMOrcGetMangledSymbol(JIT
, &testFuncName
, "testFunc");
145 LLVMOrcModuleHandle H
;
146 LLVMOrcAddLazilyCompiledIR(JIT
, &H
, wrap(M
.release()), myResolver
, nullptr);
147 LLVMOrcTargetAddress MainAddr
;
148 LLVMOrcGetSymbolAddress(JIT
, &MainAddr
, "main");
149 MainFnTy MainFn
= (MainFnTy
)MainAddr
;
150 int Result
= MainFn();
151 EXPECT_EQ(Result
, 42)
152 << "Lazily JIT'd code did not return expected result";
154 LLVMOrcRemoveModule(JIT
, H
);
156 LLVMOrcDisposeMangledSymbol(testFuncName
);
157 LLVMOrcDisposeInstance(JIT
);
160 TEST_F(OrcCAPIExecutionTest
, TestAddObjectFile
) {
164 auto ObjBuffer
= createTestObject();
166 LLVMOrcJITStackRef JIT
=
167 LLVMOrcCreateInstance(wrap(TM
.get()));
168 LLVMOrcGetMangledSymbol(JIT
, &testFuncName
, "testFunc");
170 LLVMOrcModuleHandle H
;
171 LLVMOrcAddObjectFile(JIT
, &H
, wrap(ObjBuffer
.release()), myResolver
, nullptr);
172 LLVMOrcTargetAddress MainAddr
;
173 LLVMOrcGetSymbolAddress(JIT
, &MainAddr
, "main");
174 MainFnTy MainFn
= (MainFnTy
)MainAddr
;
175 int Result
= MainFn();
176 EXPECT_EQ(Result
, 42)
177 << "Lazily JIT'd code did not return expected result";
179 LLVMOrcRemoveModule(JIT
, H
);
181 LLVMOrcDisposeMangledSymbol(testFuncName
);
182 LLVMOrcDisposeInstance(JIT
);
185 TEST_F(OrcCAPIExecutionTest
, TestDirectCallbacksAPI
) {
186 if (!SupportsIndirection
)
189 LLVMOrcJITStackRef JIT
=
190 LLVMOrcCreateInstance(wrap(TM
.get()));
192 LLVMOrcGetMangledSymbol(JIT
, &testFuncName
, "testFunc");
195 C
.APIExecTest
= this;
196 LLVMOrcTargetAddress CCAddr
;
197 LLVMOrcCreateLazyCompileCallback(JIT
, &CCAddr
, myCompileCallback
, &C
);
198 LLVMOrcCreateIndirectStub(JIT
, "foo", CCAddr
);
199 LLVMOrcTargetAddress MainAddr
;
200 LLVMOrcGetSymbolAddress(JIT
, &MainAddr
, "foo");
201 MainFnTy FooFn
= (MainFnTy
)MainAddr
;
202 int Result
= FooFn();
203 EXPECT_TRUE(C
.Compiled
)
204 << "Function wasn't lazily compiled";
205 EXPECT_EQ(Result
, 42)
206 << "Direct-callback JIT'd code did not return expected result";
210 EXPECT_FALSE(C
.Compiled
)
211 << "Direct-callback JIT'd code was JIT'd twice";
213 LLVMOrcRemoveModule(JIT
, C
.H
);
215 LLVMOrcDisposeMangledSymbol(testFuncName
);
216 LLVMOrcDisposeInstance(JIT
);