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 11 #include "llvm/IR/BasicBlock.h" 12 #include "llvm/IR/Function.h" 13 #include "llvm/IR/IRBuilder.h" 14 #include "llvm/IR/Instruction.h" 15 #include "llvm/IR/Instructions.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/IR/Type.h" 19 #include "llvm/IR/Verifier.h" 20 21 #include <vector> 22 23 namespace llvm { 24 25 namespace orc { 26 27 // ImplSymbolMap methods 28 void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) { 29 assert(SrcJD && "Tracking on Null Source .impl dylib"); 30 std::lock_guard<std::mutex> Lockit(ConcurrentAccess); 31 for (auto &I : ImplMaps) { 32 auto It = Maps.insert({I.first, {I.second.Aliasee, SrcJD}}); 33 // check rationale when independent dylibs have same symbol name? 34 assert(It.second && "ImplSymbols are already tracked for this Symbol?"); 35 (void)(It); 36 } 37 } 38 39 // If two modules, share the same LLVMContext, different threads must 40 // not access those modules concurrently, doing so leave the 41 // LLVMContext in in-consistent state. 42 // But here since each TSM has a unique Context associated with it, 43 // on locking is necessary! 44 void IRSpeculationLayer::emit(MaterializationResponsibility R, 45 ThreadSafeModule TSM) { 46 47 assert(TSM && "Speculation Layer received Null Module ?"); 48 assert(TSM.getContext().getContext() != nullptr && 49 "Module with null LLVMContext?"); 50 51 // Instrumentation of runtime calls 52 auto &InContext = *TSM.getContext().getContext(); 53 auto SpeculatorVTy = StructType::create(InContext, "Class.Speculator"); 54 auto RuntimeCallTy = FunctionType::get( 55 Type::getVoidTy(InContext), 56 {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(InContext)}, false); 57 auto RuntimeCall = 58 Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage, 59 "__orc_speculate_for", TSM.getModuleUnlocked()); 60 auto SpeclAddr = new GlobalVariable( 61 *TSM.getModuleUnlocked(), SpeculatorVTy, false, 62 GlobalValue::LinkageTypes::ExternalLinkage, nullptr, "__orc_speculator"); 63 64 IRBuilder<> Mutator(InContext); 65 66 // QueryAnalysis allowed to transform the IR source, one such example is 67 // Simplify CFG helps the static branch prediction heuristics! 68 for (auto &Fn : TSM.getModuleUnlocked()->getFunctionList()) { 69 if (!Fn.isDeclaration()) { 70 auto IRNames = QueryAnalysis(Fn, FAM); 71 // Instrument and register if Query has result 72 if (IRNames.hasValue()) { 73 Mutator.SetInsertPoint(&(Fn.getEntryBlock().front())); 74 auto ImplAddrToUint = 75 Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(InContext)); 76 Mutator.CreateCall(RuntimeCallTy, RuntimeCall, 77 {SpeclAddr, ImplAddrToUint}); 78 S.registerSymbols(internToJITSymbols(IRNames.getValue()), 79 &R.getTargetJITDylib()); 80 } 81 } 82 } 83 // No locking needed read only operation. 84 assert(!(verifyModule(*TSM.getModuleUnlocked())) && 85 "Speculation Instrumentation breaks IR?"); 86 87 NextLayer.emit(std::move(R), std::move(TSM)); 88 } 89 90 // Runtime Function Implementation 91 extern "C" void __orc_speculate_for(Speculator *Ptr, uint64_t StubId) { 92 assert(Ptr && " Null Address Received in orc_speculate_for "); 93 Ptr->speculateFor(StubId); 94 } 95 96 } // namespace orc 97 } // namespace llvm 98