blob: 5ab583124fed6616dc6602db22d58726daa606af [file] [log] [blame]
//===---------- 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"
#include <vector>
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);
}
}
// 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!
void IRSpeculationLayer::emit(MaterializationResponsibility R,
ThreadSafeModule TSM) {
assert(TSM && "Speculation Layer received Null Module ?");
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());
}
}
}
// No locking needed read only operation.
assert(!(verifyModule(*TSM.getModuleUnlocked())) &&
"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