1 //===- MCJITTestBase.h - Common base class for MCJIT Unit tests -*- C++ -*-===//
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 // This class implements common functionality required by the MCJIT unit tests,
10 // as well as logic to skip tests on unsupported architectures and operating
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
16 #define LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
18 #include "MCJITTestAPICommon.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/ExecutionEngine/ExecutionEngine.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/IRBuilder.h"
24 #include "llvm/IR/LLVMContext.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/IR/Type.h"
27 #include "llvm/Support/CodeGen.h"
31 /// Helper class that can build very simple Modules
32 class TrivialModuleBuilder
{
36 std::string BuilderTriple
;
38 TrivialModuleBuilder(const std::string
&Triple
)
39 : Builder(Context
), BuilderTriple(Triple
) {}
41 Module
*createEmptyModule(StringRef Name
= StringRef()) {
42 Module
* M
= new Module(Name
, Context
);
43 M
->setTargetTriple(Triple::normalize(BuilderTriple
));
47 Function
*startFunction(Module
*M
, FunctionType
*FT
, StringRef Name
) {
49 Function::Create(FT
, GlobalValue::ExternalLinkage
, Name
, M
);
51 BasicBlock
*BB
= BasicBlock::Create(Context
, Name
, Result
);
52 Builder
.SetInsertPoint(BB
);
57 void endFunctionWithRet(Function
*Func
, Value
*RetValue
) {
58 Builder
.CreateRet(RetValue
);
61 // Inserts a simple function that invokes Callee and takes the same arguments:
62 // int Caller(...) { return Callee(...); }
63 Function
*insertSimpleCallFunction(Module
*M
, Function
*Callee
) {
64 Function
*Result
= startFunction(M
, Callee
->getFunctionType(), "caller");
66 SmallVector
<Value
*, 1> CallArgs
;
68 for (Argument
&A
: Result
->args())
69 CallArgs
.push_back(&A
);
71 Value
*ReturnCode
= Builder
.CreateCall(Callee
, CallArgs
);
72 Builder
.CreateRet(ReturnCode
);
76 // Inserts a function named 'main' that returns a uint32_t:
77 // int32_t main() { return X; }
78 // where X is given by returnCode
79 Function
*insertMainFunction(Module
*M
, uint32_t returnCode
) {
80 Function
*Result
= startFunction(
81 M
, FunctionType::get(Type::getInt32Ty(Context
), {}, false), "main");
83 Value
*ReturnVal
= ConstantInt::get(Context
, APInt(32, returnCode
));
84 endFunctionWithRet(Result
, ReturnVal
);
90 // int32_t add(int32_t a, int32_t b) { return a + b; }
91 // in the current module and returns a pointer to it.
92 Function
*insertAddFunction(Module
*M
, StringRef Name
= "add") {
93 Function
*Result
= startFunction(
96 Type::getInt32Ty(Context
),
97 {Type::getInt32Ty(Context
), Type::getInt32Ty(Context
)}, false),
100 Function::arg_iterator args
= Result
->arg_begin();
101 Value
*Arg1
= &*args
;
102 Value
*Arg2
= &*++args
;
103 Value
*AddResult
= Builder
.CreateAdd(Arg1
, Arg2
);
105 endFunctionWithRet(Result
, AddResult
);
110 // Inserts a declaration to a function defined elsewhere
111 Function
*insertExternalReferenceToFunction(Module
*M
, FunctionType
*FTy
,
114 Function::Create(FTy
, GlobalValue::ExternalLinkage
, Name
, M
);
118 // Inserts an declaration to a function defined elsewhere
119 Function
*insertExternalReferenceToFunction(Module
*M
, Function
*Func
) {
120 Function
*Result
= Function::Create(Func
->getFunctionType(),
121 GlobalValue::ExternalLinkage
,
126 // Inserts a global variable of type int32
127 // FIXME: make this a template function to support any type
128 GlobalVariable
*insertGlobalInt32(Module
*M
,
130 int32_t InitialValue
) {
131 Type
*GlobalTy
= Type::getInt32Ty(Context
);
132 Constant
*IV
= ConstantInt::get(Context
, APInt(32, InitialValue
));
133 GlobalVariable
*Global
= new GlobalVariable(*M
,
136 GlobalValue::ExternalLinkage
,
142 // Inserts a function
143 // int32_t recursive_add(int32_t num) {
147 // int32_t recursive_param = num - 1;
148 // return num + Helper(recursive_param);
151 // NOTE: if Helper is left as the default parameter, Helper == recursive_add.
152 Function
*insertAccumulateFunction(Module
*M
,
153 Function
*Helper
= nullptr,
154 StringRef Name
= "accumulate") {
157 FunctionType::get(Type::getInt32Ty(Context
),
158 {Type::getInt32Ty(Context
)}, false),
163 BasicBlock
*BaseCase
= BasicBlock::Create(Context
, "", Result
);
164 BasicBlock
*RecursiveCase
= BasicBlock::Create(Context
, "", Result
);
167 Value
*Param
= &*Result
->arg_begin();
168 Value
*Zero
= ConstantInt::get(Context
, APInt(32, 0));
169 Builder
.CreateCondBr(Builder
.CreateICmpEQ(Param
, Zero
),
170 BaseCase
, RecursiveCase
);
173 Builder
.SetInsertPoint(BaseCase
);
174 Builder
.CreateRet(Param
);
176 // int32_t recursive_param = num - 1;
177 // return Helper(recursive_param);
178 Builder
.SetInsertPoint(RecursiveCase
);
179 Value
*One
= ConstantInt::get(Context
, APInt(32, 1));
180 Value
*RecursiveParam
= Builder
.CreateSub(Param
, One
);
181 Value
*RecursiveReturn
= Builder
.CreateCall(Helper
, RecursiveParam
);
182 Value
*Accumulator
= Builder
.CreateAdd(Param
, RecursiveReturn
);
183 Builder
.CreateRet(Accumulator
);
188 // Populates Modules A and B:
189 // Module A { Extern FB1, Function FA which calls FB1 },
190 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
191 void createCrossModuleRecursiveCase(std::unique_ptr
<Module
> &A
, Function
*&FA
,
192 std::unique_ptr
<Module
> &B
,
193 Function
*&FB1
, Function
*&FB2
) {
195 B
.reset(createEmptyModule("B"));
196 FB1
= insertAccumulateFunction(B
.get(), nullptr, "FB1");
198 // Declare FB1 in A (as an external).
199 A
.reset(createEmptyModule("A"));
200 Function
*FB1Extern
= insertExternalReferenceToFunction(A
.get(), FB1
);
202 // Define FA in A (with a call to FB1).
203 FA
= insertAccumulateFunction(A
.get(), FB1Extern
, "FA");
205 // Declare FA in B (as an external)
206 Function
*FAExtern
= insertExternalReferenceToFunction(B
.get(), FA
);
208 // Define FB2 in B (with a call to FA)
209 FB2
= insertAccumulateFunction(B
.get(), FAExtern
, "FB2");
212 // Module A { Function FA },
213 // Module B { Extern FA, Function FB which calls FA },
214 // Module C { Extern FB, Function FC which calls FB },
216 createThreeModuleChainedCallsCase(std::unique_ptr
<Module
> &A
, Function
*&FA
,
217 std::unique_ptr
<Module
> &B
, Function
*&FB
,
218 std::unique_ptr
<Module
> &C
, Function
*&FC
) {
219 A
.reset(createEmptyModule("A"));
220 FA
= insertAddFunction(A
.get());
222 B
.reset(createEmptyModule("B"));
223 Function
*FAExtern_in_B
= insertExternalReferenceToFunction(B
.get(), FA
);
224 FB
= insertSimpleCallFunction(B
.get(), FAExtern_in_B
);
226 C
.reset(createEmptyModule("C"));
227 Function
*FBExtern_in_C
= insertExternalReferenceToFunction(C
.get(), FB
);
228 FC
= insertSimpleCallFunction(C
.get(), FBExtern_in_C
);
231 // Module A { Function FA },
232 // Populates Modules A and B:
233 // Module B { Function FB }
234 void createTwoModuleCase(std::unique_ptr
<Module
> &A
, Function
*&FA
,
235 std::unique_ptr
<Module
> &B
, Function
*&FB
) {
236 A
.reset(createEmptyModule("A"));
237 FA
= insertAddFunction(A
.get());
239 B
.reset(createEmptyModule("B"));
240 FB
= insertAddFunction(B
.get());
243 // Module A { Function FA },
244 // Module B { Extern FA, Function FB which calls FA }
245 void createTwoModuleExternCase(std::unique_ptr
<Module
> &A
, Function
*&FA
,
246 std::unique_ptr
<Module
> &B
, Function
*&FB
) {
247 A
.reset(createEmptyModule("A"));
248 FA
= insertAddFunction(A
.get());
250 B
.reset(createEmptyModule("B"));
251 Function
*FAExtern_in_B
= insertExternalReferenceToFunction(B
.get(), FA
);
252 FB
= insertSimpleCallFunction(B
.get(), FAExtern_in_B
);
255 // Module A { Function FA },
256 // Module B { Extern FA, Function FB which calls FA },
257 // Module C { Extern FB, Function FC which calls FA },
258 void createThreeModuleCase(std::unique_ptr
<Module
> &A
, Function
*&FA
,
259 std::unique_ptr
<Module
> &B
, Function
*&FB
,
260 std::unique_ptr
<Module
> &C
, Function
*&FC
) {
261 A
.reset(createEmptyModule("A"));
262 FA
= insertAddFunction(A
.get());
264 B
.reset(createEmptyModule("B"));
265 Function
*FAExtern_in_B
= insertExternalReferenceToFunction(B
.get(), FA
);
266 FB
= insertSimpleCallFunction(B
.get(), FAExtern_in_B
);
268 C
.reset(createEmptyModule("C"));
269 Function
*FAExtern_in_C
= insertExternalReferenceToFunction(C
.get(), FA
);
270 FC
= insertSimpleCallFunction(C
.get(), FAExtern_in_C
);
274 class MCJITTestBase
: public MCJITTestAPICommon
, public TrivialModuleBuilder
{
277 : TrivialModuleBuilder(HostTriple
), OptLevel(CodeGenOpt::None
),
278 CodeModel(CodeModel::Small
), MArch(""), MM(new SectionMemoryManager
) {
279 // The architectures below are known to be compatible with MCJIT as they
280 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
282 SupportedArchs
.push_back(Triple::aarch64
);
283 SupportedArchs
.push_back(Triple::arm
);
284 SupportedArchs
.push_back(Triple::mips
);
285 SupportedArchs
.push_back(Triple::mipsel
);
286 SupportedArchs
.push_back(Triple::mips64
);
287 SupportedArchs
.push_back(Triple::mips64el
);
288 SupportedArchs
.push_back(Triple::x86
);
289 SupportedArchs
.push_back(Triple::x86_64
);
291 // Some architectures have sub-architectures in which tests will fail, like
292 // ARM. These two vectors will define if they do have sub-archs (to avoid
293 // extra work for those who don't), and if so, if they are listed to work
294 HasSubArchs
.push_back(Triple::arm
);
295 SupportedSubArchs
.push_back("armv6");
296 SupportedSubArchs
.push_back("armv7");
298 UnsupportedEnvironments
.push_back(Triple::Cygnus
);
301 void createJIT(std::unique_ptr
<Module
> M
) {
303 // Due to the EngineBuilder constructor, it is required to have a Module
304 // in order to construct an ExecutionEngine (i.e. MCJIT)
305 assert(M
!= 0 && "a non-null Module must be provided to create MCJIT");
307 EngineBuilder
EB(std::move(M
));
309 TheJIT
.reset(EB
.setEngineKind(EngineKind::JIT
)
310 .setMCJITMemoryManager(std::move(MM
))
312 .setOptLevel(CodeGenOpt::None
)
314 .setMCPU(sys::getHostCPUName())
317 // At this point, we cannot modify the module any more.
318 assert(TheJIT
.get() != NULL
&& "error creating MCJIT with EngineBuilder");
321 CodeGenOpt::Level OptLevel
;
322 CodeModel::Model CodeModel
;
324 SmallVector
<std::string
, 1> MAttrs
;
325 std::unique_ptr
<ExecutionEngine
> TheJIT
;
326 std::unique_ptr
<RTDyldMemoryManager
> MM
;
328 std::unique_ptr
<Module
> M
;
333 #endif // LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H