123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- //===---------- speculation.cpp - Utilities for Speculation ----------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ExecutionEngine/Orc/Speculation.h"
- #include "llvm/IR/BasicBlock.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/IRBuilder.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Type.h"
- #include "llvm/IR/Verifier.h"
- namespace llvm {
- namespace orc {
- // ImplSymbolMap methods
- void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) {
- assert(SrcJD && "Tracking on Null Source .impl dylib");
- std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
- for (auto &I : ImplMaps) {
- auto It = Maps.insert({I.first, {I.second.Aliasee, SrcJD}});
- // check rationale when independent dylibs have same symbol name?
- assert(It.second && "ImplSymbols are already tracked for this Symbol?");
- (void)(It);
- }
- }
- // Trigger Speculative Compiles.
- void Speculator::speculateForEntryPoint(Speculator *Ptr, uint64_t StubId) {
- assert(Ptr && " Null Address Received in orc_speculate_for ");
- Ptr->speculateFor(StubId);
- }
- Error Speculator::addSpeculationRuntime(JITDylib &JD,
- MangleAndInterner &Mangle) {
- JITEvaluatedSymbol ThisPtr(pointerToJITTargetAddress(this),
- JITSymbolFlags::Exported);
- JITEvaluatedSymbol SpeculateForEntryPtr(
- pointerToJITTargetAddress(&speculateForEntryPoint),
- JITSymbolFlags::Exported);
- return JD.define(absoluteSymbols({
- {Mangle("__orc_speculator"), ThisPtr}, // Data Symbol
- {Mangle("__orc_speculate_for"), SpeculateForEntryPtr} // Callable Symbol
- }));
- }
- // If two modules, share the same LLVMContext, different threads must
- // not access them concurrently without locking the associated LLVMContext
- // this implementation follows this contract.
- void IRSpeculationLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
- ThreadSafeModule TSM) {
- assert(TSM && "Speculation Layer received Null Module ?");
- assert(TSM.getContext().getContext() != nullptr &&
- "Module with null LLVMContext?");
- // Instrumentation of runtime calls, lock the Module
- TSM.withModuleDo([this, &R](Module &M) {
- auto &MContext = M.getContext();
- auto SpeculatorVTy = StructType::create(MContext, "Class.Speculator");
- auto RuntimeCallTy = FunctionType::get(
- Type::getVoidTy(MContext),
- {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(MContext)}, false);
- auto RuntimeCall =
- Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage,
- "__orc_speculate_for", &M);
- auto SpeclAddr = new GlobalVariable(
- M, SpeculatorVTy, false, GlobalValue::LinkageTypes::ExternalLinkage,
- nullptr, "__orc_speculator");
- IRBuilder<> Mutator(MContext);
- // QueryAnalysis allowed to transform the IR source, one such example is
- // Simplify CFG helps the static branch prediction heuristics!
- for (auto &Fn : M.getFunctionList()) {
- if (!Fn.isDeclaration()) {
- auto IRNames = QueryAnalysis(Fn);
- // Instrument and register if Query has result
- if (IRNames) {
- // Emit globals for each function.
- auto LoadValueTy = Type::getInt8Ty(MContext);
- auto SpeculatorGuard = new GlobalVariable(
- M, LoadValueTy, false, GlobalValue::LinkageTypes::InternalLinkage,
- ConstantInt::get(LoadValueTy, 0),
- "__orc_speculate.guard.for." + Fn.getName());
- SpeculatorGuard->setAlignment(Align(1));
- SpeculatorGuard->setUnnamedAddr(GlobalValue::UnnamedAddr::Local);
- BasicBlock &ProgramEntry = Fn.getEntryBlock();
- // Create BasicBlocks before the program's entry basicblock
- BasicBlock *SpeculateBlock = BasicBlock::Create(
- MContext, "__orc_speculate.block", &Fn, &ProgramEntry);
- BasicBlock *SpeculateDecisionBlock = BasicBlock::Create(
- MContext, "__orc_speculate.decision.block", &Fn, SpeculateBlock);
- assert(SpeculateDecisionBlock == &Fn.getEntryBlock() &&
- "SpeculateDecisionBlock not updated?");
- Mutator.SetInsertPoint(SpeculateDecisionBlock);
- auto LoadGuard =
- Mutator.CreateLoad(LoadValueTy, SpeculatorGuard, "guard.value");
- // if just loaded value equal to 0,return true.
- auto CanSpeculate =
- Mutator.CreateICmpEQ(LoadGuard, ConstantInt::get(LoadValueTy, 0),
- "compare.to.speculate");
- Mutator.CreateCondBr(CanSpeculate, SpeculateBlock, &ProgramEntry);
- Mutator.SetInsertPoint(SpeculateBlock);
- auto ImplAddrToUint =
- Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(MContext));
- Mutator.CreateCall(RuntimeCallTy, RuntimeCall,
- {SpeclAddr, ImplAddrToUint});
- Mutator.CreateStore(ConstantInt::get(LoadValueTy, 1),
- SpeculatorGuard);
- Mutator.CreateBr(&ProgramEntry);
- assert(Mutator.GetInsertBlock()->getParent() == &Fn &&
- "IR builder association mismatch?");
- S.registerSymbols(internToJITSymbols(*IRNames),
- &R->getTargetJITDylib());
- }
- }
- }
- });
- assert(!TSM.withModuleDo([](const Module &M) { return verifyModule(M); }) &&
- "Speculation Instrumentation breaks IR?");
- NextLayer.emit(std::move(R), std::move(TSM));
- }
- } // namespace orc
- } // namespace llvm
|