diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc/Speculation.cpp')
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/Speculation.cpp | 135 |
1 files changed, 92 insertions, 43 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp index 5ab583124fe..4f2ea92706c 100644 --- a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/Speculation.h" - #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -17,6 +16,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" +#include "llvm/Support/Debug.h" #include <vector> @@ -36,11 +36,28 @@ void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) { } } +// 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 those modules concurrently, doing so leave the -// LLVMContext in in-consistent state. -// But here since each TSM has a unique Context associated with it, -// on locking is necessary! +// not access them concurrently without locking the associated LLVMContext +// this implementation follows this contract. void IRSpeculationLayer::emit(MaterializationResponsibility R, ThreadSafeModule TSM) { @@ -48,50 +65,82 @@ void IRSpeculationLayer::emit(MaterializationResponsibility R, assert(TSM.getContext().getContext() != nullptr && "Module with null LLVMContext?"); - // Instrumentation of runtime calls - auto &InContext = *TSM.getContext().getContext(); - auto SpeculatorVTy = StructType::create(InContext, "Class.Speculator"); - auto RuntimeCallTy = FunctionType::get( - Type::getVoidTy(InContext), - {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(InContext)}, false); - auto RuntimeCall = - Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage, - "__orc_speculate_for", TSM.getModuleUnlocked()); - auto SpeclAddr = new GlobalVariable( - *TSM.getModuleUnlocked(), SpeculatorVTy, false, - GlobalValue::LinkageTypes::ExternalLinkage, nullptr, "__orc_speculator"); - - IRBuilder<> Mutator(InContext); - - // QueryAnalysis allowed to transform the IR source, one such example is - // Simplify CFG helps the static branch prediction heuristics! - for (auto &Fn : TSM.getModuleUnlocked()->getFunctionList()) { - if (!Fn.isDeclaration()) { - auto IRNames = QueryAnalysis(Fn, FAM); - // Instrument and register if Query has result - if (IRNames.hasValue()) { - Mutator.SetInsertPoint(&(Fn.getEntryBlock().front())); - auto ImplAddrToUint = - Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(InContext)); - Mutator.CreateCall(RuntimeCallTy, RuntimeCall, - {SpeclAddr, ImplAddrToUint}); - S.registerSymbols(internToJITSymbols(IRNames.getValue()), - &R.getTargetJITDylib()); + // 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.hasValue()) { + + // 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(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.getValue()), + &R.getTargetJITDylib()); + } } } - } - // No locking needed read only operation. - assert(!(verifyModule(*TSM.getModuleUnlocked())) && + }); + + assert(!TSM.withModuleDo([](const Module &M) { return verifyModule(M); }) && "Speculation Instrumentation breaks IR?"); NextLayer.emit(std::move(R), std::move(TSM)); } -// Runtime Function Implementation -extern "C" void __orc_speculate_for(Speculator *Ptr, uint64_t StubId) { - assert(Ptr && " Null Address Received in orc_speculate_for "); - Ptr->speculateFor(StubId); -} - } // namespace orc } // namespace llvm |