//===- 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/SandboxIR/Function.h" #include "llvm/SandboxIR/Instruction.h" #include "llvm/SandboxIR/Module.h" namespace llvm::sandboxir { std::unique_ptr Context::detachLLVMValue(llvm::Value *V) { std::unique_ptr Erased; auto It = LLVMValueToValueMap.find(V); if (It != LLVMValueToValueMap.end()) { auto *Val = It->second.release(); Erased = std::unique_ptr(Val); LLVMValueToValueMap.erase(It); } return Erased; } std::unique_ptr 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 &&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(V)) { getTracker().emplaceIfTracking(I); runCreateInstrCallbacks(I); } return V; } Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) { auto Pair = LLVMValueToValueMap.insert({LLVMV, nullptr}); auto It = Pair.first; if (!Pair.second) return It->second.get(); if (auto *C = dyn_cast(LLVMV)) { switch (C->getValueID()) { case llvm::Value::ConstantIntVal: It->second = std::unique_ptr( new ConstantInt(cast(C), *this)); return It->second.get(); case llvm::Value::ConstantFPVal: It->second = std::unique_ptr( new ConstantFP(cast(C), *this)); return It->second.get(); case llvm::Value::BlockAddressVal: It->second = std::unique_ptr( new BlockAddress(cast(C), *this)); return It->second.get(); case llvm::Value::ConstantTokenNoneVal: It->second = std::unique_ptr( new ConstantTokenNone(cast(C), *this)); return It->second.get(); case llvm::Value::ConstantAggregateZeroVal: { auto *CAZ = cast(C); It->second = std::unique_ptr( 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(0, EC.getFixedValue())) getOrCreateValueInternal(CAZ->getElementValue(ElmIdx), CAZ); } return Ret; } case llvm::Value::ConstantPointerNullVal: It->second = std::unique_ptr( new ConstantPointerNull(cast(C), *this)); return It->second.get(); case llvm::Value::PoisonValueVal: It->second = std::unique_ptr( new PoisonValue(cast(C), *this)); return It->second.get(); case llvm::Value::UndefValueVal: It->second = std::unique_ptr( new UndefValue(cast(C), *this)); return It->second.get(); case llvm::Value::DSOLocalEquivalentVal: { auto *DSOLE = cast(C); It->second = std::unique_ptr( new DSOLocalEquivalent(DSOLE, *this)); auto *Ret = It->second.get(); getOrCreateValueInternal(DSOLE->getGlobalValue(), DSOLE); return Ret; } case llvm::Value::ConstantArrayVal: It->second = std::unique_ptr( new ConstantArray(cast(C), *this)); break; case llvm::Value::ConstantStructVal: It->second = std::unique_ptr( new ConstantStruct(cast(C), *this)); break; case llvm::Value::ConstantVectorVal: It->second = std::unique_ptr( new ConstantVector(cast(C), *this)); break; case llvm::Value::FunctionVal: It->second = std::unique_ptr( new Function(cast(C), *this)); break; case llvm::Value::GlobalIFuncVal: It->second = std::unique_ptr( new GlobalIFunc(cast(C), *this)); break; case llvm::Value::GlobalVariableVal: It->second = std::unique_ptr( new GlobalVariable(cast(C), *this)); break; case llvm::Value::GlobalAliasVal: It->second = std::unique_ptr( new GlobalAlias(cast(C), *this)); break; case llvm::Value::NoCFIValueVal: It->second = std::unique_ptr( new NoCFIValue(cast(C), *this)); break; case llvm::Value::ConstantPtrAuthVal: It->second = std::unique_ptr( new ConstantPtrAuth(cast(C), *this)); break; case llvm::Value::ConstantExprVal: It->second = std::unique_ptr( new ConstantExpr(cast(C), *this)); break; default: It->second = std::unique_ptr(new Constant(C, *this)); break; } auto *NewC = It->second.get(); for (llvm::Value *COp : C->operands()) getOrCreateValueInternal(COp, C); return NewC; } if (auto *Arg = dyn_cast(LLVMV)) { It->second = std::unique_ptr(new Argument(Arg, *this)); return It->second.get(); } if (auto *BB = dyn_cast(LLVMV)) { assert(isa(U) && "This won't create a SBBB, don't call this function directly!"); if (auto *SBBB = getValue(BB)) return SBBB; return nullptr; } assert(isa(LLVMV) && "Expected Instruction"); switch (cast(LLVMV)->getOpcode()) { case llvm::Instruction::VAArg: { auto *LLVMVAArg = cast(LLVMV); It->second = std::unique_ptr(new VAArgInst(LLVMVAArg, *this)); return It->second.get(); } case llvm::Instruction::Freeze: { auto *LLVMFreeze = cast(LLVMV); It->second = std::unique_ptr(new FreezeInst(LLVMFreeze, *this)); return It->second.get(); } case llvm::Instruction::Fence: { auto *LLVMFence = cast(LLVMV); It->second = std::unique_ptr(new FenceInst(LLVMFence, *this)); return It->second.get(); } case llvm::Instruction::Select: { auto *LLVMSel = cast(LLVMV); It->second = std::unique_ptr(new SelectInst(LLVMSel, *this)); return It->second.get(); } case llvm::Instruction::ExtractElement: { auto *LLVMIns = cast(LLVMV); It->second = std::unique_ptr( new ExtractElementInst(LLVMIns, *this)); return It->second.get(); } case llvm::Instruction::InsertElement: { auto *LLVMIns = cast(LLVMV); It->second = std::unique_ptr( new InsertElementInst(LLVMIns, *this)); return It->second.get(); } case llvm::Instruction::ShuffleVector: { auto *LLVMIns = cast(LLVMV); It->second = std::unique_ptr( new ShuffleVectorInst(LLVMIns, *this)); return It->second.get(); } case llvm::Instruction::ExtractValue: { auto *LLVMIns = cast(LLVMV); It->second = std::unique_ptr(new ExtractValueInst(LLVMIns, *this)); return It->second.get(); } case llvm::Instruction::InsertValue: { auto *LLVMIns = cast(LLVMV); It->second = std::unique_ptr(new InsertValueInst(LLVMIns, *this)); return It->second.get(); } case llvm::Instruction::Br: { auto *LLVMBr = cast(LLVMV); It->second = std::unique_ptr(new BranchInst(LLVMBr, *this)); return It->second.get(); } case llvm::Instruction::Load: { auto *LLVMLd = cast(LLVMV); It->second = std::unique_ptr(new LoadInst(LLVMLd, *this)); return It->second.get(); } case llvm::Instruction::Store: { auto *LLVMSt = cast(LLVMV); It->second = std::unique_ptr(new StoreInst(LLVMSt, *this)); return It->second.get(); } case llvm::Instruction::Ret: { auto *LLVMRet = cast(LLVMV); It->second = std::unique_ptr(new ReturnInst(LLVMRet, *this)); return It->second.get(); } case llvm::Instruction::Call: { auto *LLVMCall = cast(LLVMV); It->second = std::unique_ptr(new CallInst(LLVMCall, *this)); return It->second.get(); } case llvm::Instruction::Invoke: { auto *LLVMInvoke = cast(LLVMV); It->second = std::unique_ptr(new InvokeInst(LLVMInvoke, *this)); return It->second.get(); } case llvm::Instruction::CallBr: { auto *LLVMCallBr = cast(LLVMV); It->second = std::unique_ptr(new CallBrInst(LLVMCallBr, *this)); return It->second.get(); } case llvm::Instruction::LandingPad: { auto *LLVMLPad = cast(LLVMV); It->second = std::unique_ptr(new LandingPadInst(LLVMLPad, *this)); return It->second.get(); } case llvm::Instruction::CatchPad: { auto *LLVMCPI = cast(LLVMV); It->second = std::unique_ptr(new CatchPadInst(LLVMCPI, *this)); return It->second.get(); } case llvm::Instruction::CleanupPad: { auto *LLVMCPI = cast(LLVMV); It->second = std::unique_ptr(new CleanupPadInst(LLVMCPI, *this)); return It->second.get(); } case llvm::Instruction::CatchRet: { auto *LLVMCRI = cast(LLVMV); It->second = std::unique_ptr(new CatchReturnInst(LLVMCRI, *this)); return It->second.get(); } case llvm::Instruction::CleanupRet: { auto *LLVMCRI = cast(LLVMV); It->second = std::unique_ptr( new CleanupReturnInst(LLVMCRI, *this)); return It->second.get(); } case llvm::Instruction::GetElementPtr: { auto *LLVMGEP = cast(LLVMV); It->second = std::unique_ptr( new GetElementPtrInst(LLVMGEP, *this)); return It->second.get(); } case llvm::Instruction::CatchSwitch: { auto *LLVMCatchSwitchInst = cast(LLVMV); It->second = std::unique_ptr( new CatchSwitchInst(LLVMCatchSwitchInst, *this)); return It->second.get(); } case llvm::Instruction::Resume: { auto *LLVMResumeInst = cast(LLVMV); It->second = std::unique_ptr(new ResumeInst(LLVMResumeInst, *this)); return It->second.get(); } case llvm::Instruction::Switch: { auto *LLVMSwitchInst = cast(LLVMV); It->second = std::unique_ptr(new SwitchInst(LLVMSwitchInst, *this)); return It->second.get(); } case llvm::Instruction::FNeg: { auto *LLVMUnaryOperator = cast(LLVMV); It->second = std::unique_ptr( 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(LLVMV); It->second = std::unique_ptr( new BinaryOperator(LLVMBinaryOperator, *this)); return It->second.get(); } case llvm::Instruction::AtomicRMW: { auto *LLVMAtomicRMW = cast(LLVMV); It->second = std::unique_ptr(new AtomicRMWInst(LLVMAtomicRMW, *this)); return It->second.get(); } case llvm::Instruction::AtomicCmpXchg: { auto *LLVMAtomicCmpXchg = cast(LLVMV); It->second = std::unique_ptr( new AtomicCmpXchgInst(LLVMAtomicCmpXchg, *this)); return It->second.get(); } case llvm::Instruction::Alloca: { auto *LLVMAlloca = cast(LLVMV); It->second = std::unique_ptr(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::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(LLVMV); It->second = std::unique_ptr(new CastInst(LLVMCast, *this)); return It->second.get(); } case llvm::Instruction::PHI: { auto *LLVMPhi = cast(LLVMV); It->second = std::unique_ptr(new PHINode(LLVMPhi, *this)); return It->second.get(); } case llvm::Instruction::ICmp: { auto *LLVMICmp = cast(LLVMV); It->second = std::unique_ptr(new ICmpInst(LLVMICmp, *this)); return It->second.get(); } case llvm::Instruction::FCmp: { auto *LLVMFCmp = cast(LLVMV); It->second = std::unique_ptr(new FCmpInst(LLVMFCmp, *this)); return It->second.get(); } case llvm::Instruction::Unreachable: { auto *LLVMUnreachable = cast(LLVMV); It->second = std::unique_ptr( new UnreachableInst(LLVMUnreachable, *this)); return It->second.get(); } default: break; } It->second = std::unique_ptr( new OpaqueInst(cast(LLVMV), *this)); return It->second.get(); } Argument *Context::getOrCreateArgument(llvm::Argument *LLVMArg) { auto Pair = LLVMValueToValueMap.insert({LLVMArg, nullptr}); auto It = Pair.first; if (Pair.second) { It->second = std::unique_ptr(new Argument(LLVMArg, *this)); return cast(It->second.get()); } return cast(It->second.get()); } Constant *Context::getOrCreateConstant(llvm::Constant *LLVMC) { return cast(getOrCreateValueInternal(LLVMC, 0)); } BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) { assert(getValue(LLVMBB) == nullptr && "Already exists!"); auto NewBBPtr = std::unique_ptr(new BasicBlock(LLVMBB, *this)); auto *BB = cast(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(new VAArgInst(SI, *this)); return cast(registerValue(std::move(NewPtr))); } FreezeInst *Context::createFreezeInst(llvm::FreezeInst *SI) { auto NewPtr = std::unique_ptr(new FreezeInst(SI, *this)); return cast(registerValue(std::move(NewPtr))); } FenceInst *Context::createFenceInst(llvm::FenceInst *SI) { auto NewPtr = std::unique_ptr(new FenceInst(SI, *this)); return cast(registerValue(std::move(NewPtr))); } SelectInst *Context::createSelectInst(llvm::SelectInst *SI) { auto NewPtr = std::unique_ptr(new SelectInst(SI, *this)); return cast(registerValue(std::move(NewPtr))); } ExtractElementInst * Context::createExtractElementInst(llvm::ExtractElementInst *EEI) { auto NewPtr = std::unique_ptr(new ExtractElementInst(EEI, *this)); return cast(registerValue(std::move(NewPtr))); } InsertElementInst * Context::createInsertElementInst(llvm::InsertElementInst *IEI) { auto NewPtr = std::unique_ptr(new InsertElementInst(IEI, *this)); return cast(registerValue(std::move(NewPtr))); } ShuffleVectorInst * Context::createShuffleVectorInst(llvm::ShuffleVectorInst *SVI) { auto NewPtr = std::unique_ptr(new ShuffleVectorInst(SVI, *this)); return cast(registerValue(std::move(NewPtr))); } ExtractValueInst *Context::createExtractValueInst(llvm::ExtractValueInst *EVI) { auto NewPtr = std::unique_ptr(new ExtractValueInst(EVI, *this)); return cast(registerValue(std::move(NewPtr))); } InsertValueInst *Context::createInsertValueInst(llvm::InsertValueInst *IVI) { auto NewPtr = std::unique_ptr(new InsertValueInst(IVI, *this)); return cast(registerValue(std::move(NewPtr))); } BranchInst *Context::createBranchInst(llvm::BranchInst *BI) { auto NewPtr = std::unique_ptr(new BranchInst(BI, *this)); return cast(registerValue(std::move(NewPtr))); } LoadInst *Context::createLoadInst(llvm::LoadInst *LI) { auto NewPtr = std::unique_ptr(new LoadInst(LI, *this)); return cast(registerValue(std::move(NewPtr))); } StoreInst *Context::createStoreInst(llvm::StoreInst *SI) { auto NewPtr = std::unique_ptr(new StoreInst(SI, *this)); return cast(registerValue(std::move(NewPtr))); } ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) { auto NewPtr = std::unique_ptr(new ReturnInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CallInst *Context::createCallInst(llvm::CallInst *I) { auto NewPtr = std::unique_ptr(new CallInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } InvokeInst *Context::createInvokeInst(llvm::InvokeInst *I) { auto NewPtr = std::unique_ptr(new InvokeInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CallBrInst *Context::createCallBrInst(llvm::CallBrInst *I) { auto NewPtr = std::unique_ptr(new CallBrInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } UnreachableInst *Context::createUnreachableInst(llvm::UnreachableInst *UI) { auto NewPtr = std::unique_ptr(new UnreachableInst(UI, *this)); return cast(registerValue(std::move(NewPtr))); } LandingPadInst *Context::createLandingPadInst(llvm::LandingPadInst *I) { auto NewPtr = std::unique_ptr(new LandingPadInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CatchPadInst *Context::createCatchPadInst(llvm::CatchPadInst *I) { auto NewPtr = std::unique_ptr(new CatchPadInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CleanupPadInst *Context::createCleanupPadInst(llvm::CleanupPadInst *I) { auto NewPtr = std::unique_ptr(new CleanupPadInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CatchReturnInst *Context::createCatchReturnInst(llvm::CatchReturnInst *I) { auto NewPtr = std::unique_ptr(new CatchReturnInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CleanupReturnInst * Context::createCleanupReturnInst(llvm::CleanupReturnInst *I) { auto NewPtr = std::unique_ptr(new CleanupReturnInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } GetElementPtrInst * Context::createGetElementPtrInst(llvm::GetElementPtrInst *I) { auto NewPtr = std::unique_ptr(new GetElementPtrInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CatchSwitchInst *Context::createCatchSwitchInst(llvm::CatchSwitchInst *I) { auto NewPtr = std::unique_ptr(new CatchSwitchInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } ResumeInst *Context::createResumeInst(llvm::ResumeInst *I) { auto NewPtr = std::unique_ptr(new ResumeInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } SwitchInst *Context::createSwitchInst(llvm::SwitchInst *I) { auto NewPtr = std::unique_ptr(new SwitchInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } UnaryOperator *Context::createUnaryOperator(llvm::UnaryOperator *I) { auto NewPtr = std::unique_ptr(new UnaryOperator(I, *this)); return cast(registerValue(std::move(NewPtr))); } BinaryOperator *Context::createBinaryOperator(llvm::BinaryOperator *I) { auto NewPtr = std::unique_ptr(new BinaryOperator(I, *this)); return cast(registerValue(std::move(NewPtr))); } AtomicRMWInst *Context::createAtomicRMWInst(llvm::AtomicRMWInst *I) { auto NewPtr = std::unique_ptr(new AtomicRMWInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } AtomicCmpXchgInst * Context::createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I) { auto NewPtr = std::unique_ptr(new AtomicCmpXchgInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } AllocaInst *Context::createAllocaInst(llvm::AllocaInst *I) { auto NewPtr = std::unique_ptr(new AllocaInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } CastInst *Context::createCastInst(llvm::CastInst *I) { auto NewPtr = std::unique_ptr(new CastInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } PHINode *Context::createPHINode(llvm::PHINode *I) { auto NewPtr = std::unique_ptr(new PHINode(I, *this)); return cast(registerValue(std::move(NewPtr))); } ICmpInst *Context::createICmpInst(llvm::ICmpInst *I) { auto NewPtr = std::unique_ptr(new ICmpInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } FCmpInst *Context::createFCmpInst(llvm::FCmpInst *I) { auto NewPtr = std::unique_ptr(new FCmpInst(I, *this)); return cast(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.insert({LLVMM, nullptr}); auto It = Pair.first; if (!Pair.second) return It->second.get(); It->second = std::unique_ptr(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(getValue(F))) detach(ExistingF); auto NewFPtr = std::unique_ptr(new Function(F, *this)); auto *SBF = cast(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); } // 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"); } } // namespace llvm::sandboxir