xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ReOptimizeLayer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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