1*700637cbSDimitry Andric #include "llvm/ExecutionEngine/Orc/ReOptimizeLayer.h"
2*700637cbSDimitry Andric #include "llvm/ExecutionEngine/Orc/Mangling.h"
3*700637cbSDimitry Andric
4*700637cbSDimitry Andric using namespace llvm;
5*700637cbSDimitry Andric using namespace orc;
6*700637cbSDimitry Andric
tryStartReoptimize()7*700637cbSDimitry Andric bool ReOptimizeLayer::ReOptMaterializationUnitState::tryStartReoptimize() {
8*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
9*700637cbSDimitry Andric if (Reoptimizing)
10*700637cbSDimitry Andric return false;
11*700637cbSDimitry Andric
12*700637cbSDimitry Andric Reoptimizing = true;
13*700637cbSDimitry Andric return true;
14*700637cbSDimitry Andric }
15*700637cbSDimitry Andric
reoptimizeSucceeded()16*700637cbSDimitry Andric void ReOptimizeLayer::ReOptMaterializationUnitState::reoptimizeSucceeded() {
17*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
18*700637cbSDimitry Andric assert(Reoptimizing && "Tried to mark unstarted reoptimization as done");
19*700637cbSDimitry Andric Reoptimizing = false;
20*700637cbSDimitry Andric CurVersion++;
21*700637cbSDimitry Andric }
22*700637cbSDimitry Andric
reoptimizeFailed()23*700637cbSDimitry Andric void ReOptimizeLayer::ReOptMaterializationUnitState::reoptimizeFailed() {
24*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
25*700637cbSDimitry Andric assert(Reoptimizing && "Tried to mark unstarted reoptimization as done");
26*700637cbSDimitry Andric Reoptimizing = false;
27*700637cbSDimitry Andric }
28*700637cbSDimitry Andric
reigsterRuntimeFunctions(JITDylib & PlatformJD)29*700637cbSDimitry Andric Error ReOptimizeLayer::reigsterRuntimeFunctions(JITDylib &PlatformJD) {
30*700637cbSDimitry Andric ExecutionSession::JITDispatchHandlerAssociationMap WFs;
31*700637cbSDimitry Andric using ReoptimizeSPSSig = shared::SPSError(uint64_t, uint32_t);
32*700637cbSDimitry Andric WFs[Mangle("__orc_rt_reoptimize_tag")] =
33*700637cbSDimitry Andric ES.wrapAsyncWithSPS<ReoptimizeSPSSig>(this,
34*700637cbSDimitry Andric &ReOptimizeLayer::rt_reoptimize);
35*700637cbSDimitry Andric return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
36*700637cbSDimitry Andric }
37*700637cbSDimitry Andric
emit(std::unique_ptr<MaterializationResponsibility> R,ThreadSafeModule TSM)38*700637cbSDimitry Andric void ReOptimizeLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
39*700637cbSDimitry Andric ThreadSafeModule TSM) {
40*700637cbSDimitry Andric auto &JD = R->getTargetJITDylib();
41*700637cbSDimitry Andric
42*700637cbSDimitry Andric bool HasNonCallable = false;
43*700637cbSDimitry Andric for (auto &KV : R->getSymbols()) {
44*700637cbSDimitry Andric auto &Flags = KV.second;
45*700637cbSDimitry Andric if (!Flags.isCallable())
46*700637cbSDimitry Andric HasNonCallable = true;
47*700637cbSDimitry Andric }
48*700637cbSDimitry Andric
49*700637cbSDimitry Andric if (HasNonCallable) {
50*700637cbSDimitry Andric BaseLayer.emit(std::move(R), std::move(TSM));
51*700637cbSDimitry Andric return;
52*700637cbSDimitry Andric }
53*700637cbSDimitry Andric
54*700637cbSDimitry Andric auto &MUState = createMaterializationUnitState(TSM);
55*700637cbSDimitry Andric
56*700637cbSDimitry Andric if (auto Err = R->withResourceKeyDo([&](ResourceKey Key) {
57*700637cbSDimitry Andric registerMaterializationUnitResource(Key, MUState);
58*700637cbSDimitry Andric })) {
59*700637cbSDimitry Andric ES.reportError(std::move(Err));
60*700637cbSDimitry Andric R->failMaterialization();
61*700637cbSDimitry Andric return;
62*700637cbSDimitry Andric }
63*700637cbSDimitry Andric
64*700637cbSDimitry Andric if (auto Err =
65*700637cbSDimitry Andric ProfilerFunc(*this, MUState.getID(), MUState.getCurVersion(), TSM)) {
66*700637cbSDimitry Andric ES.reportError(std::move(Err));
67*700637cbSDimitry Andric R->failMaterialization();
68*700637cbSDimitry Andric return;
69*700637cbSDimitry Andric }
70*700637cbSDimitry Andric
71*700637cbSDimitry Andric auto InitialDests =
72*700637cbSDimitry Andric emitMUImplSymbols(MUState, MUState.getCurVersion(), JD, std::move(TSM));
73*700637cbSDimitry Andric if (!InitialDests) {
74*700637cbSDimitry Andric ES.reportError(InitialDests.takeError());
75*700637cbSDimitry Andric R->failMaterialization();
76*700637cbSDimitry Andric return;
77*700637cbSDimitry Andric }
78*700637cbSDimitry Andric
79*700637cbSDimitry Andric RSManager.emitRedirectableSymbols(std::move(R), std::move(*InitialDests));
80*700637cbSDimitry Andric }
81*700637cbSDimitry Andric
reoptimizeIfCallFrequent(ReOptimizeLayer & Parent,ReOptMaterializationUnitID MUID,unsigned CurVersion,ThreadSafeModule & TSM)82*700637cbSDimitry Andric Error ReOptimizeLayer::reoptimizeIfCallFrequent(ReOptimizeLayer &Parent,
83*700637cbSDimitry Andric ReOptMaterializationUnitID MUID,
84*700637cbSDimitry Andric unsigned CurVersion,
85*700637cbSDimitry Andric ThreadSafeModule &TSM) {
86*700637cbSDimitry Andric return TSM.withModuleDo([&](Module &M) -> Error {
87*700637cbSDimitry Andric Type *I64Ty = Type::getInt64Ty(M.getContext());
88*700637cbSDimitry Andric GlobalVariable *Counter = new GlobalVariable(
89*700637cbSDimitry Andric M, I64Ty, false, GlobalValue::InternalLinkage,
90*700637cbSDimitry Andric Constant::getNullValue(I64Ty), "__orc_reopt_counter");
91*700637cbSDimitry Andric auto ArgBufferConst = createReoptimizeArgBuffer(M, MUID, CurVersion);
92*700637cbSDimitry Andric if (auto Err = ArgBufferConst.takeError())
93*700637cbSDimitry Andric return Err;
94*700637cbSDimitry Andric GlobalVariable *ArgBuffer =
95*700637cbSDimitry Andric new GlobalVariable(M, (*ArgBufferConst)->getType(), true,
96*700637cbSDimitry Andric GlobalValue::InternalLinkage, (*ArgBufferConst));
97*700637cbSDimitry Andric for (auto &F : M) {
98*700637cbSDimitry Andric if (F.isDeclaration())
99*700637cbSDimitry Andric continue;
100*700637cbSDimitry Andric auto &BB = F.getEntryBlock();
101*700637cbSDimitry Andric auto *IP = &*BB.getFirstInsertionPt();
102*700637cbSDimitry Andric IRBuilder<> IRB(IP);
103*700637cbSDimitry Andric Value *Threshold = ConstantInt::get(I64Ty, CallCountThreshold, true);
104*700637cbSDimitry Andric Value *Cnt = IRB.CreateLoad(I64Ty, Counter);
105*700637cbSDimitry Andric // Use EQ to prevent further reoptimize calls.
106*700637cbSDimitry Andric Value *Cmp = IRB.CreateICmpEQ(Cnt, Threshold);
107*700637cbSDimitry Andric Value *Added = IRB.CreateAdd(Cnt, ConstantInt::get(I64Ty, 1));
108*700637cbSDimitry Andric (void)IRB.CreateStore(Added, Counter);
109*700637cbSDimitry Andric Instruction *SplitTerminator = SplitBlockAndInsertIfThen(Cmp, IP, false);
110*700637cbSDimitry Andric createReoptimizeCall(M, *SplitTerminator, ArgBuffer);
111*700637cbSDimitry Andric }
112*700637cbSDimitry Andric return Error::success();
113*700637cbSDimitry Andric });
114*700637cbSDimitry Andric }
115*700637cbSDimitry Andric
116*700637cbSDimitry Andric Expected<SymbolMap>
emitMUImplSymbols(ReOptMaterializationUnitState & MUState,uint32_t Version,JITDylib & JD,ThreadSafeModule TSM)117*700637cbSDimitry Andric ReOptimizeLayer::emitMUImplSymbols(ReOptMaterializationUnitState &MUState,
118*700637cbSDimitry Andric uint32_t Version, JITDylib &JD,
119*700637cbSDimitry Andric ThreadSafeModule TSM) {
120*700637cbSDimitry Andric DenseMap<SymbolStringPtr, SymbolStringPtr> RenamedMap;
121*700637cbSDimitry Andric cantFail(TSM.withModuleDo([&](Module &M) -> Error {
122*700637cbSDimitry Andric MangleAndInterner Mangle(ES, M.getDataLayout());
123*700637cbSDimitry Andric for (auto &F : M)
124*700637cbSDimitry Andric if (!F.isDeclaration()) {
125*700637cbSDimitry Andric std::string NewName =
126*700637cbSDimitry Andric (F.getName() + ".__def__." + Twine(Version)).str();
127*700637cbSDimitry Andric RenamedMap[Mangle(F.getName())] = Mangle(NewName);
128*700637cbSDimitry Andric F.setName(NewName);
129*700637cbSDimitry Andric }
130*700637cbSDimitry Andric return Error::success();
131*700637cbSDimitry Andric }));
132*700637cbSDimitry Andric
133*700637cbSDimitry Andric auto RT = JD.createResourceTracker();
134*700637cbSDimitry Andric if (auto Err =
135*700637cbSDimitry Andric JD.define(std::make_unique<BasicIRLayerMaterializationUnit>(
136*700637cbSDimitry Andric BaseLayer, *getManglingOptions(), std::move(TSM)),
137*700637cbSDimitry Andric RT))
138*700637cbSDimitry Andric return Err;
139*700637cbSDimitry Andric MUState.setResourceTracker(RT);
140*700637cbSDimitry Andric
141*700637cbSDimitry Andric SymbolLookupSet LookupSymbols;
142*700637cbSDimitry Andric for (auto [K, V] : RenamedMap)
143*700637cbSDimitry Andric LookupSymbols.add(V);
144*700637cbSDimitry Andric
145*700637cbSDimitry Andric auto ImplSymbols =
146*700637cbSDimitry Andric ES.lookup({{&JD, JITDylibLookupFlags::MatchAllSymbols}}, LookupSymbols,
147*700637cbSDimitry Andric LookupKind::Static, SymbolState::Resolved);
148*700637cbSDimitry Andric if (auto Err = ImplSymbols.takeError())
149*700637cbSDimitry Andric return Err;
150*700637cbSDimitry Andric
151*700637cbSDimitry Andric SymbolMap Result;
152*700637cbSDimitry Andric for (auto [K, V] : RenamedMap)
153*700637cbSDimitry Andric Result[K] = (*ImplSymbols)[V];
154*700637cbSDimitry Andric
155*700637cbSDimitry Andric return Result;
156*700637cbSDimitry Andric }
157*700637cbSDimitry Andric
rt_reoptimize(SendErrorFn SendResult,ReOptMaterializationUnitID MUID,uint32_t CurVersion)158*700637cbSDimitry Andric void ReOptimizeLayer::rt_reoptimize(SendErrorFn SendResult,
159*700637cbSDimitry Andric ReOptMaterializationUnitID MUID,
160*700637cbSDimitry Andric uint32_t CurVersion) {
161*700637cbSDimitry Andric auto &MUState = getMaterializationUnitState(MUID);
162*700637cbSDimitry Andric if (CurVersion < MUState.getCurVersion() || !MUState.tryStartReoptimize()) {
163*700637cbSDimitry Andric SendResult(Error::success());
164*700637cbSDimitry Andric return;
165*700637cbSDimitry Andric }
166*700637cbSDimitry Andric
167*700637cbSDimitry Andric ThreadSafeModule TSM = cloneToNewContext(MUState.getThreadSafeModule());
168*700637cbSDimitry Andric auto OldRT = MUState.getResourceTracker();
169*700637cbSDimitry Andric auto &JD = OldRT->getJITDylib();
170*700637cbSDimitry Andric
171*700637cbSDimitry Andric if (auto Err = ReOptFunc(*this, MUID, CurVersion + 1, OldRT, TSM)) {
172*700637cbSDimitry Andric ES.reportError(std::move(Err));
173*700637cbSDimitry Andric MUState.reoptimizeFailed();
174*700637cbSDimitry Andric SendResult(Error::success());
175*700637cbSDimitry Andric return;
176*700637cbSDimitry Andric }
177*700637cbSDimitry Andric
178*700637cbSDimitry Andric auto SymbolDests =
179*700637cbSDimitry Andric emitMUImplSymbols(MUState, CurVersion + 1, JD, std::move(TSM));
180*700637cbSDimitry Andric if (!SymbolDests) {
181*700637cbSDimitry Andric ES.reportError(SymbolDests.takeError());
182*700637cbSDimitry Andric MUState.reoptimizeFailed();
183*700637cbSDimitry Andric SendResult(Error::success());
184*700637cbSDimitry Andric return;
185*700637cbSDimitry Andric }
186*700637cbSDimitry Andric
187*700637cbSDimitry Andric if (auto Err = RSManager.redirect(JD, std::move(*SymbolDests))) {
188*700637cbSDimitry Andric ES.reportError(std::move(Err));
189*700637cbSDimitry Andric MUState.reoptimizeFailed();
190*700637cbSDimitry Andric SendResult(Error::success());
191*700637cbSDimitry Andric return;
192*700637cbSDimitry Andric }
193*700637cbSDimitry Andric
194*700637cbSDimitry Andric MUState.reoptimizeSucceeded();
195*700637cbSDimitry Andric SendResult(Error::success());
196*700637cbSDimitry Andric }
197*700637cbSDimitry Andric
createReoptimizeArgBuffer(Module & M,ReOptMaterializationUnitID MUID,uint32_t CurVersion)198*700637cbSDimitry Andric Expected<Constant *> ReOptimizeLayer::createReoptimizeArgBuffer(
199*700637cbSDimitry Andric Module &M, ReOptMaterializationUnitID MUID, uint32_t CurVersion) {
200*700637cbSDimitry Andric size_t ArgBufferSize = SPSReoptimizeArgList::size(MUID, CurVersion);
201*700637cbSDimitry Andric std::vector<char> ArgBuffer(ArgBufferSize);
202*700637cbSDimitry Andric shared::SPSOutputBuffer OB(ArgBuffer.data(), ArgBuffer.size());
203*700637cbSDimitry Andric if (!SPSReoptimizeArgList::serialize(OB, MUID, CurVersion))
204*700637cbSDimitry Andric return make_error<StringError>("Could not serealize args list",
205*700637cbSDimitry Andric inconvertibleErrorCode());
206*700637cbSDimitry Andric return ConstantDataArray::get(M.getContext(), ArrayRef(ArgBuffer));
207*700637cbSDimitry Andric }
208*700637cbSDimitry Andric
createReoptimizeCall(Module & M,Instruction & IP,GlobalVariable * ArgBuffer)209*700637cbSDimitry Andric void ReOptimizeLayer::createReoptimizeCall(Module &M, Instruction &IP,
210*700637cbSDimitry Andric GlobalVariable *ArgBuffer) {
211*700637cbSDimitry Andric GlobalVariable *DispatchCtx =
212*700637cbSDimitry Andric M.getGlobalVariable("__orc_rt_jit_dispatch_ctx");
213*700637cbSDimitry Andric if (!DispatchCtx)
214*700637cbSDimitry Andric DispatchCtx = new GlobalVariable(M, PointerType::get(M.getContext(), 0),
215*700637cbSDimitry Andric false, GlobalValue::ExternalLinkage,
216*700637cbSDimitry Andric nullptr, "__orc_rt_jit_dispatch_ctx");
217*700637cbSDimitry Andric GlobalVariable *ReoptimizeTag =
218*700637cbSDimitry Andric M.getGlobalVariable("__orc_rt_reoptimize_tag");
219*700637cbSDimitry Andric if (!ReoptimizeTag)
220*700637cbSDimitry Andric ReoptimizeTag = new GlobalVariable(M, PointerType::get(M.getContext(), 0),
221*700637cbSDimitry Andric false, GlobalValue::ExternalLinkage,
222*700637cbSDimitry Andric nullptr, "__orc_rt_reoptimize_tag");
223*700637cbSDimitry Andric Function *DispatchFunc = M.getFunction("__orc_rt_jit_dispatch");
224*700637cbSDimitry Andric if (!DispatchFunc) {
225*700637cbSDimitry Andric std::vector<Type *> Args = {PointerType::get(M.getContext(), 0),
226*700637cbSDimitry Andric PointerType::get(M.getContext(), 0),
227*700637cbSDimitry Andric PointerType::get(M.getContext(), 0),
228*700637cbSDimitry Andric IntegerType::get(M.getContext(), 64)};
229*700637cbSDimitry Andric FunctionType *FuncTy =
230*700637cbSDimitry Andric FunctionType::get(Type::getVoidTy(M.getContext()), Args, false);
231*700637cbSDimitry Andric DispatchFunc = Function::Create(FuncTy, GlobalValue::ExternalLinkage,
232*700637cbSDimitry Andric "__orc_rt_jit_dispatch", &M);
233*700637cbSDimitry Andric }
234*700637cbSDimitry Andric size_t ArgBufferSizeConst =
235*700637cbSDimitry Andric SPSReoptimizeArgList::size(ReOptMaterializationUnitID{}, uint32_t{});
236*700637cbSDimitry Andric Constant *ArgBufferSize = ConstantInt::get(
237*700637cbSDimitry Andric IntegerType::get(M.getContext(), 64), ArgBufferSizeConst, false);
238*700637cbSDimitry Andric IRBuilder<> IRB(&IP);
239*700637cbSDimitry Andric (void)IRB.CreateCall(DispatchFunc,
240*700637cbSDimitry Andric {DispatchCtx, ReoptimizeTag, ArgBuffer, ArgBufferSize});
241*700637cbSDimitry Andric }
242*700637cbSDimitry Andric
243*700637cbSDimitry Andric ReOptimizeLayer::ReOptMaterializationUnitState &
createMaterializationUnitState(const ThreadSafeModule & TSM)244*700637cbSDimitry Andric ReOptimizeLayer::createMaterializationUnitState(const ThreadSafeModule &TSM) {
245*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
246*700637cbSDimitry Andric ReOptMaterializationUnitID MUID = NextID;
247*700637cbSDimitry Andric MUStates.emplace(MUID,
248*700637cbSDimitry Andric ReOptMaterializationUnitState(MUID, cloneToNewContext(TSM)));
249*700637cbSDimitry Andric ++NextID;
250*700637cbSDimitry Andric return MUStates.at(MUID);
251*700637cbSDimitry Andric }
252*700637cbSDimitry Andric
253*700637cbSDimitry Andric ReOptimizeLayer::ReOptMaterializationUnitState &
getMaterializationUnitState(ReOptMaterializationUnitID MUID)254*700637cbSDimitry Andric ReOptimizeLayer::getMaterializationUnitState(ReOptMaterializationUnitID MUID) {
255*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
256*700637cbSDimitry Andric return MUStates.at(MUID);
257*700637cbSDimitry Andric }
258*700637cbSDimitry Andric
registerMaterializationUnitResource(ResourceKey Key,ReOptMaterializationUnitState & State)259*700637cbSDimitry Andric void ReOptimizeLayer::registerMaterializationUnitResource(
260*700637cbSDimitry Andric ResourceKey Key, ReOptMaterializationUnitState &State) {
261*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
262*700637cbSDimitry Andric MUResources[Key].insert(State.getID());
263*700637cbSDimitry Andric }
264*700637cbSDimitry Andric
handleRemoveResources(JITDylib & JD,ResourceKey K)265*700637cbSDimitry Andric Error ReOptimizeLayer::handleRemoveResources(JITDylib &JD, ResourceKey K) {
266*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
267*700637cbSDimitry Andric for (auto MUID : MUResources[K])
268*700637cbSDimitry Andric MUStates.erase(MUID);
269*700637cbSDimitry Andric
270*700637cbSDimitry Andric MUResources.erase(K);
271*700637cbSDimitry Andric return Error::success();
272*700637cbSDimitry Andric }
273*700637cbSDimitry Andric
handleTransferResources(JITDylib & JD,ResourceKey DstK,ResourceKey SrcK)274*700637cbSDimitry Andric void ReOptimizeLayer::handleTransferResources(JITDylib &JD, ResourceKey DstK,
275*700637cbSDimitry Andric ResourceKey SrcK) {
276*700637cbSDimitry Andric std::unique_lock<std::mutex> Lock(Mutex);
277*700637cbSDimitry Andric MUResources[DstK].insert_range(MUResources[SrcK]);
278*700637cbSDimitry Andric MUResources.erase(SrcK);
279*700637cbSDimitry Andric }
280