xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Speculation.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
1*8bcb0991SDimitry Andric //===---------- speculation.cpp - Utilities for Speculation ----------===//
2*8bcb0991SDimitry Andric //
3*8bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*8bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8bcb0991SDimitry Andric //
7*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
8*8bcb0991SDimitry Andric 
9*8bcb0991SDimitry Andric #include "llvm/ExecutionEngine/Orc/Speculation.h"
10*8bcb0991SDimitry Andric #include "llvm/IR/BasicBlock.h"
11*8bcb0991SDimitry Andric #include "llvm/IR/Function.h"
12*8bcb0991SDimitry Andric #include "llvm/IR/IRBuilder.h"
13*8bcb0991SDimitry Andric #include "llvm/IR/Instruction.h"
14*8bcb0991SDimitry Andric #include "llvm/IR/Instructions.h"
15*8bcb0991SDimitry Andric #include "llvm/IR/LLVMContext.h"
16*8bcb0991SDimitry Andric #include "llvm/IR/Module.h"
17*8bcb0991SDimitry Andric #include "llvm/IR/Type.h"
18*8bcb0991SDimitry Andric #include "llvm/IR/Verifier.h"
19*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h"
20*8bcb0991SDimitry Andric 
21*8bcb0991SDimitry Andric #include <vector>
22*8bcb0991SDimitry Andric 
23*8bcb0991SDimitry Andric namespace llvm {
24*8bcb0991SDimitry Andric 
25*8bcb0991SDimitry Andric namespace orc {
26*8bcb0991SDimitry Andric 
27*8bcb0991SDimitry Andric // ImplSymbolMap methods
28*8bcb0991SDimitry Andric void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) {
29*8bcb0991SDimitry Andric   assert(SrcJD && "Tracking on Null Source .impl dylib");
30*8bcb0991SDimitry Andric   std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
31*8bcb0991SDimitry Andric   for (auto &I : ImplMaps) {
32*8bcb0991SDimitry Andric     auto It = Maps.insert({I.first, {I.second.Aliasee, SrcJD}});
33*8bcb0991SDimitry Andric     // check rationale when independent dylibs have same symbol name?
34*8bcb0991SDimitry Andric     assert(It.second && "ImplSymbols are already tracked for this Symbol?");
35*8bcb0991SDimitry Andric     (void)(It);
36*8bcb0991SDimitry Andric   }
37*8bcb0991SDimitry Andric }
38*8bcb0991SDimitry Andric 
39*8bcb0991SDimitry Andric // Trigger Speculative Compiles.
40*8bcb0991SDimitry Andric void Speculator::speculateForEntryPoint(Speculator *Ptr, uint64_t StubId) {
41*8bcb0991SDimitry Andric   assert(Ptr && " Null Address Received in orc_speculate_for ");
42*8bcb0991SDimitry Andric   Ptr->speculateFor(StubId);
43*8bcb0991SDimitry Andric }
44*8bcb0991SDimitry Andric 
45*8bcb0991SDimitry Andric Error Speculator::addSpeculationRuntime(JITDylib &JD,
46*8bcb0991SDimitry Andric                                         MangleAndInterner &Mangle) {
47*8bcb0991SDimitry Andric   JITEvaluatedSymbol ThisPtr(pointerToJITTargetAddress(this),
48*8bcb0991SDimitry Andric                              JITSymbolFlags::Exported);
49*8bcb0991SDimitry Andric   JITEvaluatedSymbol SpeculateForEntryPtr(
50*8bcb0991SDimitry Andric       pointerToJITTargetAddress(&speculateForEntryPoint),
51*8bcb0991SDimitry Andric       JITSymbolFlags::Exported);
52*8bcb0991SDimitry Andric   return JD.define(absoluteSymbols({
53*8bcb0991SDimitry Andric       {Mangle("__orc_speculator"), ThisPtr},                // Data Symbol
54*8bcb0991SDimitry Andric       {Mangle("__orc_speculate_for"), SpeculateForEntryPtr} // Callable Symbol
55*8bcb0991SDimitry Andric   }));
56*8bcb0991SDimitry Andric }
57*8bcb0991SDimitry Andric 
58*8bcb0991SDimitry Andric // If two modules, share the same LLVMContext, different threads must
59*8bcb0991SDimitry Andric // not access them concurrently without locking the associated LLVMContext
60*8bcb0991SDimitry Andric // this implementation follows this contract.
61*8bcb0991SDimitry Andric void IRSpeculationLayer::emit(MaterializationResponsibility R,
62*8bcb0991SDimitry Andric                               ThreadSafeModule TSM) {
63*8bcb0991SDimitry Andric 
64*8bcb0991SDimitry Andric   assert(TSM && "Speculation Layer received Null Module ?");
65*8bcb0991SDimitry Andric   assert(TSM.getContext().getContext() != nullptr &&
66*8bcb0991SDimitry Andric          "Module with null LLVMContext?");
67*8bcb0991SDimitry Andric 
68*8bcb0991SDimitry Andric   // Instrumentation of runtime calls, lock the Module
69*8bcb0991SDimitry Andric   TSM.withModuleDo([this, &R](Module &M) {
70*8bcb0991SDimitry Andric     auto &MContext = M.getContext();
71*8bcb0991SDimitry Andric     auto SpeculatorVTy = StructType::create(MContext, "Class.Speculator");
72*8bcb0991SDimitry Andric     auto RuntimeCallTy = FunctionType::get(
73*8bcb0991SDimitry Andric         Type::getVoidTy(MContext),
74*8bcb0991SDimitry Andric         {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(MContext)}, false);
75*8bcb0991SDimitry Andric     auto RuntimeCall =
76*8bcb0991SDimitry Andric         Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage,
77*8bcb0991SDimitry Andric                          "__orc_speculate_for", &M);
78*8bcb0991SDimitry Andric     auto SpeclAddr = new GlobalVariable(
79*8bcb0991SDimitry Andric         M, SpeculatorVTy, false, GlobalValue::LinkageTypes::ExternalLinkage,
80*8bcb0991SDimitry Andric         nullptr, "__orc_speculator");
81*8bcb0991SDimitry Andric 
82*8bcb0991SDimitry Andric     IRBuilder<> Mutator(MContext);
83*8bcb0991SDimitry Andric 
84*8bcb0991SDimitry Andric     // QueryAnalysis allowed to transform the IR source, one such example is
85*8bcb0991SDimitry Andric     // Simplify CFG helps the static branch prediction heuristics!
86*8bcb0991SDimitry Andric     for (auto &Fn : M.getFunctionList()) {
87*8bcb0991SDimitry Andric       if (!Fn.isDeclaration()) {
88*8bcb0991SDimitry Andric 
89*8bcb0991SDimitry Andric         auto IRNames = QueryAnalysis(Fn);
90*8bcb0991SDimitry Andric         // Instrument and register if Query has result
91*8bcb0991SDimitry Andric         if (IRNames.hasValue()) {
92*8bcb0991SDimitry Andric 
93*8bcb0991SDimitry Andric           // Emit globals for each function.
94*8bcb0991SDimitry Andric           auto LoadValueTy = Type::getInt8Ty(MContext);
95*8bcb0991SDimitry Andric           auto SpeculatorGuard = new GlobalVariable(
96*8bcb0991SDimitry Andric               M, LoadValueTy, false, GlobalValue::LinkageTypes::InternalLinkage,
97*8bcb0991SDimitry Andric               ConstantInt::get(LoadValueTy, 0),
98*8bcb0991SDimitry Andric               "__orc_speculate.guard.for." + Fn.getName());
99*8bcb0991SDimitry Andric           SpeculatorGuard->setAlignment(Align::None());
100*8bcb0991SDimitry Andric           SpeculatorGuard->setUnnamedAddr(GlobalValue::UnnamedAddr::Local);
101*8bcb0991SDimitry Andric 
102*8bcb0991SDimitry Andric           BasicBlock &ProgramEntry = Fn.getEntryBlock();
103*8bcb0991SDimitry Andric           // Create BasicBlocks before the program's entry basicblock
104*8bcb0991SDimitry Andric           BasicBlock *SpeculateBlock = BasicBlock::Create(
105*8bcb0991SDimitry Andric               MContext, "__orc_speculate.block", &Fn, &ProgramEntry);
106*8bcb0991SDimitry Andric           BasicBlock *SpeculateDecisionBlock = BasicBlock::Create(
107*8bcb0991SDimitry Andric               MContext, "__orc_speculate.decision.block", &Fn, SpeculateBlock);
108*8bcb0991SDimitry Andric 
109*8bcb0991SDimitry Andric           assert(SpeculateDecisionBlock == &Fn.getEntryBlock() &&
110*8bcb0991SDimitry Andric                  "SpeculateDecisionBlock not updated?");
111*8bcb0991SDimitry Andric           Mutator.SetInsertPoint(SpeculateDecisionBlock);
112*8bcb0991SDimitry Andric 
113*8bcb0991SDimitry Andric           auto LoadGuard =
114*8bcb0991SDimitry Andric               Mutator.CreateLoad(LoadValueTy, SpeculatorGuard, "guard.value");
115*8bcb0991SDimitry Andric           // if just loaded value equal to 0,return true.
116*8bcb0991SDimitry Andric           auto CanSpeculate =
117*8bcb0991SDimitry Andric               Mutator.CreateICmpEQ(LoadGuard, ConstantInt::get(LoadValueTy, 0),
118*8bcb0991SDimitry Andric                                    "compare.to.speculate");
119*8bcb0991SDimitry Andric           Mutator.CreateCondBr(CanSpeculate, SpeculateBlock, &ProgramEntry);
120*8bcb0991SDimitry Andric 
121*8bcb0991SDimitry Andric           Mutator.SetInsertPoint(SpeculateBlock);
122*8bcb0991SDimitry Andric           auto ImplAddrToUint =
123*8bcb0991SDimitry Andric               Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(MContext));
124*8bcb0991SDimitry Andric           Mutator.CreateCall(RuntimeCallTy, RuntimeCall,
125*8bcb0991SDimitry Andric                              {SpeclAddr, ImplAddrToUint});
126*8bcb0991SDimitry Andric           Mutator.CreateStore(ConstantInt::get(LoadValueTy, 1),
127*8bcb0991SDimitry Andric                               SpeculatorGuard);
128*8bcb0991SDimitry Andric           Mutator.CreateBr(&ProgramEntry);
129*8bcb0991SDimitry Andric 
130*8bcb0991SDimitry Andric           assert(Mutator.GetInsertBlock()->getParent() == &Fn &&
131*8bcb0991SDimitry Andric                  "IR builder association mismatch?");
132*8bcb0991SDimitry Andric           S.registerSymbols(internToJITSymbols(IRNames.getValue()),
133*8bcb0991SDimitry Andric                             &R.getTargetJITDylib());
134*8bcb0991SDimitry Andric         }
135*8bcb0991SDimitry Andric       }
136*8bcb0991SDimitry Andric     }
137*8bcb0991SDimitry Andric   });
138*8bcb0991SDimitry Andric 
139*8bcb0991SDimitry Andric   assert(!TSM.withModuleDo([](const Module &M) { return verifyModule(M); }) &&
140*8bcb0991SDimitry Andric          "Speculation Instrumentation breaks IR?");
141*8bcb0991SDimitry Andric 
142*8bcb0991SDimitry Andric   NextLayer.emit(std::move(R), std::move(TSM));
143*8bcb0991SDimitry Andric }
144*8bcb0991SDimitry Andric 
145*8bcb0991SDimitry Andric } // namespace orc
146*8bcb0991SDimitry Andric } // namespace llvm
147