Skip to content

Commit 01effcd

Browse files
authored
[ORC] Add, and call through, reoptimize function in ReOptimizeLayer. (#173204)
ReOptimizeLayer was building LLVM IR to define a precomputed, SPS-serialized argument buffer, then inserting calls directly to __orc_rt_jit_dispatch, passing the address of the precomputed buffer and an __orc_rt_reoptimize_tag defined by the ORC runtime. This design is non-canonical, requiring the ORC runtime to be loaded (or an extra definition for __orc_rt_reoptimize_tag to be inserted) while not using the runtime to perform the serialization. This commit updates ReOptimizeLayer to instead insert calls to an __orc_rt_reoptimize function implemented in the ORC runtime. This function will perform serialization and call __orc_rt_jit_dispatch, similar to other functions in the ORC runtime. To maintain support for in-process JITs that don't use the ORC runtime, this commit adds a ReOptimizeLayer::addOrcRTLiteSupport method which injects IR to define __orc_rt_reoptimize (calling through to an orc_rt_lite_reoptimize_helper function defined in LLVM) and __orc_rt_reoptimize_tag. The ReOptimizeLayerTest is updated to use addOrcRTLiteSupport.
1 parent b836942 commit 01effcd

File tree

6 files changed

+153
-64
lines changed

6 files changed

+153
-64
lines changed

compiler-rt/lib/orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
set(ORC_COMMON_SOURCES
55
debug.cpp
66
dlfcn_wrapper.cpp
7+
reoptimize.cpp
78
rtti.cpp
89
log_error_to_stderr.cpp
910
run_program_wrapper.cpp

compiler-rt/lib/orc/elfnix_platform.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ using namespace orc_rt;
3030
using namespace orc_rt::elfnix;
3131

3232
// Declare function tags for functions in the JIT process.
33-
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_reoptimize_tag)
3433
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_push_initializers_tag)
3534
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag)
3635

compiler-rt/lib/orc/reoptimize.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- reoptimize.cpp -----------------------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains code required to load the rest of the ELF-on-*IX runtime.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "jit_dispatch.h"
14+
#include "wrapper_function_utils.h"
15+
16+
using namespace orc_rt;
17+
18+
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_reoptimize_tag)
19+
20+
ORC_RT_INTERFACE void __orc_rt_reoptimize(uint64_t MUID, uint32_t CurVersion) {
21+
if (auto Err = WrapperFunction<void(uint64_t, uint32_t)>::call(
22+
JITDispatch(&__orc_rt_reoptimize_tag), MUID, CurVersion)) {
23+
__orc_rt_log_error(toString(std::move(Err)).c_str());
24+
// FIXME: Should we abort here? Depending on the error we can't guarantee
25+
// that the JIT'd code is in a consistent state.
26+
}
27+
}

llvm/include/llvm/ExecutionEngine/Orc/ReOptimizeLayer.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ class LLVM_ABI ReOptimizeLayer : public IRLayer, public ResourceManager {
6060
this->ProfilerFunc = std::move(ProfilerFunc);
6161
}
6262

63+
/// Add ORC Runtime-lite support for reoptimization to PlatformJD.
64+
///
65+
/// This allows reoptimization to be used without the ORC runtime.
66+
///
67+
/// WARNING: For use with in-process JITs only.
68+
/// WARNING: Do not use if the ORC runtime is loaded, as this will introduce
69+
/// duplicate definitions.
70+
Error addOrcRTLiteSupport(JITDylib &PlatformJD, const DataLayout &DL);
71+
6372
/// Registers reoptimize runtime dispatch handlers to given PlatformJD. The
6473
/// reoptimization request will not be handled if dispatch handler is not
6574
/// registered by using this function.
@@ -87,7 +96,8 @@ class LLVM_ABI ReOptimizeLayer : public IRLayer, public ResourceManager {
8796

8897
// Create IR reoptimize request fucntion call.
8998
static void createReoptimizeCall(Module &M, Instruction &IP,
90-
GlobalVariable *ArgBuffer);
99+
ReOptMaterializationUnitID MUID,
100+
unsigned CurVersion);
91101

