Alexander Richardson 3a4b351ba1
[IR] Introduce the ptrtoaddr instruction
This introduces a new `ptrtoaddr` instruction which is similar to
`ptrtoint` but has two differences:

1) Unlike `ptrtoint`, `ptrtoaddr` does not capture provenance
2) `ptrtoaddr` only extracts (and then extends/truncates) the low
   index-width bits of the pointer

For most architectures, difference 2) does not matter since index (address)
width and pointer representation width are the same, but this does make a
difference for architectures that have pointers that aren't just plain
integer addresses such as AMDGPU fat pointers or CHERI capabilities.

This commit introduces textual and bitcode IR support as well as basic code
generation, but optimization passes do not handle the new instruction yet
so it may result in worse code than using ptrtoint. Follow-up changes will
update capture tracking, etc. for the new instruction.

RFC: https://discourse.llvm.org/t/clarifiying-the-semantics-of-ptrtoint/83987/54

Reviewed By: nikic

Pull Request: https://github.com/llvm/llvm-project/pull/139357
2025-08-08 10:12:39 -07:00

782 lines
30 KiB
C++

//===- Context.cpp - The Context class of Sandbox IR ----------------------===//
//
// 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/SandboxIR/Context.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/SandboxIR/Function.h"
#include "llvm/SandboxIR/Instruction.h"
#include "llvm/SandboxIR/Module.h"
namespace llvm::sandboxir {
std::unique_ptr<Value> Context::detachLLVMValue(llvm::Value *V) {
std::unique_ptr<Value> Erased;
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end()) {
auto *Val = It->second.release();
Erased = std::unique_ptr<Value>(Val);
LLVMValueToValueMap.erase(It);
}
return Erased;
}
std::unique_ptr<Value> Context::detach(Value *V) {
assert(V->getSubclassID() != Value::ClassID::Constant &&
"Can't detach a constant!");
assert(V->getSubclassID() != Value::ClassID::User && "Can't detach a user!");
return detachLLVMValue(V->Val);
}
Value *Context::registerValue(std::unique_ptr<Value> &&VPtr) {
assert(VPtr->getSubclassID() != Value::ClassID::User &&
"Can't register a user!");
Value *V = VPtr.get();
[[maybe_unused]] auto Pair =
LLVMValueToValueMap.insert({VPtr->Val, std::move(VPtr)});
assert(Pair.second && "Already exists!");
// Track creation of instructions.
// Please note that we don't allow the creation of detached instructions,
// meaning that the instructions need to be inserted into a block upon
// creation. This is why the tracker class combines creation and insertion.
if (auto *I = dyn_cast<Instruction>(V)) {
getTracker().emplaceIfTracking<CreateAndInsertInst>(I);
runCreateInstrCallbacks(I);
}
return V;
}
Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
auto Pair = LLVMValueToValueMap.try_emplace(LLVMV);
auto It = Pair.first;
if (!Pair.second)
return It->second.get();
// Instruction
if (auto *LLVMI = dyn_cast<llvm::Instruction>(LLVMV)) {
switch (LLVMI->getOpcode()) {
case llvm::Instruction::VAArg: {
auto *LLVMVAArg = cast<llvm::VAArgInst>(LLVMV);
It->second = std::unique_ptr<VAArgInst>(new VAArgInst(LLVMVAArg, *this));
return It->second.get();
}
case llvm::Instruction::Freeze: {
auto *LLVMFreeze = cast<llvm::FreezeInst>(LLVMV);
It->second =
std::unique_ptr<FreezeInst>(new FreezeInst(LLVMFreeze, *this));
return It->second.get();
}
case llvm::Instruction::Fence: {
auto *LLVMFence = cast<llvm::FenceInst>(LLVMV);
It->second = std::unique_ptr<FenceInst>(new FenceInst(LLVMFence, *this));
return It->second.get();
}
case llvm::Instruction::Select: {
auto *LLVMSel = cast<llvm::SelectInst>(LLVMV);
It->second = std::unique_ptr<SelectInst>(new SelectInst(LLVMSel, *this));
return It->second.get();
}
case llvm::Instruction::ExtractElement: {
auto *LLVMIns = cast<llvm::ExtractElementInst>(LLVMV);
It->second = std::unique_ptr<ExtractElementInst>(
new ExtractElementInst(LLVMIns, *this));
return It->second.get();
}
case llvm::Instruction::InsertElement: {
auto *LLVMIns = cast<llvm::InsertElementInst>(LLVMV);
It->second = std::unique_ptr<InsertElementInst>(
new InsertElementInst(LLVMIns, *this));
return It->second.get();
}
case llvm::Instruction::ShuffleVector: {
auto *LLVMIns = cast<llvm::ShuffleVectorInst>(LLVMV);
It->second = std::unique_ptr<ShuffleVectorInst>(
new ShuffleVectorInst(LLVMIns, *this));
return It->second.get();
}
case llvm::Instruction::ExtractValue: {
auto *LLVMIns = cast<llvm::ExtractValueInst>(LLVMV);
It->second = std::unique_ptr<ExtractValueInst>(
new ExtractValueInst(LLVMIns, *this));
return It->second.get();
}
case llvm::Instruction::InsertValue: {
auto *LLVMIns = cast<llvm::InsertValueInst>(LLVMV);
It->second =
std::unique_ptr<InsertValueInst>(new InsertValueInst(LLVMIns, *this));
return It->second.get();
}
case llvm::Instruction::Br: {
auto *LLVMBr = cast<llvm::BranchInst>(LLVMV);
It->second = std::unique_ptr<BranchInst>(new BranchInst(LLVMBr, *this));
return It->second.get();
}
case llvm::Instruction::Load: {
auto *LLVMLd = cast<llvm::LoadInst>(LLVMV);
It->second = std::unique_ptr<LoadInst>(new LoadInst(LLVMLd, *this));
return It->second.get();
}
case llvm::Instruction::Store: {
auto *LLVMSt = cast<llvm::StoreInst>(LLVMV);
It->second = std::unique_ptr<StoreInst>(new StoreInst(LLVMSt, *this));
return It->second.get();
}
case llvm::Instruction::Ret: {
auto *LLVMRet = cast<llvm::ReturnInst>(LLVMV);
It->second = std::unique_ptr<ReturnInst>(new ReturnInst(LLVMRet, *this));
return It->second.get();
}
case llvm::Instruction::Call: {
auto *LLVMCall = cast<llvm::CallInst>(LLVMV);
It->second = std::unique_ptr<CallInst>(new CallInst(LLVMCall, *this));
return It->second.get();
}
case llvm::Instruction::Invoke: {
auto *LLVMInvoke = cast<llvm::InvokeInst>(LLVMV);
It->second =
std::unique_ptr<InvokeInst>(new InvokeInst(LLVMInvoke, *this));
return It->second.get();
}
case llvm::Instruction::CallBr: {
auto *LLVMCallBr = cast<llvm::CallBrInst>(LLVMV);
It->second =
std::unique_ptr<CallBrInst>(new CallBrInst(LLVMCallBr, *this));
return It->second.get();
}
case llvm::Instruction::LandingPad: {
auto *LLVMLPad = cast<llvm::LandingPadInst>(LLVMV);
It->second =
std::unique_ptr<LandingPadInst>(new LandingPadInst(LLVMLPad, *this));
return It->second.get();
}
case llvm::Instruction::CatchPad: {
auto *LLVMCPI = cast<llvm::CatchPadInst>(LLVMV);
It->second =
std::unique_ptr<CatchPadInst>(new CatchPadInst(LLVMCPI, *this));
return It->second.get();
}
case llvm::Instruction::CleanupPad: {
auto *LLVMCPI = cast<llvm::CleanupPadInst>(LLVMV);
It->second =
std::unique_ptr<CleanupPadInst>(new CleanupPadInst(LLVMCPI, *this));
return It->second.get();
}
case llvm::Instruction::CatchRet: {
auto *LLVMCRI = cast<llvm::CatchReturnInst>(LLVMV);
It->second =
std::unique_ptr<CatchReturnInst>(new CatchReturnInst(LLVMCRI, *this));
return It->second.get();
}
case llvm::Instruction::CleanupRet: {
auto *LLVMCRI = cast<llvm::CleanupReturnInst>(LLVMV);
It->second = std::unique_ptr<CleanupReturnInst>(
new CleanupReturnInst(LLVMCRI, *this));
return It->second.get();
}
case llvm::Instruction::GetElementPtr: {
auto *LLVMGEP = cast<llvm::GetElementPtrInst>(LLVMV);
It->second = std::unique_ptr<GetElementPtrInst>(
new GetElementPtrInst(LLVMGEP, *this));
return It->second.get();
}
case llvm::Instruction::CatchSwitch: {
auto *LLVMCatchSwitchInst = cast<llvm::CatchSwitchInst>(LLVMV);
It->second = std::unique_ptr<CatchSwitchInst>(
new CatchSwitchInst(LLVMCatchSwitchInst, *this));
return It->second.get();
}
case llvm::Instruction::Resume: {
auto *LLVMResumeInst = cast<llvm::ResumeInst>(LLVMV);
It->second =
std::unique_ptr<ResumeInst>(new ResumeInst(LLVMResumeInst, *this));
return It->second.get();
}
case llvm::Instruction::Switch: {
auto *LLVMSwitchInst = cast<llvm::SwitchInst>(LLVMV);
It->second =
std::unique_ptr<SwitchInst>(new SwitchInst(LLVMSwitchInst, *this));
return It->second.get();
}
case llvm::Instruction::FNeg: {
auto *LLVMUnaryOperator = cast<llvm::UnaryOperator>(LLVMV);
It->second = std::unique_ptr<UnaryOperator>(
new UnaryOperator(LLVMUnaryOperator, *this));
return It->second.get();
}
case llvm::Instruction::Add:
case llvm::Instruction::FAdd:
case llvm::Instruction::Sub:
case llvm::Instruction::FSub:
case llvm::Instruction::Mul:
case llvm::Instruction::FMul:
case llvm::Instruction::UDiv:
case llvm::Instruction::SDiv:
case llvm::Instruction::FDiv:
case llvm::Instruction::URem:
case llvm::Instruction::SRem:
case llvm::Instruction::FRem:
case llvm::Instruction::Shl:
case llvm::Instruction::LShr:
case llvm::Instruction::AShr:
case llvm::Instruction::And:
case llvm::Instruction::Or:
case llvm::Instruction::Xor: {
auto *LLVMBinaryOperator = cast<llvm::BinaryOperator>(LLVMV);
It->second = std::unique_ptr<BinaryOperator>(
new BinaryOperator(LLVMBinaryOperator, *this));
return It->second.get();
}
case llvm::Instruction::AtomicRMW: {
auto *LLVMAtomicRMW = cast<llvm::AtomicRMWInst>(LLVMV);
It->second = std::unique_ptr<AtomicRMWInst>(
new AtomicRMWInst(LLVMAtomicRMW, *this));
return It->second.get();
}
case llvm::Instruction::AtomicCmpXchg: {
auto *LLVMAtomicCmpXchg = cast<llvm::AtomicCmpXchgInst>(LLVMV);
It->second = std::unique_ptr<AtomicCmpXchgInst>(
new AtomicCmpXchgInst(LLVMAtomicCmpXchg, *this));
return It->second.get();
}
case llvm::Instruction::Alloca: {
auto *LLVMAlloca = cast<llvm::AllocaInst>(LLVMV);
It->second =
std::unique_ptr<AllocaInst>(new AllocaInst(LLVMAlloca, *this));
return It->second.get();
}
case llvm::Instruction::ZExt:
case llvm::Instruction::SExt:
case llvm::Instruction::FPToUI:
case llvm::Instruction::FPToSI:
case llvm::Instruction::FPExt:
case llvm::Instruction::PtrToAddr:
case llvm::Instruction::PtrToInt:
case llvm::Instruction::IntToPtr:
case llvm::Instruction::SIToFP:
case llvm::Instruction::UIToFP:
case llvm::Instruction::Trunc:
case llvm::Instruction::FPTrunc:
case llvm::Instruction::BitCast:
case llvm::Instruction::AddrSpaceCast: {
auto *LLVMCast = cast<llvm::CastInst>(LLVMV);
It->second = std::unique_ptr<CastInst>(new CastInst(LLVMCast, *this));
return It->second.get();
}
case llvm::Instruction::PHI: {
auto *LLVMPhi = cast<llvm::PHINode>(LLVMV);
It->second = std::unique_ptr<PHINode>(new PHINode(LLVMPhi, *this));
return It->second.get();
}
case llvm::Instruction::ICmp: {
auto *LLVMICmp = cast<llvm::ICmpInst>(LLVMV);
It->second = std::unique_ptr<ICmpInst>(new ICmpInst(LLVMICmp, *this));
return It->second.get();
}
case llvm::Instruction::FCmp: {
auto *LLVMFCmp = cast<llvm::FCmpInst>(LLVMV);
It->second = std::unique_ptr<FCmpInst>(new FCmpInst(LLVMFCmp, *this));
return It->second.get();
}
case llvm::Instruction::Unreachable: {
auto *LLVMUnreachable = cast<llvm::UnreachableInst>(LLVMV);
It->second = std::unique_ptr<UnreachableInst>(
new UnreachableInst(LLVMUnreachable, *this));
return It->second.get();
}
default:
break;
}
It->second = std::unique_ptr<OpaqueInst>(
new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
return It->second.get();
}
// Constant
if (auto *LLVMC = dyn_cast<llvm::Constant>(LLVMV)) {
switch (LLVMC->getValueID()) {
case llvm::Value::ConstantIntVal:
It->second = std::unique_ptr<ConstantInt>(
new ConstantInt(cast<llvm::ConstantInt>(LLVMC), *this));
return It->second.get();
case llvm::Value::ConstantFPVal:
It->second = std::unique_ptr<ConstantFP>(
new ConstantFP(cast<llvm::ConstantFP>(LLVMC), *this));
return It->second.get();
case llvm::Value::BlockAddressVal:
It->second = std::unique_ptr<BlockAddress>(
new BlockAddress(cast<llvm::BlockAddress>(LLVMC), *this));
return It->second.get();
case llvm::Value::ConstantTokenNoneVal:
It->second = std::unique_ptr<ConstantTokenNone>(
new ConstantTokenNone(cast<llvm::ConstantTokenNone>(LLVMC), *this));
return It->second.get();
case llvm::Value::ConstantAggregateZeroVal: {
auto *CAZ = cast<llvm::ConstantAggregateZero>(LLVMC);
It->second = std::unique_ptr<ConstantAggregateZero>(
new ConstantAggregateZero(CAZ, *this));
auto *Ret = It->second.get();
// Must create sandboxir for elements.
auto EC = CAZ->getElementCount();
if (EC.isFixed()) {
for (auto ElmIdx : seq<unsigned>(0, EC.getFixedValue()))
getOrCreateValueInternal(CAZ->getElementValue(ElmIdx), CAZ);
}
return Ret;
}
case llvm::Value::ConstantPointerNullVal:
It->second = std::unique_ptr<ConstantPointerNull>(new ConstantPointerNull(
cast<llvm::ConstantPointerNull>(LLVMC), *this));
return It->second.get();
case llvm::Value::PoisonValueVal:
It->second = std::unique_ptr<PoisonValue>(
new PoisonValue(cast<llvm::PoisonValue>(LLVMC), *this));
return It->second.get();
case llvm::Value::UndefValueVal:
It->second = std::unique_ptr<UndefValue>(
new UndefValue(cast<llvm::UndefValue>(LLVMC), *this));
return It->second.get();
case llvm::Value::DSOLocalEquivalentVal: {
auto *DSOLE = cast<llvm::DSOLocalEquivalent>(LLVMC);
It->second = std::unique_ptr<DSOLocalEquivalent>(
new DSOLocalEquivalent(DSOLE, *this));
auto *Ret = It->second.get();
getOrCreateValueInternal(DSOLE->getGlobalValue(), DSOLE);
return Ret;
}
case llvm::Value::ConstantArrayVal:
It->second = std::unique_ptr<ConstantArray>(
new ConstantArray(cast<llvm::ConstantArray>(LLVMC), *this));
break;
case llvm::Value::ConstantStructVal:
It->second = std::unique_ptr<ConstantStruct>(
new ConstantStruct(cast<llvm::ConstantStruct>(LLVMC), *this));
break;
case llvm::Value::ConstantVectorVal:
It->second = std::unique_ptr<ConstantVector>(
new ConstantVector(cast<llvm::ConstantVector>(LLVMC), *this));
break;
case llvm::Value::ConstantDataArrayVal:
It->second = std::unique_ptr<ConstantDataArray>(
new ConstantDataArray(cast<llvm::ConstantDataArray>(LLVMC), *this));
break;
case llvm::Value::ConstantDataVectorVal:
It->second = std::unique_ptr<ConstantDataVector>(
new ConstantDataVector(cast<llvm::ConstantDataVector>(LLVMC), *this));
break;
case llvm::Value::FunctionVal:
It->second = std::unique_ptr<Function>(
new Function(cast<llvm::Function>(LLVMC), *this));
break;
case llvm::Value::GlobalIFuncVal:
It->second = std::unique_ptr<GlobalIFunc>(
new GlobalIFunc(cast<llvm::GlobalIFunc>(LLVMC), *this));
break;
case llvm::Value::GlobalVariableVal:
It->second = std::unique_ptr<GlobalVariable>(
new GlobalVariable(cast<llvm::GlobalVariable>(LLVMC), *this));
break;
case llvm::Value::GlobalAliasVal:
It->second = std::unique_ptr<GlobalAlias>(
new GlobalAlias(cast<llvm::GlobalAlias>(LLVMC), *this));
break;
case llvm::Value::NoCFIValueVal:
It->second = std::unique_ptr<NoCFIValue>(
new NoCFIValue(cast<llvm::NoCFIValue>(LLVMC), *this));
break;
case llvm::Value::ConstantPtrAuthVal:
It->second = std::unique_ptr<ConstantPtrAuth>(
new ConstantPtrAuth(cast<llvm::ConstantPtrAuth>(LLVMC), *this));
break;
case llvm::Value::ConstantExprVal:
It->second = std::unique_ptr<ConstantExpr>(
new ConstantExpr(cast<llvm::ConstantExpr>(LLVMC), *this));
break;
default:
It->second = std::unique_ptr<Constant>(new Constant(LLVMC, *this));
break;
}
auto *NewC = It->second.get();
for (llvm::Value *COp : LLVMC->operands())
getOrCreateValueInternal(COp, LLVMC);
return NewC;
}
// Argument
if (auto *LLVMArg = dyn_cast<llvm::Argument>(LLVMV)) {
It->second = std::unique_ptr<Argument>(new Argument(LLVMArg, *this));
return It->second.get();
}
// BasicBlock
if (auto *LLVMBB = dyn_cast<llvm::BasicBlock>(LLVMV)) {
assert(isa<llvm::BlockAddress>(U) &&
"This won't create a SBBB, don't call this function directly!");
if (auto *SBBB = getValue(LLVMBB))
return SBBB;
return nullptr;
}
// Metadata
if (auto *LLVMMD = dyn_cast<llvm::MetadataAsValue>(LLVMV)) {
It->second = std::unique_ptr<OpaqueValue>(new OpaqueValue(LLVMMD, *this));
return It->second.get();
}
// InlineAsm
if (auto *LLVMAsm = dyn_cast<llvm::InlineAsm>(LLVMV)) {
It->second = std::unique_ptr<OpaqueValue>(new OpaqueValue(LLVMAsm, *this));
return It->second.get();
}
llvm_unreachable("Unhandled LLVMV type!");
}
Argument *Context::getOrCreateArgument(llvm::Argument *LLVMArg) {
auto Pair = LLVMValueToValueMap.try_emplace(LLVMArg);
auto It = Pair.first;
if (Pair.second) {
It->second = std::unique_ptr<Argument>(new Argument(LLVMArg, *this));
return cast<Argument>(It->second.get());
}
return cast<Argument>(It->second.get());
}
Constant *Context::getOrCreateConstant(llvm::Constant *LLVMC) {
return cast<Constant>(getOrCreateValueInternal(LLVMC, 0));
}
BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {
assert(getValue(LLVMBB) == nullptr && "Already exists!");
auto NewBBPtr = std::unique_ptr<BasicBlock>(new BasicBlock(LLVMBB, *this));
auto *BB = cast<BasicBlock>(registerValue(std::move(NewBBPtr)));
// Create SandboxIR for BB's body.
BB->buildBasicBlockFromLLVMIR(LLVMBB);
return BB;
}
VAArgInst *Context::createVAArgInst(llvm::VAArgInst *SI) {
auto NewPtr = std::unique_ptr<VAArgInst>(new VAArgInst(SI, *this));
return cast<VAArgInst>(registerValue(std::move(NewPtr)));
}
FreezeInst *Context::createFreezeInst(llvm::FreezeInst *SI) {
auto NewPtr = std::unique_ptr<FreezeInst>(new FreezeInst(SI, *this));
return cast<FreezeInst>(registerValue(std::move(NewPtr)));
}
FenceInst *Context::createFenceInst(llvm::FenceInst *SI) {
auto NewPtr = std::unique_ptr<FenceInst>(new FenceInst(SI, *this));
return cast<FenceInst>(registerValue(std::move(NewPtr)));
}
SelectInst *Context::createSelectInst(llvm::SelectInst *SI) {
auto NewPtr = std::unique_ptr<SelectInst>(new SelectInst(SI, *this));
return cast<SelectInst>(registerValue(std::move(NewPtr)));
}
ExtractElementInst *
Context::createExtractElementInst(llvm::ExtractElementInst *EEI) {
auto NewPtr =
std::unique_ptr<ExtractElementInst>(new ExtractElementInst(EEI, *this));
return cast<ExtractElementInst>(registerValue(std::move(NewPtr)));
}
InsertElementInst *
Context::createInsertElementInst(llvm::InsertElementInst *IEI) {
auto NewPtr =
std::unique_ptr<InsertElementInst>(new InsertElementInst(IEI, *this));
return cast<InsertElementInst>(registerValue(std::move(NewPtr)));
}
ShuffleVectorInst *
Context::createShuffleVectorInst(llvm::ShuffleVectorInst *SVI) {
auto NewPtr =
std::unique_ptr<ShuffleVectorInst>(new ShuffleVectorInst(SVI, *this));
return cast<ShuffleVectorInst>(registerValue(std::move(NewPtr)));
}
ExtractValueInst *Context::createExtractValueInst(llvm::ExtractValueInst *EVI) {
auto NewPtr =
std::unique_ptr<ExtractValueInst>(new ExtractValueInst(EVI, *this));
return cast<ExtractValueInst>(registerValue(std::move(NewPtr)));
}
InsertValueInst *Context::createInsertValueInst(llvm::InsertValueInst *IVI) {
auto NewPtr =
std::unique_ptr<InsertValueInst>(new InsertValueInst(IVI, *this));
return cast<InsertValueInst>(registerValue(std::move(NewPtr)));
}
BranchInst *Context::createBranchInst(llvm::BranchInst *BI) {
auto NewPtr = std::unique_ptr<BranchInst>(new BranchInst(BI, *this));
return cast<BranchInst>(registerValue(std::move(NewPtr)));
}
LoadInst *Context::createLoadInst(llvm::LoadInst *LI) {
auto NewPtr = std::unique_ptr<LoadInst>(new LoadInst(LI, *this));
return cast<LoadInst>(registerValue(std::move(NewPtr)));
}
StoreInst *Context::createStoreInst(llvm::StoreInst *SI) {
auto NewPtr = std::unique_ptr<StoreInst>(new StoreInst(SI, *this));
return cast<StoreInst>(registerValue(std::move(NewPtr)));
}
ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) {
auto NewPtr = std::unique_ptr<ReturnInst>(new ReturnInst(I, *this));
return cast<ReturnInst>(registerValue(std::move(NewPtr)));
}
CallInst *Context::createCallInst(llvm::CallInst *I) {
auto NewPtr = std::unique_ptr<CallInst>(new CallInst(I, *this));
return cast<CallInst>(registerValue(std::move(NewPtr)));
}
InvokeInst *Context::createInvokeInst(llvm::InvokeInst *I) {
auto NewPtr = std::unique_ptr<InvokeInst>(new InvokeInst(I, *this));
return cast<InvokeInst>(registerValue(std::move(NewPtr)));
}
CallBrInst *Context::createCallBrInst(llvm::CallBrInst *I) {
auto NewPtr = std::unique_ptr<CallBrInst>(new CallBrInst(I, *this));
return cast<CallBrInst>(registerValue(std::move(NewPtr)));
}
UnreachableInst *Context::createUnreachableInst(llvm::UnreachableInst *UI) {
auto NewPtr =
std::unique_ptr<UnreachableInst>(new UnreachableInst(UI, *this));
return cast<UnreachableInst>(registerValue(std::move(NewPtr)));
}
LandingPadInst *Context::createLandingPadInst(llvm::LandingPadInst *I) {
auto NewPtr = std::unique_ptr<LandingPadInst>(new LandingPadInst(I, *this));
return cast<LandingPadInst>(registerValue(std::move(NewPtr)));
}
CatchPadInst *Context::createCatchPadInst(llvm::CatchPadInst *I) {
auto NewPtr = std::unique_ptr<CatchPadInst>(new CatchPadInst(I, *this));
return cast<CatchPadInst>(registerValue(std::move(NewPtr)));
}
CleanupPadInst *Context::createCleanupPadInst(llvm::CleanupPadInst *I) {
auto NewPtr = std::unique_ptr<CleanupPadInst>(new CleanupPadInst(I, *this));
return cast<CleanupPadInst>(registerValue(std::move(NewPtr)));
}
CatchReturnInst *Context::createCatchReturnInst(llvm::CatchReturnInst *I) {
auto NewPtr = std::unique_ptr<CatchReturnInst>(new CatchReturnInst(I, *this));
return cast<CatchReturnInst>(registerValue(std::move(NewPtr)));
}
CleanupReturnInst *
Context::createCleanupReturnInst(llvm::CleanupReturnInst *I) {
auto NewPtr =
std::unique_ptr<CleanupReturnInst>(new CleanupReturnInst(I, *this));
return cast<CleanupReturnInst>(registerValue(std::move(NewPtr)));
}
GetElementPtrInst *
Context::createGetElementPtrInst(llvm::GetElementPtrInst *I) {
auto NewPtr =
std::unique_ptr<GetElementPtrInst>(new GetElementPtrInst(I, *this));
return cast<GetElementPtrInst>(registerValue(std::move(NewPtr)));
}
CatchSwitchInst *Context::createCatchSwitchInst(llvm::CatchSwitchInst *I) {
auto NewPtr = std::unique_ptr<CatchSwitchInst>(new CatchSwitchInst(I, *this));
return cast<CatchSwitchInst>(registerValue(std::move(NewPtr)));
}
ResumeInst *Context::createResumeInst(llvm::ResumeInst *I) {
auto NewPtr = std::unique_ptr<ResumeInst>(new ResumeInst(I, *this));
return cast<ResumeInst>(registerValue(std::move(NewPtr)));
}
SwitchInst *Context::createSwitchInst(llvm::SwitchInst *I) {
auto NewPtr = std::unique_ptr<SwitchInst>(new SwitchInst(I, *this));
return cast<SwitchInst>(registerValue(std::move(NewPtr)));
}
UnaryOperator *Context::createUnaryOperator(llvm::UnaryOperator *I) {
auto NewPtr = std::unique_ptr<UnaryOperator>(new UnaryOperator(I, *this));
return cast<UnaryOperator>(registerValue(std::move(NewPtr)));
}
BinaryOperator *Context::createBinaryOperator(llvm::BinaryOperator *I) {
auto NewPtr = std::unique_ptr<BinaryOperator>(new BinaryOperator(I, *this));
return cast<BinaryOperator>(registerValue(std::move(NewPtr)));
}
AtomicRMWInst *Context::createAtomicRMWInst(llvm::AtomicRMWInst *I) {
auto NewPtr = std::unique_ptr<AtomicRMWInst>(new AtomicRMWInst(I, *this));
return cast<AtomicRMWInst>(registerValue(std::move(NewPtr)));
}
AtomicCmpXchgInst *
Context::createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I) {
auto NewPtr =
std::unique_ptr<AtomicCmpXchgInst>(new AtomicCmpXchgInst(I, *this));
return cast<AtomicCmpXchgInst>(registerValue(std::move(NewPtr)));
}
AllocaInst *Context::createAllocaInst(llvm::AllocaInst *I) {
auto NewPtr = std::unique_ptr<AllocaInst>(new AllocaInst(I, *this));
return cast<AllocaInst>(registerValue(std::move(NewPtr)));
}
CastInst *Context::createCastInst(llvm::CastInst *I) {
auto NewPtr = std::unique_ptr<CastInst>(new CastInst(I, *this));
return cast<CastInst>(registerValue(std::move(NewPtr)));
}
PHINode *Context::createPHINode(llvm::PHINode *I) {
auto NewPtr = std::unique_ptr<PHINode>(new PHINode(I, *this));
return cast<PHINode>(registerValue(std::move(NewPtr)));
}
ICmpInst *Context::createICmpInst(llvm::ICmpInst *I) {
auto NewPtr = std::unique_ptr<ICmpInst>(new ICmpInst(I, *this));
return cast<ICmpInst>(registerValue(std::move(NewPtr)));
}
FCmpInst *Context::createFCmpInst(llvm::FCmpInst *I) {
auto NewPtr = std::unique_ptr<FCmpInst>(new FCmpInst(I, *this));
return cast<FCmpInst>(registerValue(std::move(NewPtr)));
}
Value *Context::getValue(llvm::Value *V) const {
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end())
return It->second.get();
return nullptr;
}
Context::Context(LLVMContext &LLVMCtx)
: LLVMCtx(LLVMCtx), IRTracker(*this),
LLVMIRBuilder(LLVMCtx, ConstantFolder()) {}
Context::~Context() {}
void Context::clear() {
// TODO: Ideally we should clear only function-scope objects, and keep global
// objects, like Constants to avoid recreating them.
LLVMValueToValueMap.clear();
}
Module *Context::getModule(llvm::Module *LLVMM) const {
auto It = LLVMModuleToModuleMap.find(LLVMM);
if (It != LLVMModuleToModuleMap.end())
return It->second.get();
return nullptr;
}
Module *Context::getOrCreateModule(llvm::Module *LLVMM) {
auto Pair = LLVMModuleToModuleMap.try_emplace(LLVMM);
auto It = Pair.first;
if (!Pair.second)
return It->second.get();
It->second = std::unique_ptr<Module>(new Module(*LLVMM, *this));
return It->second.get();
}
Function *Context::createFunction(llvm::Function *F) {
// Create the module if needed before we create the new sandboxir::Function.
// Note: this won't fully populate the module. The only globals that will be
// available will be the ones being used within the function.
getOrCreateModule(F->getParent());
// There may be a function declaration already defined. Regardless destroy it.
if (Function *ExistingF = cast_or_null<Function>(getValue(F)))
detach(ExistingF);
auto NewFPtr = std::unique_ptr<Function>(new Function(F, *this));
auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
// Create arguments.
for (auto &Arg : F->args())
getOrCreateArgument(&Arg);
// Create BBs.
for (auto &BB : *F)
createBasicBlock(&BB);
return SBF;
}
Module *Context::createModule(llvm::Module *LLVMM) {
auto *M = getOrCreateModule(LLVMM);
// Create the functions.
for (auto &LLVMF : *LLVMM)
createFunction(&LLVMF);
// Create globals.
for (auto &Global : LLVMM->globals())
getOrCreateValue(&Global);
// Create aliases.
for (auto &Alias : LLVMM->aliases())
getOrCreateValue(&Alias);
// Create ifuncs.
for (auto &IFunc : LLVMM->ifuncs())
getOrCreateValue(&IFunc);
return M;
}
void Context::runEraseInstrCallbacks(Instruction *I) {
for (const auto &CBEntry : EraseInstrCallbacks)
CBEntry.second(I);
}
void Context::runCreateInstrCallbacks(Instruction *I) {
for (auto &CBEntry : CreateInstrCallbacks)
CBEntry.second(I);
}
void Context::runMoveInstrCallbacks(Instruction *I, const BBIterator &WhereIt) {
for (auto &CBEntry : MoveInstrCallbacks)
CBEntry.second(I, WhereIt);
}
void Context::runSetUseCallbacks(const Use &U, Value *NewSrc) {
for (auto &CBEntry : SetUseCallbacks)
CBEntry.second(U, NewSrc);
}
// An arbitrary limit, to check for accidental misuse. We expect a small number
// of callbacks to be registered at a time, but we can increase this number if
// we discover we needed more.
[[maybe_unused]] static constexpr int MaxRegisteredCallbacks = 16;
Context::CallbackID Context::registerEraseInstrCallback(EraseInstrCallback CB) {
assert(EraseInstrCallbacks.size() <= MaxRegisteredCallbacks &&
"EraseInstrCallbacks size limit exceeded");
CallbackID ID{NextCallbackID++};
EraseInstrCallbacks[ID] = CB;
return ID;
}
void Context::unregisterEraseInstrCallback(CallbackID ID) {
[[maybe_unused]] bool Erased = EraseInstrCallbacks.erase(ID);
assert(Erased &&
"Callback ID not found in EraseInstrCallbacks during deregistration");
}
Context::CallbackID
Context::registerCreateInstrCallback(CreateInstrCallback CB) {
assert(CreateInstrCallbacks.size() <= MaxRegisteredCallbacks &&
"CreateInstrCallbacks size limit exceeded");
CallbackID ID{NextCallbackID++};
CreateInstrCallbacks[ID] = CB;
return ID;
}
void Context::unregisterCreateInstrCallback(CallbackID ID) {
[[maybe_unused]] bool Erased = CreateInstrCallbacks.erase(ID);
assert(Erased &&
"Callback ID not found in CreateInstrCallbacks during deregistration");
}
Context::CallbackID Context::registerMoveInstrCallback(MoveInstrCallback CB) {
assert(MoveInstrCallbacks.size() <= MaxRegisteredCallbacks &&
"MoveInstrCallbacks size limit exceeded");
CallbackID ID{NextCallbackID++};
MoveInstrCallbacks[ID] = CB;
return ID;
}
void Context::unregisterMoveInstrCallback(CallbackID ID) {
[[maybe_unused]] bool Erased = MoveInstrCallbacks.erase(ID);
assert(Erased &&
"Callback ID not found in MoveInstrCallbacks during deregistration");
}
Context::CallbackID Context::registerSetUseCallback(SetUseCallback CB) {
assert(SetUseCallbacks.size() <= MaxRegisteredCallbacks &&
"SetUseCallbacks size limit exceeded");
CallbackID ID{NextCallbackID++};
SetUseCallbacks[ID] = CB;
return ID;
}
void Context::unregisterSetUseCallback(CallbackID ID) {
[[maybe_unused]] bool Erased = SetUseCallbacks.erase(ID);
assert(Erased &&
"Callback ID not found in SetUseCallbacks during deregistration");
}
} // namespace llvm::sandboxir