1 //===------ OrcTestCommon.h - Utilities for Orc 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 // Common utilities for the Orc unit tests.
11 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H
15 #define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H
17 #include "llvm/ExecutionEngine/ExecutionEngine.h"
18 #include "llvm/ExecutionEngine/JITSymbol.h"
19 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/LLVMContext.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Support/TargetRegistry.h"
26 #include "llvm/Support/TargetSelect.h"
27 #include "gtest/gtest.h"
34 // CoreAPIsStandardTest that saves a bunch of boilerplate by providing the
37 // (1) ES -- An ExecutionSession
38 // (2) Foo, Bar, Baz, Qux -- SymbolStringPtrs for strings "foo", "bar", "baz",
39 // and "qux" respectively.
40 // (3) FooAddr, BarAddr, BazAddr, QuxAddr -- Dummy addresses. Guaranteed
41 // distinct and non-null.
42 // (4) FooSym, BarSym, BazSym, QuxSym -- JITEvaluatedSymbols with FooAddr,
43 // BarAddr, BazAddr, and QuxAddr respectively. All with default strong,
44 // linkage and non-hidden visibility.
45 // (5) V -- A JITDylib associated with ES.
46 class CoreAPIsBasedStandardTest
: public testing::Test
{
48 std::shared_ptr
<SymbolStringPool
> SSP
= std::make_shared
<SymbolStringPool
>();
49 ExecutionSession ES
{SSP
};
50 JITDylib
&JD
= ES
.createJITDylib("JD");
51 SymbolStringPtr Foo
= ES
.intern("foo");
52 SymbolStringPtr Bar
= ES
.intern("bar");
53 SymbolStringPtr Baz
= ES
.intern("baz");
54 SymbolStringPtr Qux
= ES
.intern("qux");
55 static const JITTargetAddress FooAddr
= 1U;
56 static const JITTargetAddress BarAddr
= 2U;
57 static const JITTargetAddress BazAddr
= 3U;
58 static const JITTargetAddress QuxAddr
= 4U;
59 JITEvaluatedSymbol FooSym
=
60 JITEvaluatedSymbol(FooAddr
, JITSymbolFlags::Exported
);
61 JITEvaluatedSymbol BarSym
=
62 JITEvaluatedSymbol(BarAddr
, JITSymbolFlags::Exported
);
63 JITEvaluatedSymbol BazSym
=
64 JITEvaluatedSymbol(BazAddr
, JITSymbolFlags::Exported
);
65 JITEvaluatedSymbol QuxSym
=
66 JITEvaluatedSymbol(QuxAddr
, JITSymbolFlags::Exported
);
69 } // end namespace orc
71 class OrcNativeTarget
{
73 static void initialize() {
74 if (!NativeTargetInitialized
) {
75 InitializeNativeTarget();
76 InitializeNativeTargetAsmParser();
77 InitializeNativeTargetAsmPrinter();
78 NativeTargetInitialized
= true;
83 static bool NativeTargetInitialized
;
86 class SimpleMaterializationUnit
: public orc::MaterializationUnit
{
88 using MaterializeFunction
=
89 std::function
<void(orc::MaterializationResponsibility
)>;
90 using DiscardFunction
=
91 std::function
<void(const orc::JITDylib
&, orc::SymbolStringPtr
)>;
92 using DestructorFunction
= std::function
<void()>;
94 SimpleMaterializationUnit(
95 orc::SymbolFlagsMap SymbolFlags
, MaterializeFunction Materialize
,
96 DiscardFunction Discard
= DiscardFunction(),
97 DestructorFunction Destructor
= DestructorFunction())
98 : MaterializationUnit(std::move(SymbolFlags
), orc::VModuleKey()),
99 Materialize(std::move(Materialize
)), Discard(std::move(Discard
)),
100 Destructor(std::move(Destructor
)) {}
102 ~SimpleMaterializationUnit() override
{
107 StringRef
getName() const override
{ return "<Simple>"; }
109 void materialize(orc::MaterializationResponsibility R
) override
{
110 Materialize(std::move(R
));
113 void discard(const orc::JITDylib
&JD
,
114 const orc::SymbolStringPtr
&Name
) override
{
116 Discard(JD
, std::move(Name
));
118 llvm_unreachable("Discard not supported");
122 MaterializeFunction Materialize
;
123 DiscardFunction Discard
;
124 DestructorFunction Destructor
;
127 // Base class for Orc tests that will execute code.
128 class OrcExecutionTest
{
133 // Initialize the native target if it hasn't been done already.
134 OrcNativeTarget::initialize();
136 // Try to select a TargetMachine for the host.
137 TM
.reset(EngineBuilder().selectTarget());
140 // If we found a TargetMachine, check that it's one that Orc supports.
141 const Triple
& TT
= TM
->getTargetTriple();
143 // Bail out for windows platforms. We do not support these yet.
144 if ((TT
.getArch() != Triple::x86_64
&& TT
.getArch() != Triple::x86
) ||
149 SupportsJIT
= TM
->getTarget().hasJIT();
150 // Use ability to create callback manager to detect whether Orc
151 // has indirection support on this platform. This way the test
152 // and Orc code do not get out of sync.
153 SupportsIndirection
= !!orc::createLocalCompileCallbackManager(TT
, ES
, 0);
158 orc::ExecutionSession ES
;
160 std::unique_ptr
<TargetMachine
> TM
;
161 bool SupportsJIT
= false;
162 bool SupportsIndirection
= false;
165 class ModuleBuilder
{
167 ModuleBuilder(LLVMContext
&Context
, StringRef Triple
,
170 Function
*createFunctionDecl(FunctionType
*FTy
, StringRef Name
) {
171 return Function::Create(FTy
, GlobalValue::ExternalLinkage
, Name
, M
.get());
174 Module
* getModule() { return M
.get(); }
175 const Module
* getModule() const { return M
.get(); }
176 std::unique_ptr
<Module
> takeModule() { return std::move(M
); }
179 std::unique_ptr
<Module
> M
;
182 // Dummy struct type.
187 inline StructType
*getDummyStructTy(LLVMContext
&Context
) {
188 return StructType::get(ArrayType::get(Type::getInt32Ty(Context
), 256));
191 template <typename HandleT
, typename ModuleT
>
192 class MockBaseLayer
{
195 using ModuleHandleT
= HandleT
;
197 using AddModuleSignature
=
198 Expected
<ModuleHandleT
>(ModuleT M
,
199 std::shared_ptr
<JITSymbolResolver
> R
);
201 using RemoveModuleSignature
= Error(ModuleHandleT H
);
202 using FindSymbolSignature
= JITSymbol(const std::string
&Name
,
203 bool ExportedSymbolsOnly
);
204 using FindSymbolInSignature
= JITSymbol(ModuleHandleT H
,
205 const std::string
&Name
,
206 bool ExportedSymbolsONly
);
207 using EmitAndFinalizeSignature
= Error(ModuleHandleT H
);
209 std::function
<AddModuleSignature
> addModuleImpl
;
210 std::function
<RemoveModuleSignature
> removeModuleImpl
;
211 std::function
<FindSymbolSignature
> findSymbolImpl
;
212 std::function
<FindSymbolInSignature
> findSymbolInImpl
;
213 std::function
<EmitAndFinalizeSignature
> emitAndFinalizeImpl
;
215 Expected
<ModuleHandleT
> addModule(ModuleT M
,
216 std::shared_ptr
<JITSymbolResolver
> R
) {
217 assert(addModuleImpl
&&
218 "addModule called, but no mock implementation was provided");
219 return addModuleImpl(std::move(M
), std::move(R
));
222 Error
removeModule(ModuleHandleT H
) {
223 assert(removeModuleImpl
&&
224 "removeModule called, but no mock implementation was provided");
225 return removeModuleImpl(H
);
228 JITSymbol
findSymbol(const std::string
&Name
, bool ExportedSymbolsOnly
) {
229 assert(findSymbolImpl
&&
230 "findSymbol called, but no mock implementation was provided");
231 return findSymbolImpl(Name
, ExportedSymbolsOnly
);
234 JITSymbol
findSymbolIn(ModuleHandleT H
, const std::string
&Name
,
235 bool ExportedSymbolsOnly
) {
236 assert(findSymbolInImpl
&&
237 "findSymbolIn called, but no mock implementation was provided");
238 return findSymbolInImpl(H
, Name
, ExportedSymbolsOnly
);
241 Error
emitAndFinaliez(ModuleHandleT H
) {
242 assert(emitAndFinalizeImpl
&&
243 "emitAndFinalize called, but no mock implementation was provided");
244 return emitAndFinalizeImpl(H
);
248 class ReturnNullJITSymbol
{
250 template <typename
... Args
>
251 JITSymbol
operator()(Args
...) const {
256 template <typename ReturnT
>
257 class DoNothingAndReturn
{
259 DoNothingAndReturn(ReturnT Ret
) : Ret(std::move(Ret
)) {}
261 template <typename
... Args
>
262 void operator()(Args
...) const { return Ret
; }
268 class DoNothingAndReturn
<void> {
270 template <typename
... Args
>
271 void operator()(Args
...) const { }