92102
Error handleRemoveResources(JITDylib &JD, ResourceKey K) override;
93103
void handleTransferResources(JITDylib &JD, ResourceKey DstK,
@@ -148,10 +158,6 @@ class LLVM_ABI ReOptimizeLayer : public IRLayer, public ResourceManager {
148158
void rt_reoptimize(SendErrorFn SendResult, ReOptMaterializationUnitID MUID,
149159
uint32_t CurVersion);
150160

151-
static Expected<Constant *>
152-
createReoptimizeArgBuffer(Module &M, ReOptMaterializationUnitID MUID,
153-
uint32_t CurVersion);
154-
155161
ReOptMaterializationUnitState &
156162
createMaterializationUnitState(const ThreadSafeModule &TSM);
157163

llvm/lib/ExecutionEngine/Orc/ReOptimizeLayer.cpp

Lines changed: 111 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,103 @@ void ReOptimizeLayer::ReOptMaterializationUnitState::reoptimizeFailed() {
2626
Reoptimizing = false;
2727
}
2828

29+
static void orc_rt_lite_reoptimize_helper(
30+
shared::CWrapperFunctionBuffer (*JITDispatch)(void *Ctx, void *Tag,
31+
void *Data, size_t Size),
32+
void *JITDispatchCtx, void *Tag, uint64_t MUID, uint32_t CurVersion) {
33+
// Serialize the arguments into a WrapperFunctionBuffer and call dispatch.
34+
using SPSArgs = shared::SPSArgList<uint64_t, uint32_t>;
35+
auto ArgBytes =
36+
shared::WrapperFunctionBuffer::allocate(SPSArgs::size(MUID, CurVersion));
37+
shared::SPSOutputBuffer OB(ArgBytes.data(), ArgBytes.size());
38+
if (!SPSArgs::serialize(OB, MUID, CurVersion)) {
39+
errs()
40+
<< "Reoptimization error: could not serialize reoptimization arguments";
41+
abort();
42+
}
43+
shared::WrapperFunctionBuffer Buf{
44+
JITDispatch(JITDispatchCtx, Tag, ArgBytes.data(), ArgBytes.size())};
45+
46+
if (const char *ErrMsg = Buf.getOutOfBandError()) {
47+
errs() << "Reoptimization error: " << ErrMsg << "\naborting.\n";
48+
abort();
49+
}
50+
}
51+
52+
Error ReOptimizeLayer::addOrcRTLiteSupport(JITDylib &PlatformJD,
53+
const DataLayout &DL) {
54+
auto Ctx = std::make_unique<LLVMContext>();
55+
auto Mod = std::make_unique<Module>("orc-rt-lite-reoptimize.ll", *Ctx);
56+
Mod->setDataLayout(DL);
57+
58+
IRBuilder<> Builder(*Ctx);
59+
60+
// Create basic types portably
61+
Type *VoidTy = Type::getVoidTy(*Ctx);
62+
Type *Int8Ty = Type::getInt8Ty(*Ctx);
63+
Type *Int32Ty = Type::getInt32Ty(*Ctx);
64+
Type *Int64Ty = Type::getInt64Ty(*Ctx);
65+
Type *VoidPtrTy = PointerType::getUnqual(*Ctx);
66+
67+
// Helper function type: void (void*, void*, void*, uint64_t, uint32_t)
68+
FunctionType *HelperFnTy = FunctionType::get(
69+
VoidTy, {VoidPtrTy, VoidPtrTy, VoidPtrTy, Int64Ty, Int32Ty}, false);
70+
71+
// Define ReoptimizeTag with initializer = 0
72+
GlobalVariable *ReoptimizeTag = new GlobalVariable(
73+
*Mod, Int8Ty, false, GlobalValue::ExternalLinkage,
74+
ConstantInt::get(Int8Ty, 0), "__orc_rt_reoptimize_tag");
75+
76+
// Define orc_rt_lite_reoptimize function: void (uint64_t, uint32_t)
77+
FunctionType *ReOptimizeFnTy =
78+
FunctionType::get(VoidTy, {Int64Ty, Int32Ty}, false);
79+
80+
Function *ReOptimizeFn =
81+
Function::Create(ReOptimizeFnTy, Function::ExternalLinkage,
82+
"__orc_rt_reoptimize", Mod.get());
83+
84+
// Set parameter names
85+
auto ArgIt = ReOptimizeFn->arg_begin();
86+
Value *MUID = &*ArgIt++;
87+
MUID->setName("MUID");
88+
Value *CurVersion = &*ArgIt;
89+
CurVersion->setName("CurVersion");
90+
91+
// Build function body
92+
BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ReOptimizeFn);
93+
Builder.SetInsertPoint(Entry);
94+
95+
// Create absolute address constants
96+
auto &JDI = PlatformJD.getExecutionSession()
97+
.getExecutorProcessControl()
98+
.getJITDispatchInfo();
99+
100+
Type *IntPtrTy = DL.getIntPtrType(*Ctx);
101+
Constant *JITDispatchPtr = ConstantExpr::getIntToPtr(
102+
ConstantInt::get(IntPtrTy, JDI.JITDispatchFunction.getValue()),
103+
VoidPtrTy);
104+
Constant *JITDispatchCtxPtr = ConstantExpr::getIntToPtr(
105+
ConstantInt::get(IntPtrTy, JDI.JITDispatchContext.getValue()), VoidPtrTy);
106+
Constant *HelperFnAddr = ConstantExpr::getIntToPtr(
107+
ConstantInt::get(IntPtrTy, reinterpret_cast<uintptr_t>(
108+
&orc_rt_lite_reoptimize_helper)),
109+
PointerType::getUnqual(*Ctx));
110+
111+
// Cast ReoptimizeTag to void*
112+
Value *ReoptimizeTagPtr = Builder.CreatePointerCast(ReoptimizeTag, VoidPtrTy);
113+
114+
// Call the helper function
115+
Builder.CreateCall(
116+
HelperFnTy, HelperFnAddr,
117+
{JITDispatchPtr, JITDispatchCtxPtr, ReoptimizeTagPtr, MUID, CurVersion});
118+
119+
// Return void
120+
Builder.CreateRetVoid();
121+
122+
return BaseLayer.add(PlatformJD,
123+
ThreadSafeModule(std::move(Mod), std::move(Ctx)));
124+
}
125+
29126
Error ReOptimizeLayer::registerRuntimeFunctions(JITDylib &PlatformJD) {
30127
ExecutionSession::JITDispatchHandlerAssociationMap WFs;
31128
using ReoptimizeSPSSig = shared::SPSError(uint64_t, uint32_t);
@@ -88,12 +185,6 @@ Error ReOptimizeLayer::reoptimizeIfCallFrequent(ReOptimizeLayer &Parent,
88185
GlobalVariable *Counter = new GlobalVariable(
89186
M, I64Ty, false, GlobalValue::InternalLinkage,
90187
Constant::getNullValue(I64Ty), "__orc_reopt_counter");
91-
auto ArgBufferConst = createReoptimizeArgBuffer(M, MUID, CurVersion);
92-
if (auto Err = ArgBufferConst.takeError())
93-
return Err;
94-
GlobalVariable *ArgBuffer =
95-
new GlobalVariable(M, (*ArgBufferConst)->getType(), true,
96-
GlobalValue::InternalLinkage, (*ArgBufferConst));
97188
for (auto &F : M) {
98189
if (F.isDeclaration())
99190
continue;
@@ -107,7 +198,7 @@ Error ReOptimizeLayer::reoptimizeIfCallFrequent(ReOptimizeLayer &Parent,
107198
Value *Added = IRB.CreateAdd(Cnt, ConstantInt::get(I64Ty, 1));
108199
(void)IRB.CreateStore(Added, Counter);
109200
Instruction *SplitTerminator = SplitBlockAndInsertIfThen(Cmp, IP, false);
110-
createReoptimizeCall(M, *SplitTerminator, ArgBuffer);
201+
createReoptimizeCall(M, *SplitTerminator, MUID, CurVersion);
111202
}
112203
return Error::success();
113204
});
@@ -195,49 +286,23 @@ void ReOptimizeLayer::rt_reoptimize(SendErrorFn SendResult,
195286
SendResult(Error::success());
196287
}
197288

198-
Expected<Constant *> ReOptimizeLayer::createReoptimizeArgBuffer(
199-
Module &M, ReOptMaterializationUnitID MUID, uint32_t CurVersion) {
200-
size_t ArgBufferSize = SPSReoptimizeArgList::size(MUID, CurVersion);
201-
std::vector<char> ArgBuffer(ArgBufferSize);
202-
shared::SPSOutputBuffer OB(ArgBuffer.data(), ArgBuffer.size());
203-
if (!SPSReoptimizeArgList::serialize(OB, MUID, CurVersion))
204-
return make_error<StringError>("Could not serealize args list",
205-
inconvertibleErrorCode());
206-
return ConstantDataArray::get(M.getContext(), ArrayRef(ArgBuffer));
207-
}
208-
209289
void ReOptimizeLayer::createReoptimizeCall(Module &M, Instruction &IP,
210-
GlobalVariable *ArgBuffer) {
211-
GlobalVariable *DispatchCtx =
212-
M.getGlobalVariable("__orc_rt_jit_dispatch_ctx");
213-
if (!DispatchCtx)
214-
DispatchCtx = new GlobalVariable(M, PointerType::get(M.getContext(), 0),
215-
false, GlobalValue::ExternalLinkage,
216-
nullptr, "__orc_rt_jit_dispatch_ctx");
217-
GlobalVariable *ReoptimizeTag =
218-
M.getGlobalVariable("__orc_rt_reoptimize_tag");
219-
if (!ReoptimizeTag)
220-
ReoptimizeTag = new GlobalVariable(M, PointerType::get(M.getContext(), 0),
221-
false, GlobalValue::ExternalLinkage,
222-
nullptr, "__orc_rt_reoptimize_tag");
223-
Function *DispatchFunc = M.getFunction("__orc_rt_jit_dispatch");
224-
if (!DispatchFunc) {
225-
std::vector<Type *> Args = {PointerType::get(M.getContext(), 0),
226-
PointerType::get(M.getContext(), 0),
227-
PointerType::get(M.getContext(), 0),
228-
IntegerType::get(M.getContext(), 64)};
290+
ReOptMaterializationUnitID MUID,
291+
uint32_t CurVersion) {
292+
Type *MUIDTy = IntegerType::get(M.getContext(), 64);
293+
Type *VersionTy = IntegerType::get(M.getContext(), 32);
294+
Function *ReoptimizeFunc = M.getFunction("__orc_rt_reoptimize");
295+
if (!ReoptimizeFunc) {
296+
std::vector<Type *> ArgTys = {MUIDTy, VersionTy};
229297
FunctionType *FuncTy =
230-
FunctionType::get(Type::getVoidTy(M.getContext()), Args, false);
231-
DispatchFunc = Function::Create(FuncTy, GlobalValue::ExternalLinkage,
232-
"__orc_rt_jit_dispatch", &M);
298+
FunctionType::get(Type::getVoidTy(M.getContext()), ArgTys, false);
299+
ReoptimizeFunc = Function::Create(FuncTy, GlobalValue::ExternalLinkage,
300+
"__orc_rt_reoptimize", &M);
233301
}
234-
size_t ArgBufferSizeConst =
235-
SPSReoptimizeArgList::size(ReOptMaterializationUnitID{}, uint32_t{});
236-
Constant *ArgBufferSize = ConstantInt::get(
237-
IntegerType::get(M.getContext(), 64), ArgBufferSizeConst, false);
302+
Constant *MUIDArg = ConstantInt::get(MUIDTy, MUID, false);
303+
Constant *CurVersionArg = ConstantInt::get(VersionTy, CurVersion, false);
238304
IRBuilder<> IRB(&IP);
239-
(void)IRB.CreateCall(DispatchFunc,
240-
{DispatchCtx, ReoptimizeTag, ArgBuffer, ArgBufferSize});
305+
(void)IRB.CreateCall(ReoptimizeFunc, {MUIDArg, CurVersionArg});
241306
}
242307

243308
ReOptimizeLayer::ReOptMaterializationUnitState &

llvm/unittests/ExecutionEngine/Orc/ReOptimizeLayerTest.cpp

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,13 @@ static Function *createRetFunction(Module *M, StringRef Name,
140140
TEST_F(ReOptimizeLayerTest, BasicReOptimization) {
141141
MangleAndInterner Mangle(*ES, *DL);
142142

143-
auto &EPC = ES->getExecutorProcessControl();
144-
EXPECT_THAT_ERROR(JD->define(absoluteSymbols(
145-
{{Mangle("__orc_rt_jit_dispatch"),
146-
{EPC.getJITDispatchInfo().JITDispatchFunction,
147-
JITSymbolFlags::Exported}},
148-
{Mangle("__orc_rt_jit_dispatch_ctx"),
149-
{EPC.getJITDispatchInfo().JITDispatchContext,
150-
JITSymbolFlags::Exported}},
151-
{Mangle("__orc_rt_reoptimize_tag"),
152-
{ExecutorAddr(), JITSymbolFlags::Exported}}})),
153-
Succeeded());
154-
155143
auto RM = JITLinkRedirectableSymbolManager::Create(*ObjLinkingLayer);
156144
EXPECT_THAT_ERROR(RM.takeError(), Succeeded());
157145

158146
ROLayer = std::make_unique<ReOptimizeLayer>(*ES, *DL, *CompileLayer, **RM);
147+
if (auto Err = ROLayer->addOrcRTLiteSupport(*JD, *DL))
148+
FAIL() << toString(std::move(Err));
149+
159150
ROLayer->setReoptimizeFunc(
160151
[&](ReOptimizeLayer &Parent,
161152
ReOptimizeLayer::ReOptMaterializationUnitID MUID, unsigned CurVerison,

0 commit comments

Comments
 (0)