1 //===---- IndirectionUtils.cpp - Utilities for call indirection in Orc ----===//
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 "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
13 #include "llvm/IR/CallSite.h"
14 #include "llvm/IR/IRBuilder.h"
15 #include "llvm/Support/Format.h"
16 #include "llvm/Transforms/Utils/Cloning.h"
20 using namespace llvm::orc
;
24 class CompileCallbackMaterializationUnit
: public orc::MaterializationUnit
{
26 using CompileFunction
= JITCompileCallbackManager::CompileFunction
;
28 CompileCallbackMaterializationUnit(SymbolStringPtr Name
,
29 CompileFunction Compile
, VModuleKey K
)
30 : MaterializationUnit(SymbolFlagsMap({{Name
, JITSymbolFlags::Exported
}}),
32 Name(std::move(Name
)), Compile(std::move(Compile
)) {}
34 StringRef
getName() const override
{ return "<Compile Callbacks>"; }
37 void materialize(MaterializationResponsibility R
) override
{
39 Result
[Name
] = JITEvaluatedSymbol(Compile(), JITSymbolFlags::Exported
);
40 // No dependencies, so these calls cannot fail.
41 cantFail(R
.notifyResolved(Result
));
42 cantFail(R
.notifyEmitted());
45 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Name
) override
{
46 llvm_unreachable("Discard should never occur on a LMU?");
50 CompileFunction Compile
;
58 void IndirectStubsManager::anchor() {}
59 void TrampolinePool::anchor() {}
61 Expected
<JITTargetAddress
>
62 JITCompileCallbackManager::getCompileCallback(CompileFunction Compile
) {
63 if (auto TrampolineAddr
= TP
->getTrampoline()) {
65 ES
.intern(std::string("cc") + std::to_string(++NextCallbackId
));
67 std::lock_guard
<std::mutex
> Lock(CCMgrMutex
);
68 AddrToSymbol
[*TrampolineAddr
] = CallbackName
;
69 cantFail(CallbacksJD
.define(
70 std::make_unique
<CompileCallbackMaterializationUnit
>(
71 std::move(CallbackName
), std::move(Compile
),
72 ES
.allocateVModule())));
73 return *TrampolineAddr
;
75 return TrampolineAddr
.takeError();
78 JITTargetAddress
JITCompileCallbackManager::executeCompileCallback(
79 JITTargetAddress TrampolineAddr
) {
83 std::unique_lock
<std::mutex
> Lock(CCMgrMutex
);
84 auto I
= AddrToSymbol
.find(TrampolineAddr
);
86 // If this address is not associated with a compile callback then report an
87 // error to the execution session and return ErrorHandlerAddress to the
89 if (I
== AddrToSymbol
.end()) {
93 raw_string_ostream
ErrMsgStream(ErrMsg
);
94 ErrMsgStream
<< "No compile callback for trampoline at "
95 << format("0x%016" PRIx64
, TrampolineAddr
);
98 make_error
<StringError
>(std::move(ErrMsg
), inconvertibleErrorCode()));
99 return ErrorHandlerAddress
;
104 if (auto Sym
= ES
.lookup(JITDylibSearchList({{&CallbacksJD
, true}}), Name
))
105 return Sym
->getAddress();
107 llvm::dbgs() << "Didn't find callback.\n";
108 // If anything goes wrong materializing Sym then report it to the session
109 // and return the ErrorHandlerAddress;
110 ES
.reportError(Sym
.takeError());
111 return ErrorHandlerAddress
;
115 Expected
<std::unique_ptr
<JITCompileCallbackManager
>>
116 createLocalCompileCallbackManager(const Triple
&T
, ExecutionSession
&ES
,
117 JITTargetAddress ErrorHandlerAddress
) {
118 switch (T
.getArch()) {
120 return make_error
<StringError
>(
121 std::string("No callback manager available for ") + T
.str(),
122 inconvertibleErrorCode());
123 case Triple::aarch64
: {
124 typedef orc::LocalJITCompileCallbackManager
<orc::OrcAArch64
> CCMgrT
;
125 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
129 typedef orc::LocalJITCompileCallbackManager
<orc::OrcI386
> CCMgrT
;
130 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
134 typedef orc::LocalJITCompileCallbackManager
<orc::OrcMips32Be
> CCMgrT
;
135 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
137 case Triple::mipsel
: {
138 typedef orc::LocalJITCompileCallbackManager
<orc::OrcMips32Le
> CCMgrT
;
139 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
143 case Triple::mips64el
: {
144 typedef orc::LocalJITCompileCallbackManager
<orc::OrcMips64
> CCMgrT
;
145 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
148 case Triple::x86_64
: {
149 if ( T
.getOS() == Triple::OSType::Win32
) {
150 typedef orc::LocalJITCompileCallbackManager
<orc::OrcX86_64_Win32
> CCMgrT
;
151 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
153 typedef orc::LocalJITCompileCallbackManager
<orc::OrcX86_64_SysV
> CCMgrT
;
154 return CCMgrT::Create(ES
, ErrorHandlerAddress
);
161 std::function
<std::unique_ptr
<IndirectStubsManager
>()>
162 createLocalIndirectStubsManagerBuilder(const Triple
&T
) {
163 switch (T
.getArch()) {
166 return std::make_unique
<
167 orc::LocalIndirectStubsManager
<orc::OrcGenericABI
>>();
170 case Triple::aarch64
:
172 return std::make_unique
<
173 orc::LocalIndirectStubsManager
<orc::OrcAArch64
>>();
178 return std::make_unique
<
179 orc::LocalIndirectStubsManager
<orc::OrcI386
>>();
184 return std::make_unique
<
185 orc::LocalIndirectStubsManager
<orc::OrcMips32Be
>>();
190 return std::make_unique
<
191 orc::LocalIndirectStubsManager
<orc::OrcMips32Le
>>();
195 case Triple::mips64el
:
197 return std::make_unique
<
198 orc::LocalIndirectStubsManager
<orc::OrcMips64
>>();
202 if (T
.getOS() == Triple::OSType::Win32
) {
204 return std::make_unique
<
205 orc::LocalIndirectStubsManager
<orc::OrcX86_64_Win32
>>();
209 return std::make_unique
<
210 orc::LocalIndirectStubsManager
<orc::OrcX86_64_SysV
>>();
217 Constant
* createIRTypedAddress(FunctionType
&FT
, JITTargetAddress Addr
) {
218 Constant
*AddrIntVal
=
219 ConstantInt::get(Type::getInt64Ty(FT
.getContext()), Addr
);
220 Constant
*AddrPtrVal
=
221 ConstantExpr::getCast(Instruction::IntToPtr
, AddrIntVal
,
222 PointerType::get(&FT
, 0));
226 GlobalVariable
* createImplPointer(PointerType
&PT
, Module
&M
,
227 const Twine
&Name
, Constant
*Initializer
) {
228 auto IP
= new GlobalVariable(M
, &PT
, false, GlobalValue::ExternalLinkage
,
229 Initializer
, Name
, nullptr,
230 GlobalValue::NotThreadLocal
, 0, true);
231 IP
->setVisibility(GlobalValue::HiddenVisibility
);
235 void makeStub(Function
&F
, Value
&ImplPointer
) {
236 assert(F
.isDeclaration() && "Can't turn a definition into a stub.");
237 assert(F
.getParent() && "Function isn't in a module.");
238 Module
&M
= *F
.getParent();
239 BasicBlock
*EntryBlock
= BasicBlock::Create(M
.getContext(), "entry", &F
);
240 IRBuilder
<> Builder(EntryBlock
);
241 LoadInst
*ImplAddr
= Builder
.CreateLoad(F
.getType(), &ImplPointer
);
242 std::vector
<Value
*> CallArgs
;
243 for (auto &A
: F
.args())
244 CallArgs
.push_back(&A
);
245 CallInst
*Call
= Builder
.CreateCall(F
.getFunctionType(), ImplAddr
, CallArgs
);
247 Call
->setAttributes(F
.getAttributes());
248 if (F
.getReturnType()->isVoidTy())
249 Builder
.CreateRetVoid();
251 Builder
.CreateRet(Call
);
254 std::vector
<GlobalValue
*> SymbolLinkagePromoter::operator()(Module
&M
) {
255 std::vector
<GlobalValue
*> PromotedGlobals
;
257 for (auto &GV
: M
.global_values()) {
258 bool Promoted
= true;
260 // Rename if necessary.
262 GV
.setName("__orc_anon." + Twine(NextId
++));
263 else if (GV
.getName().startswith("\01L"))
264 GV
.setName("__" + GV
.getName().substr(1) + "." + Twine(NextId
++));
265 else if (GV
.hasLocalLinkage())
266 GV
.setName("__orc_lcl." + GV
.getName() + "." + Twine(NextId
++));
270 if (GV
.hasLocalLinkage()) {
271 GV
.setLinkage(GlobalValue::ExternalLinkage
);
272 GV
.setVisibility(GlobalValue::HiddenVisibility
);
275 GV
.setUnnamedAddr(GlobalValue::UnnamedAddr::None
);
278 PromotedGlobals
.push_back(&GV
);
281 return PromotedGlobals
;
284 Function
* cloneFunctionDecl(Module
&Dst
, const Function
&F
,
285 ValueToValueMapTy
*VMap
) {
287 Function::Create(cast
<FunctionType
>(F
.getValueType()),
288 F
.getLinkage(), F
.getName(), &Dst
);
289 NewF
->copyAttributesFrom(&F
);
293 auto NewArgI
= NewF
->arg_begin();
294 for (auto ArgI
= F
.arg_begin(), ArgE
= F
.arg_end(); ArgI
!= ArgE
;
296 (*VMap
)[&*ArgI
] = &*NewArgI
;
302 void moveFunctionBody(Function
&OrigF
, ValueToValueMapTy
&VMap
,
303 ValueMaterializer
*Materializer
,
305 assert(!OrigF
.isDeclaration() && "Nothing to move");
307 NewF
= cast
<Function
>(VMap
[&OrigF
]);
309 assert(VMap
[&OrigF
] == NewF
&& "Incorrect function mapping in VMap.");
310 assert(NewF
&& "Function mapping missing from VMap.");
311 assert(NewF
->getParent() != OrigF
.getParent() &&
312 "moveFunctionBody should only be used to move bodies between "
315 SmallVector
<ReturnInst
*, 8> Returns
; // Ignore returns cloned.
316 CloneFunctionInto(NewF
, &OrigF
, VMap
, /*ModuleLevelChanges=*/true, Returns
,
317 "", nullptr, nullptr, Materializer
);
321 GlobalVariable
* cloneGlobalVariableDecl(Module
&Dst
, const GlobalVariable
&GV
,
322 ValueToValueMapTy
*VMap
) {
323 GlobalVariable
*NewGV
= new GlobalVariable(
324 Dst
, GV
.getValueType(), GV
.isConstant(),
325 GV
.getLinkage(), nullptr, GV
.getName(), nullptr,
326 GV
.getThreadLocalMode(), GV
.getType()->getAddressSpace());
327 NewGV
->copyAttributesFrom(&GV
);
329 (*VMap
)[&GV
] = NewGV
;
333 void moveGlobalVariableInitializer(GlobalVariable
&OrigGV
,
334 ValueToValueMapTy
&VMap
,
335 ValueMaterializer
*Materializer
,
336 GlobalVariable
*NewGV
) {
337 assert(OrigGV
.hasInitializer() && "Nothing to move");
339 NewGV
= cast
<GlobalVariable
>(VMap
[&OrigGV
]);
341 assert(VMap
[&OrigGV
] == NewGV
&&
342 "Incorrect global variable mapping in VMap.");
343 assert(NewGV
->getParent() != OrigGV
.getParent() &&
344 "moveGlobalVariableInitializer should only be used to move "
345 "initializers between modules");
347 NewGV
->setInitializer(MapValue(OrigGV
.getInitializer(), VMap
, RF_None
,
348 nullptr, Materializer
));
351 GlobalAlias
* cloneGlobalAliasDecl(Module
&Dst
, const GlobalAlias
&OrigA
,
352 ValueToValueMapTy
&VMap
) {
353 assert(OrigA
.getAliasee() && "Original alias doesn't have an aliasee?");
354 auto *NewA
= GlobalAlias::create(OrigA
.getValueType(),
355 OrigA
.getType()->getPointerAddressSpace(),
356 OrigA
.getLinkage(), OrigA
.getName(), &Dst
);
357 NewA
->copyAttributesFrom(&OrigA
);
362 void cloneModuleFlagsMetadata(Module
&Dst
, const Module
&Src
,
363 ValueToValueMapTy
&VMap
) {
364 auto *MFs
= Src
.getModuleFlagsMetadata();
367 for (auto *MF
: MFs
->operands())
368 Dst
.addModuleFlag(MapMetadata(MF
, VMap
));
371 } // End namespace orc.
372 } // End namespace llvm.