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