//===- Instruction.cpp - The Instructions 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/Instruction.h" #include "llvm/SandboxIR/Function.h" namespace llvm::sandboxir { const char *Instruction::getOpcodeName(Opcode Opc) { switch (Opc) { #define OP(OPC) \ case Opcode::OPC: \ return #OPC; #define OPCODES(...) __VA_ARGS__ #define DEF_INSTR(ID, OPC, CLASS) OPC #include "llvm/SandboxIR/Values.def" } llvm_unreachable("Unknown Opcode"); } llvm::Instruction *Instruction::getTopmostLLVMInstruction() const { Instruction *Prev = getPrevNode(); if (Prev == nullptr) { // If at top of the BB, return the first BB instruction. return &*cast(getParent()->Val)->begin(); } // Else get the Previous sandbox IR instruction's bottom IR instruction and // return its successor. llvm::Instruction *PrevBotI = cast(Prev->Val); return PrevBotI->getNextNode(); } BBIterator Instruction::getIterator() const { auto *I = cast(Val); return BasicBlock::iterator(I->getParent(), I->getIterator(), &Ctx); } Instruction *Instruction::getNextNode() const { assert(getParent() != nullptr && "Detached!"); assert(getIterator() != getParent()->end() && "Already at end!"); // `Val` is the bottom-most LLVM IR instruction. Get the next in the chain, // and get the corresponding sandboxir Instruction that maps to it. This works // even for SandboxIR Instructions that map to more than one LLVM Instruction. auto *LLVMI = cast(Val); assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!"); auto *NextLLVMI = LLVMI->getNextNode(); auto *NextI = cast_or_null(Ctx.getValue(NextLLVMI)); if (NextI == nullptr) return nullptr; return NextI; } Instruction *Instruction::getPrevNode() const { assert(getParent() != nullptr && "Detached!"); auto It = getIterator(); if (It != getParent()->begin()) return std::prev(getIterator()).get(); return nullptr; } void Instruction::removeFromParent() { Ctx.getTracker().emplaceIfTracking(this); // Detach all the LLVM IR instructions from their parent BB. for (llvm::Instruction *I : getLLVMInstrs()) I->removeFromParent(); } void Instruction::eraseFromParent() { assert(users().empty() && "Still connected to users, can't erase!"); Ctx.runEraseInstrCallbacks(this); std::unique_ptr Detached = Ctx.detach(this); auto LLVMInstrs = getLLVMInstrs(); auto &Tracker = Ctx.getTracker(); if (Tracker.isTracking()) { Tracker.track(std::make_unique(std::move(Detached))); // We don't actually delete the IR instruction, because then it would be // impossible to bring it back from the dead at the same memory location. // Instead we remove it from its BB and track its current location. for (llvm::Instruction *I : LLVMInstrs) I->removeFromParent(); // TODO: Multi-instructions need special treatment because some of the // references are internal to the instruction. for (llvm::Instruction *I : LLVMInstrs) I->dropAllReferences(); } else { // Erase in reverse to avoid erasing nstructions with attached uses. for (llvm::Instruction *I : reverse(LLVMInstrs)) I->eraseFromParent(); } } void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) { if (std::next(getIterator()) == WhereIt) // Destination is same as origin, nothing to do. return; Ctx.runMoveInstrCallbacks(this, WhereIt); Ctx.getTracker().emplaceIfTracking(this); auto *LLVMBB = cast(BB.Val); llvm::BasicBlock::iterator It; if (WhereIt == BB.end()) { It = LLVMBB->end(); } else { Instruction *WhereI = &*WhereIt; It = WhereI->getTopmostLLVMInstruction()->getIterator(); } // TODO: Move this to the verifier of sandboxir::Instruction. assert(is_sorted(getLLVMInstrs(), [](auto *I1, auto *I2) { return I1->comesBefore(I2); }) && "Expected program order!"); // Do the actual move in LLVM IR. for (auto *I : getLLVMInstrs()) I->moveBefore(*LLVMBB, It); } void Instruction::insertBefore(Instruction *BeforeI) { llvm::Instruction *BeforeTopI = BeforeI->getTopmostLLVMInstruction(); Ctx.getTracker().emplaceIfTracking(this); // Insert the LLVM IR Instructions in program order. for (llvm::Instruction *I : getLLVMInstrs()) I->insertBefore(BeforeTopI->getIterator()); } void Instruction::insertAfter(Instruction *AfterI) { insertInto(AfterI->getParent(), std::next(AfterI->getIterator())); } void Instruction::insertInto(BasicBlock *BB, const BBIterator &WhereIt) { llvm::BasicBlock *LLVMBB = cast(BB->Val); llvm::Instruction *LLVMBeforeI; llvm::BasicBlock::iterator LLVMBeforeIt; Instruction *BeforeI; if (WhereIt != BB->end()) { BeforeI = &*WhereIt; LLVMBeforeI = BeforeI->getTopmostLLVMInstruction(); LLVMBeforeIt = LLVMBeforeI->getIterator(); } else { BeforeI = nullptr; LLVMBeforeI = nullptr; LLVMBeforeIt = LLVMBB->end(); } Ctx.getTracker().emplaceIfTracking(this); // Insert the LLVM IR Instructions in program order. for (llvm::Instruction *I : getLLVMInstrs()) I->insertInto(LLVMBB, LLVMBeforeIt); } BasicBlock *Instruction::getParent() const { // Get the LLVM IR Instruction that this maps to, get its parent, and get the // corresponding sandboxir::BasicBlock by looking it up in sandboxir::Context. auto *BB = cast(Val)->getParent(); if (BB == nullptr) return nullptr; return cast(Ctx.getValue(BB)); } bool Instruction::classof(const sandboxir::Value *From) { switch (From->getSubclassID()) { #define DEF_INSTR(ID, OPC, CLASS) \ case ClassID::ID: \ return true; #include "llvm/SandboxIR/Values.def" default: return false; } } void Instruction::setHasNoUnsignedWrap(bool B) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setHasNoUnsignedWrap(B); } void Instruction::setHasNoSignedWrap(bool B) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setHasNoSignedWrap(B); } void Instruction::setFast(bool B) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&Instruction::isFast, &Instruction::setFast>>(this); cast(Val)->setFast(B); } void Instruction::setIsExact(bool B) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&Instruction::isExact, &Instruction::setIsExact>>(this); cast(Val)->setIsExact(B); } void Instruction::setHasAllowReassoc(bool B) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setHasAllowReassoc(B); } void Instruction::setHasNoNaNs(bool B) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&Instruction::hasNoNaNs, &Instruction::setHasNoNaNs>>( this); cast(Val)->setHasNoNaNs(B); } void Instruction::setHasNoInfs(bool B) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&Instruction::hasNoInfs, &Instruction::setHasNoInfs>>( this); cast(Val)->setHasNoInfs(B); } void Instruction::setHasNoSignedZeros(bool B) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setHasNoSignedZeros(B); } void Instruction::setHasAllowReciprocal(bool B) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setHasAllowReciprocal(B); } void Instruction::setHasAllowContract(bool B) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setHasAllowContract(B); } void Instruction::setFastMathFlags(FastMathFlags FMF) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setFastMathFlags(FMF); } void Instruction::copyFastMathFlags(FastMathFlags FMF) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->copyFastMathFlags(FMF); } Type *Instruction::getAccessType() const { return Ctx.getType(cast(Val)->getAccessType()); } void Instruction::setHasApproxFunc(bool B) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setHasApproxFunc(B); } #ifndef NDEBUG void Instruction::dumpOS(raw_ostream &OS) const { OS << "Unimplemented! Please override dump()."; } #endif // NDEBUG VAArgInst *VAArgInst::create(Value *List, Type *Ty, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *LLVMI = cast(Builder.CreateVAArg(List->Val, Ty->LLVMTy, Name)); return Ctx.createVAArgInst(LLVMI); } Value *VAArgInst::getPointerOperand() { return Ctx.getValue(cast(Val)->getPointerOperand()); } FreezeInst *FreezeInst::create(Value *V, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *LLVMI = cast(Builder.CreateFreeze(V->Val, Name)); return Ctx.createFreezeInst(LLVMI); } FenceInst *FenceInst::create(AtomicOrdering Ordering, InsertPosition Pos, Context &Ctx, SyncScope::ID SSID) { auto &Builder = Instruction::setInsertPos(Pos); llvm::FenceInst *LLVMI = Builder.CreateFence(Ordering, SSID); return Ctx.createFenceInst(LLVMI); } void FenceInst::setOrdering(AtomicOrdering Ordering) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&FenceInst::getOrdering, &FenceInst::setOrdering>>( this); cast(Val)->setOrdering(Ordering); } void FenceInst::setSyncScopeID(SyncScope::ID SSID) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setSyncScopeID(SSID); } Value *SelectInst::create(Value *Cond, Value *True, Value *False, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = Instruction::setInsertPos(Pos); llvm::Value *NewV = Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name); if (auto *NewSI = dyn_cast(NewV)) return Ctx.createSelectInst(NewSI); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } void SelectInst::swapValues() { Ctx.getTracker().emplaceIfTracking(getOperandUse(1), getOperandUse(2)); cast(Val)->swapValues(); } bool SelectInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Select; } BranchInst *BranchInst::create(BasicBlock *IfTrue, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); llvm::BranchInst *NewBr = Builder.CreateBr(cast(IfTrue->Val)); return Ctx.createBranchInst(NewBr); } BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); llvm::BranchInst *NewBr = Builder.CreateCondBr(Cond->Val, cast(IfTrue->Val), cast(IfFalse->Val)); return Ctx.createBranchInst(NewBr); } bool BranchInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Br; } Value *BranchInst::getCondition() const { assert(isConditional() && "Cannot get condition of an uncond branch!"); return Ctx.getValue(cast(Val)->getCondition()); } BasicBlock *BranchInst::getSuccessor(unsigned SuccIdx) const { assert(SuccIdx < getNumSuccessors() && "Successor # out of range for Branch!"); return cast_or_null( Ctx.getValue(cast(Val)->getSuccessor(SuccIdx))); } void BranchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) { assert((Idx == 0 || Idx == 1) && "Out of bounds!"); setOperand(2u - Idx, NewSucc); } BasicBlock *BranchInst::LLVMBBToSBBB::operator()(llvm::BasicBlock *BB) const { return cast(Ctx.getValue(BB)); } const BasicBlock * BranchInst::ConstLLVMBBToSBBB::operator()(const llvm::BasicBlock *BB) const { return cast(Ctx.getValue(BB)); } void LoadInst::setVolatile(bool V) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&LoadInst::isVolatile, &LoadInst::setVolatile>>(this); cast(Val)->setVolatile(V); } LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *NewLI = Builder.CreateAlignedLoad(Ty->LLVMTy, Ptr->Val, Align, IsVolatile, Name); auto *NewSBI = Ctx.createLoadInst(NewLI); return NewSBI; } bool LoadInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Load; } Value *LoadInst::getPointerOperand() const { return Ctx.getValue(cast(Val)->getPointerOperand()); } void StoreInst::setVolatile(bool V) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&StoreInst::isVolatile, &StoreInst::setVolatile>>(this); cast(Val)->setVolatile(V); } StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx) { auto &Builder = setInsertPos(Pos); auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile); auto *NewSBI = Ctx.createStoreInst(NewSI); return NewSBI; } bool StoreInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Store; } Value *StoreInst::getValueOperand() const { return Ctx.getValue(cast(Val)->getValueOperand()); } Value *StoreInst::getPointerOperand() const { return Ctx.getValue(cast(Val)->getPointerOperand()); } UnreachableInst *UnreachableInst::create(InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); llvm::UnreachableInst *NewUI = Builder.CreateUnreachable(); return Ctx.createUnreachableInst(NewUI); } bool UnreachableInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Unreachable; } ReturnInst *ReturnInst::createCommon(Value *RetVal, IRBuilder<> &Builder, Context &Ctx) { llvm::ReturnInst *NewRI; if (RetVal != nullptr) NewRI = Builder.CreateRet(RetVal->Val); else NewRI = Builder.CreateRetVoid(); return Ctx.createReturnInst(NewRI); } ReturnInst *ReturnInst::create(Value *RetVal, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); return createCommon(RetVal, Builder, Ctx); } Value *ReturnInst::getReturnValue() const { auto *LLVMRetVal = cast(Val)->getReturnValue(); return LLVMRetVal != nullptr ? Ctx.getValue(LLVMRetVal) : nullptr; } FunctionType *CallBase::getFunctionType() const { return cast( Ctx.getType(cast(Val)->getFunctionType())); } Value *CallBase::getCalledOperand() const { return Ctx.getValue(cast(Val)->getCalledOperand()); } Use CallBase::getCalledOperandUse() const { llvm::Use *LLVMUse = &cast(Val)->getCalledOperandUse(); return Use(LLVMUse, cast(Ctx.getValue(LLVMUse->getUser())), Ctx); } Function *CallBase::getCalledFunction() const { return cast_or_null( Ctx.getValue(cast(Val)->getCalledFunction())); } Function *CallBase::getCaller() { return cast(Ctx.getValue(cast(Val)->getCaller())); } void CallBase::setCalledFunction(Function *F) { // F's function type is private, so we rely on `setCalledFunction()` to update // it. But even though we are calling `setCalledFunction()` we also need to // track this change at the SandboxIR level, which is why we call // `setCalledOperand()` here. // Note: This may break if `setCalledFunction()` early returns if `F` // is already set, but we do have a unit test for it. setCalledOperand(F); cast(Val)->setCalledFunction( cast(F->getFunctionType()->LLVMTy), cast(F->Val)); } CallInst *CallInst::create(FunctionType *FTy, Value *Func, ArrayRef Args, InsertPosition Pos, Context &Ctx, const Twine &NameStr) { auto &Builder = setInsertPos(Pos); SmallVector LLVMArgs; LLVMArgs.reserve(Args.size()); for (Value *Arg : Args) LLVMArgs.push_back(Arg->Val); llvm::CallInst *NewCI = Builder.CreateCall( cast(FTy->LLVMTy), Func->Val, LLVMArgs, NameStr); return Ctx.createCallInst(NewCI); } InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, InsertPosition Pos, Context &Ctx, const Twine &NameStr) { auto &Builder = setInsertPos(Pos); SmallVector LLVMArgs; LLVMArgs.reserve(Args.size()); for (Value *Arg : Args) LLVMArgs.push_back(Arg->Val); llvm::InvokeInst *Invoke = Builder.CreateInvoke( cast(FTy->LLVMTy), Func->Val, cast(IfNormal->Val), cast(IfException->Val), LLVMArgs, NameStr); return Ctx.createInvokeInst(Invoke); } BasicBlock *InvokeInst::getNormalDest() const { return cast( Ctx.getValue(cast(Val)->getNormalDest())); } BasicBlock *InvokeInst::getUnwindDest() const { return cast( Ctx.getValue(cast(Val)->getUnwindDest())); } void InvokeInst::setNormalDest(BasicBlock *BB) { setOperand(1, BB); assert(getNormalDest() == BB && "LLVM IR uses a different operan index!"); } void InvokeInst::setUnwindDest(BasicBlock *BB) { setOperand(2, BB); assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!"); } LandingPadInst *InvokeInst::getLandingPadInst() const { return cast( Ctx.getValue(cast(Val)->getLandingPadInst())); ; } BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const { return cast( Ctx.getValue(cast(Val)->getSuccessor(SuccIdx))); } CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func, BasicBlock *DefaultDest, ArrayRef IndirectDests, ArrayRef Args, InsertPosition Pos, Context &Ctx, const Twine &NameStr) { auto &Builder = setInsertPos(Pos); SmallVector LLVMIndirectDests; LLVMIndirectDests.reserve(IndirectDests.size()); for (BasicBlock *IndDest : IndirectDests) LLVMIndirectDests.push_back(cast(IndDest->Val)); SmallVector LLVMArgs; LLVMArgs.reserve(Args.size()); for (Value *Arg : Args) LLVMArgs.push_back(Arg->Val); llvm::CallBrInst *CallBr = Builder.CreateCallBr(cast(FTy->LLVMTy), Func->Val, cast(DefaultDest->Val), LLVMIndirectDests, LLVMArgs, NameStr); return Ctx.createCallBrInst(CallBr); } Value *CallBrInst::getIndirectDestLabel(unsigned Idx) const { return Ctx.getValue(cast(Val)->getIndirectDestLabel(Idx)); } Value *CallBrInst::getIndirectDestLabelUse(unsigned Idx) const { return Ctx.getValue( cast(Val)->getIndirectDestLabelUse(Idx)); } BasicBlock *CallBrInst::getDefaultDest() const { return cast( Ctx.getValue(cast(Val)->getDefaultDest())); } BasicBlock *CallBrInst::getIndirectDest(unsigned Idx) const { return cast( Ctx.getValue(cast(Val)->getIndirectDest(Idx))); } llvm::SmallVector CallBrInst::getIndirectDests() const { SmallVector BBs; for (llvm::BasicBlock *LLVMBB : cast(Val)->getIndirectDests()) BBs.push_back(cast(Ctx.getValue(LLVMBB))); return BBs; } void CallBrInst::setDefaultDest(BasicBlock *BB) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setDefaultDest(cast(BB->Val)); } void CallBrInst::setIndirectDest(unsigned Idx, BasicBlock *BB) { Ctx.getTracker() .emplaceIfTracking>( this, Idx); cast(Val)->setIndirectDest(Idx, cast(BB->Val)); } BasicBlock *CallBrInst::getSuccessor(unsigned Idx) const { return cast( Ctx.getValue(cast(Val)->getSuccessor(Idx))); } LandingPadInst *LandingPadInst::create(Type *RetTy, unsigned NumReservedClauses, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::LandingPadInst *LLVMI = Builder.CreateLandingPad(RetTy->LLVMTy, NumReservedClauses, Name); return Ctx.createLandingPadInst(LLVMI); } void LandingPadInst::setCleanup(bool V) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setCleanup(V); } Constant *LandingPadInst::getClause(unsigned Idx) const { return cast( Ctx.getValue(cast(Val)->getClause(Idx))); } Value *FuncletPadInst::getParentPad() const { return Ctx.getValue(cast(Val)->getParentPad()); } void FuncletPadInst::setParentPad(Value *ParentPad) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setParentPad(ParentPad->Val); } Value *FuncletPadInst::getArgOperand(unsigned Idx) const { return Ctx.getValue(cast(Val)->getArgOperand(Idx)); } void FuncletPadInst::setArgOperand(unsigned Idx, Value *V) { Ctx.getTracker() .emplaceIfTracking>( this, Idx); cast(Val)->setArgOperand(Idx, V->Val); } CatchSwitchInst *CatchPadInst::getCatchSwitch() const { return cast( Ctx.getValue(cast(Val)->getCatchSwitch())); } CatchPadInst *CatchPadInst::create(Value *ParentPad, ArrayRef Args, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); SmallVector LLVMArgs; LLVMArgs.reserve(Args.size()); for (auto *Arg : Args) LLVMArgs.push_back(Arg->Val); llvm::CatchPadInst *LLVMI = Builder.CreateCatchPad(ParentPad->Val, LLVMArgs, Name); return Ctx.createCatchPadInst(LLVMI); } CleanupPadInst *CleanupPadInst::create(Value *ParentPad, ArrayRef Args, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); SmallVector LLVMArgs; LLVMArgs.reserve(Args.size()); for (auto *Arg : Args) LLVMArgs.push_back(Arg->Val); llvm::CleanupPadInst *LLVMI = Builder.CreateCleanupPad(ParentPad->Val, LLVMArgs, Name); return Ctx.createCleanupPadInst(LLVMI); } CatchReturnInst *CatchReturnInst::create(CatchPadInst *CatchPad, BasicBlock *BB, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); llvm::CatchReturnInst *LLVMI = Builder.CreateCatchRet( cast(CatchPad->Val), cast(BB->Val)); return Ctx.createCatchReturnInst(LLVMI); } CatchPadInst *CatchReturnInst::getCatchPad() const { return cast( Ctx.getValue(cast(Val)->getCatchPad())); } void CatchReturnInst::setCatchPad(CatchPadInst *CatchPad) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setCatchPad( cast(CatchPad->Val)); } BasicBlock *CatchReturnInst::getSuccessor() const { return cast( Ctx.getValue(cast(Val)->getSuccessor())); } void CatchReturnInst::setSuccessor(BasicBlock *NewSucc) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setSuccessor( cast(NewSucc->Val)); } Value *CatchReturnInst::getCatchSwitchParentPad() const { return Ctx.getValue( cast(Val)->getCatchSwitchParentPad()); } CleanupReturnInst *CleanupReturnInst::create(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); auto *LLVMUnwindBB = UnwindBB != nullptr ? cast(UnwindBB->Val) : nullptr; llvm::CleanupReturnInst *LLVMI = Builder.CreateCleanupRet( cast(CleanupPad->Val), LLVMUnwindBB); return Ctx.createCleanupReturnInst(LLVMI); } CleanupPadInst *CleanupReturnInst::getCleanupPad() const { return cast( Ctx.getValue(cast(Val)->getCleanupPad())); } void CleanupReturnInst::setCleanupPad(CleanupPadInst *CleanupPad) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setCleanupPad( cast(CleanupPad->Val)); } BasicBlock *CleanupReturnInst::getUnwindDest() const { return cast_or_null( Ctx.getValue(cast(Val)->getUnwindDest())); } void CleanupReturnInst::setUnwindDest(BasicBlock *NewDest) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setUnwindDest( cast(NewDest->Val)); } Value *GetElementPtrInst::create(Type *Ty, Value *Ptr, ArrayRef IdxList, InsertPosition Pos, Context &Ctx, const Twine &NameStr) { auto &Builder = setInsertPos(Pos); SmallVector LLVMIdxList; LLVMIdxList.reserve(IdxList.size()); for (Value *Idx : IdxList) LLVMIdxList.push_back(Idx->Val); llvm::Value *NewV = Builder.CreateGEP(Ty->LLVMTy, Ptr->Val, LLVMIdxList, NameStr); if (auto *NewGEP = dyn_cast(NewV)) return Ctx.createGetElementPtrInst(NewGEP); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Type *GetElementPtrInst::getSourceElementType() const { return Ctx.getType( cast(Val)->getSourceElementType()); } Type *GetElementPtrInst::getResultElementType() const { return Ctx.getType( cast(Val)->getResultElementType()); } Value *GetElementPtrInst::getPointerOperand() const { return Ctx.getValue(cast(Val)->getPointerOperand()); } Type *GetElementPtrInst::getPointerOperandType() const { return Ctx.getType( cast(Val)->getPointerOperandType()); } BasicBlock *PHINode::LLVMBBToBB::operator()(llvm::BasicBlock *LLVMBB) const { return cast(Ctx.getValue(LLVMBB)); } PHINode *PHINode::create(Type *Ty, unsigned NumReservedValues, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::PHINode *NewPHI = Builder.CreatePHI(Ty->LLVMTy, NumReservedValues, Name); return Ctx.createPHINode(NewPHI); } bool PHINode::classof(const Value *From) { return From->getSubclassID() == ClassID::PHI; } Value *PHINode::getIncomingValue(unsigned Idx) const { return Ctx.getValue(cast(Val)->getIncomingValue(Idx)); } void PHINode::setIncomingValue(unsigned Idx, Value *V) { Ctx.getTracker() .emplaceIfTracking>(this, Idx); cast(Val)->setIncomingValue(Idx, V->Val); } BasicBlock *PHINode::getIncomingBlock(unsigned Idx) const { return cast( Ctx.getValue(cast(Val)->getIncomingBlock(Idx))); } BasicBlock *PHINode::getIncomingBlock(const Use &U) const { llvm::Use *LLVMUse = U.LLVMUse; llvm::BasicBlock *BB = cast(Val)->getIncomingBlock(*LLVMUse); return cast(Ctx.getValue(BB)); } void PHINode::setIncomingBlock(unsigned Idx, BasicBlock *BB) { // Helper to disambiguate PHINode::getIncomingBlock(unsigned). constexpr BasicBlock *(PHINode::*GetIncomingBlockFn)(unsigned) const = &PHINode::getIncomingBlock; Ctx.getTracker() .emplaceIfTracking< GenericSetterWithIdx>( this, Idx); cast(Val)->setIncomingBlock(Idx, cast(BB->Val)); } void PHINode::addIncoming(Value *V, BasicBlock *BB) { auto &Tracker = Ctx.getTracker(); Tracker.emplaceIfTracking(this); cast(Val)->addIncoming(V->Val, cast(BB->Val)); } Value *PHINode::removeIncomingValue(unsigned Idx) { auto &Tracker = Ctx.getTracker(); Tracker.emplaceIfTracking(this, Idx); llvm::Value *LLVMV = cast(Val)->removeIncomingValue(Idx, /*DeletePHIIfEmpty=*/false); return Ctx.getValue(LLVMV); } Value *PHINode::removeIncomingValue(BasicBlock *BB) { auto &Tracker = Ctx.getTracker(); Tracker.emplaceIfTracking(this, getBasicBlockIndex(BB)); auto *LLVMBB = cast(BB->Val); llvm::Value *LLVMV = cast(Val)->removeIncomingValue(LLVMBB, /*DeletePHIIfEmpty=*/false); return Ctx.getValue(LLVMV); } int PHINode::getBasicBlockIndex(const BasicBlock *BB) const { auto *LLVMBB = cast(BB->Val); return cast(Val)->getBasicBlockIndex(LLVMBB); } Value *PHINode::getIncomingValueForBlock(const BasicBlock *BB) const { auto *LLVMBB = cast(BB->Val); llvm::Value *LLVMV = cast(Val)->getIncomingValueForBlock(LLVMBB); return Ctx.getValue(LLVMV); } Value *PHINode::hasConstantValue() const { llvm::Value *LLVMV = cast(Val)->hasConstantValue(); return LLVMV != nullptr ? Ctx.getValue(LLVMV) : nullptr; } void PHINode::replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New) { assert(New && Old && "Sandbox IR PHI node got a null basic block!"); for (unsigned Idx = 0, NumOps = cast(Val)->getNumOperands(); Idx != NumOps; ++Idx) if (getIncomingBlock(Idx) == Old) setIncomingBlock(Idx, New); } void PHINode::removeIncomingValueIf(function_ref Predicate) { // Avoid duplicate tracking by going through this->removeIncomingValue here at // the expense of some performance. Copy PHI::removeIncomingValueIf more // directly if performance becomes an issue. // Removing the element at index X, moves the element previously at X + 1 // to X. Working from the end avoids complications from that. unsigned Idx = getNumIncomingValues(); while (Idx > 0) { if (Predicate(Idx - 1)) removeIncomingValue(Idx - 1); --Idx; } } Value *CmpInst::create(Predicate P, Value *S1, Value *S2, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *LLVMV = Builder.CreateCmp(P, S1->Val, S2->Val, Name); // It may have been folded into a constant. if (auto *LLVMC = dyn_cast(LLVMV)) return Ctx.getOrCreateConstant(LLVMC); if (isa(LLVMV)) return Ctx.createICmpInst(cast(LLVMV)); return Ctx.createFCmpInst(cast(LLVMV)); } Value *CmpInst::createWithCopiedFlags(Predicate P, Value *S1, Value *S2, const Instruction *F, InsertPosition Pos, Context &Ctx, const Twine &Name) { Value *V = create(P, S1, S2, Pos, Ctx, Name); if (auto *C = dyn_cast(V)) return C; cast(V->Val)->copyIRFlags(F->Val); return V; } Type *CmpInst::makeCmpResultType(Type *OpndType) { if (auto *VT = dyn_cast(OpndType)) { // TODO: Cleanup when we have more complete support for // sandboxir::VectorType return OpndType->getContext().getType(llvm::VectorType::get( llvm::Type::getInt1Ty(OpndType->getContext().LLVMCtx), cast(VT->LLVMTy)->getElementCount())); } return Type::getInt1Ty(OpndType->getContext()); } void CmpInst::setPredicate(Predicate P) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&CmpInst::getPredicate, &CmpInst::setPredicate>>(this); cast(Val)->setPredicate(P); } void CmpInst::swapOperands() { if (ICmpInst *IC = dyn_cast(this)) IC->swapOperands(); else cast(this)->swapOperands(); } void ICmpInst::swapOperands() { Ctx.getTracker().emplaceIfTracking(this); cast(Val)->swapOperands(); } void FCmpInst::swapOperands() { Ctx.getTracker().emplaceIfTracking(this); cast(Val)->swapOperands(); } #ifndef NDEBUG void CmpInst::dumpOS(raw_ostream &OS) const { dumpCommonPrefix(OS); dumpCommonSuffix(OS); } void CmpInst::dump() const { dumpOS(dbgs()); dbgs() << "\n"; } #endif // NDEBUG static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) { switch (Opc) { case Instruction::Opcode::ZExt: return static_cast(llvm::Instruction::ZExt); case Instruction::Opcode::SExt: return static_cast(llvm::Instruction::SExt); case Instruction::Opcode::FPToUI: return static_cast(llvm::Instruction::FPToUI); case Instruction::Opcode::FPToSI: return static_cast(llvm::Instruction::FPToSI); case Instruction::Opcode::FPExt: return static_cast(llvm::Instruction::FPExt); case Instruction::Opcode::PtrToInt: return static_cast(llvm::Instruction::PtrToInt); case Instruction::Opcode::IntToPtr: return static_cast(llvm::Instruction::IntToPtr); case Instruction::Opcode::SIToFP: return static_cast(llvm::Instruction::SIToFP); case Instruction::Opcode::UIToFP: return static_cast(llvm::Instruction::UIToFP); case Instruction::Opcode::Trunc: return static_cast(llvm::Instruction::Trunc); case Instruction::Opcode::FPTrunc: return static_cast(llvm::Instruction::FPTrunc); case Instruction::Opcode::BitCast: return static_cast(llvm::Instruction::BitCast); case Instruction::Opcode::AddrSpaceCast: return static_cast( llvm::Instruction::AddrSpaceCast); default: llvm_unreachable("Opcode not suitable for CastInst!"); } } /// \Returns the LLVM opcode that corresponds to \p Opc. static llvm::Instruction::UnaryOps getLLVMUnaryOp(Instruction::Opcode Opc) { switch (Opc) { case Instruction::Opcode::FNeg: return static_cast(llvm::Instruction::FNeg); default: llvm_unreachable("Not a unary op!"); } } CatchSwitchInst *CatchSwitchInst::create(Value *ParentPad, BasicBlock *UnwindBB, unsigned NumHandlers, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::CatchSwitchInst *LLVMCSI = Builder.CreateCatchSwitch( ParentPad->Val, cast(UnwindBB->Val), NumHandlers, Name); return Ctx.createCatchSwitchInst(LLVMCSI); } Value *CatchSwitchInst::getParentPad() const { return Ctx.getValue(cast(Val)->getParentPad()); } void CatchSwitchInst::setParentPad(Value *ParentPad) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setParentPad(ParentPad->Val); } BasicBlock *CatchSwitchInst::getUnwindDest() const { return cast_or_null( Ctx.getValue(cast(Val)->getUnwindDest())); } void CatchSwitchInst::setUnwindDest(BasicBlock *UnwindDest) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setUnwindDest( cast(UnwindDest->Val)); } void CatchSwitchInst::addHandler(BasicBlock *Dest) { Ctx.getTracker().emplaceIfTracking(this); cast(Val)->addHandler( cast(Dest->Val)); } ResumeInst *ResumeInst::create(Value *Exn, InsertPosition Pos, Context &Ctx) { auto &Builder = setInsertPos(Pos); auto *LLVMI = cast(Builder.CreateResume(Exn->Val)); return Ctx.createResumeInst(LLVMI); } Value *ResumeInst::getValue() const { return Ctx.getValue(cast(Val)->getValue()); } SwitchInst *SwitchInst::create(Value *V, BasicBlock *Dest, unsigned NumCases, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::SwitchInst *LLVMSwitch = Builder.CreateSwitch(V->Val, cast(Dest->Val), NumCases); return Ctx.createSwitchInst(LLVMSwitch); } Value *SwitchInst::getCondition() const { return Ctx.getValue(cast(Val)->getCondition()); } void SwitchInst::setCondition(Value *V) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&SwitchInst::getCondition, &SwitchInst::setCondition>>( this); cast(Val)->setCondition(V->Val); } BasicBlock *SwitchInst::getDefaultDest() const { return cast( Ctx.getValue(cast(Val)->getDefaultDest())); } void SwitchInst::setDefaultDest(BasicBlock *DefaultCase) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setDefaultDest( cast(DefaultCase->Val)); } ConstantInt *SwitchInst::findCaseDest(BasicBlock *BB) { auto *LLVMC = cast(Val)->findCaseDest( cast(BB->Val)); return LLVMC != nullptr ? cast(Ctx.getValue(LLVMC)) : nullptr; } void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) { Ctx.getTracker().emplaceIfTracking(this, OnVal); // TODO: Track this! cast(Val)->addCase(cast(OnVal->Val), cast(Dest->Val)); } SwitchInst::CaseIt SwitchInst::removeCase(CaseIt It) { Ctx.getTracker().emplaceIfTracking(this); auto *LLVMSwitch = cast(Val); unsigned CaseNum = It - case_begin(); llvm::SwitchInst::CaseIt LLVMIt(LLVMSwitch, CaseNum); auto LLVMCaseIt = LLVMSwitch->removeCase(LLVMIt); unsigned Num = LLVMCaseIt - LLVMSwitch->case_begin(); return CaseIt(this, Num); } BasicBlock *SwitchInst::getSuccessor(unsigned Idx) const { return cast( Ctx.getValue(cast(Val)->getSuccessor(Idx))); } void SwitchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) { Ctx.getTracker() .emplaceIfTracking>(this, Idx); cast(Val)->setSuccessor( Idx, cast(NewSucc->Val)); } Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *NewLLVMV = Builder.CreateUnOp(getLLVMUnaryOp(Op), OpV->Val, Name); if (auto *NewUnOpV = dyn_cast(NewLLVMV)) { return Ctx.createUnaryOperator(NewUnOpV); } assert(isa(NewLLVMV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewLLVMV)); } Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV, Value *CopyFrom, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto *NewV = create(Op, OpV, Pos, Ctx, Name); if (auto *UnI = dyn_cast(NewV->Val)) UnI->copyIRFlags(CopyFrom->Val); return NewV; } /// \Returns the LLVM opcode that corresponds to \p Opc. static llvm::Instruction::BinaryOps getLLVMBinaryOp(Instruction::Opcode Opc) { switch (Opc) { case Instruction::Opcode::Add: return static_cast(llvm::Instruction::Add); case Instruction::Opcode::FAdd: return static_cast(llvm::Instruction::FAdd); case Instruction::Opcode::Sub: return static_cast(llvm::Instruction::Sub); case Instruction::Opcode::FSub: return static_cast(llvm::Instruction::FSub); case Instruction::Opcode::Mul: return static_cast(llvm::Instruction::Mul); case Instruction::Opcode::FMul: return static_cast(llvm::Instruction::FMul); case Instruction::Opcode::UDiv: return static_cast(llvm::Instruction::UDiv); case Instruction::Opcode::SDiv: return static_cast(llvm::Instruction::SDiv); case Instruction::Opcode::FDiv: return static_cast(llvm::Instruction::FDiv); case Instruction::Opcode::URem: return static_cast(llvm::Instruction::URem); case Instruction::Opcode::SRem: return static_cast(llvm::Instruction::SRem); case Instruction::Opcode::FRem: return static_cast(llvm::Instruction::FRem); case Instruction::Opcode::Shl: return static_cast(llvm::Instruction::Shl); case Instruction::Opcode::LShr: return static_cast(llvm::Instruction::LShr); case Instruction::Opcode::AShr: return static_cast(llvm::Instruction::AShr); case Instruction::Opcode::And: return static_cast(llvm::Instruction::And); case Instruction::Opcode::Or: return static_cast(llvm::Instruction::Or); case Instruction::Opcode::Xor: return static_cast(llvm::Instruction::Xor); default: llvm_unreachable("Not a binary op!"); } } Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateBinOp(getLLVMBinaryOp(Op), LHS->Val, RHS->Val, Name); if (auto *NewBinOp = dyn_cast(NewV)) return Ctx.createBinaryOperator(NewBinOp); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS, Value *RHS, Value *CopyFrom, InsertPosition Pos, Context &Ctx, const Twine &Name) { Value *NewV = create(Op, LHS, RHS, Pos, Ctx, Name); if (auto *NewBO = dyn_cast(NewV)) cast(NewBO->Val)->copyIRFlags(CopyFrom->Val); return NewV; } void PossiblyDisjointInst::setIsDisjoint(bool B) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setIsDisjoint(B); } void AtomicRMWInst::setAlignment(Align Align) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setAlignment(Align); } void AtomicRMWInst::setVolatile(bool V) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setVolatile(V); } void AtomicRMWInst::setOrdering(AtomicOrdering Ordering) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setOrdering(Ordering); } void AtomicRMWInst::setSyncScopeID(SyncScope::ID SSID) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setSyncScopeID(SSID); } Value *AtomicRMWInst::getPointerOperand() { return Ctx.getValue(cast(Val)->getPointerOperand()); } Value *AtomicRMWInst::getValOperand() { return Ctx.getValue(cast(Val)->getValOperand()); } AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, InsertPosition Pos, Context &Ctx, SyncScope::ID SSID, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *LLVMAtomicRMW = Builder.CreateAtomicRMW(Op, Ptr->Val, Val->Val, Align, Ordering, SSID); LLVMAtomicRMW->setName(Name); return Ctx.createAtomicRMWInst(LLVMAtomicRMW); } void AtomicCmpXchgInst::setSyncScopeID(SyncScope::ID SSID) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setSyncScopeID(SSID); } Value *AtomicCmpXchgInst::getPointerOperand() { return Ctx.getValue(cast(Val)->getPointerOperand()); } Value *AtomicCmpXchgInst::getCompareOperand() { return Ctx.getValue(cast(Val)->getCompareOperand()); } Value *AtomicCmpXchgInst::getNewValOperand() { return Ctx.getValue(cast(Val)->getNewValOperand()); } AtomicCmpXchgInst * AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, InsertPosition Pos, Context &Ctx, SyncScope::ID SSID, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *LLVMAtomicCmpXchg = Builder.CreateAtomicCmpXchg(Ptr->Val, Cmp->Val, New->Val, Align, SuccessOrdering, FailureOrdering, SSID); LLVMAtomicCmpXchg->setName(Name); return Ctx.createAtomicCmpXchgInst(LLVMAtomicCmpXchg); } void AtomicCmpXchgInst::setAlignment(Align Align) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setAlignment(Align); } void AtomicCmpXchgInst::setVolatile(bool V) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setVolatile(V); } void AtomicCmpXchgInst::setWeak(bool IsWeak) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setWeak(IsWeak); } void AtomicCmpXchgInst::setSuccessOrdering(AtomicOrdering Ordering) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setSuccessOrdering(Ordering); } void AtomicCmpXchgInst::setFailureOrdering(AtomicOrdering Ordering) { Ctx.getTracker() .emplaceIfTracking>( this); cast(Val)->setFailureOrdering(Ordering); } AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, InsertPosition Pos, Context &Ctx, Value *ArraySize, const Twine &Name) { auto &Builder = setInsertPos(Pos); auto *NewAlloca = Builder.CreateAlloca(Ty->LLVMTy, AddrSpace, ArraySize->Val, Name); return Ctx.createAllocaInst(NewAlloca); } Type *AllocaInst::getAllocatedType() const { return Ctx.getType(cast(Val)->getAllocatedType()); } void AllocaInst::setAllocatedType(Type *Ty) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setAllocatedType(Ty->LLVMTy); } void AllocaInst::setAlignment(Align Align) { Ctx.getTracker() .emplaceIfTracking< GenericSetter<&AllocaInst::getAlign, &AllocaInst::setAlignment>>( this); cast(Val)->setAlignment(Align); } void AllocaInst::setUsedWithInAlloca(bool V) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setUsedWithInAlloca(V); } Value *AllocaInst::getArraySize() { return Ctx.getValue(cast(Val)->getArraySize()); } PointerType *AllocaInst::getType() const { return cast(Ctx.getType(cast(Val)->getType())); } Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand, InsertPosition Pos, Context &Ctx, const Twine &Name) { assert(getLLVMCastOp(Op) && "Opcode not suitable for CastInst!"); auto &Builder = setInsertPos(Pos); auto *NewV = Builder.CreateCast(getLLVMCastOp(Op), Operand->Val, DestTy->LLVMTy, Name); if (auto *NewCI = dyn_cast(NewV)) return Ctx.createCastInst(NewCI); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } bool CastInst::classof(const Value *From) { return From->getSubclassID() == ClassID::Cast; } Type *CastInst::getSrcTy() const { return Ctx.getType(cast(Val)->getSrcTy()); } Type *CastInst::getDestTy() const { return Ctx.getType(cast(Val)->getDestTy()); } void PossiblyNonNegInst::setNonNeg(bool B) { Ctx.getTracker() .emplaceIfTracking>(this); cast(Val)->setNonNeg(B); } Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = Instruction::setInsertPos(Pos); llvm::Value *NewV = Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name); if (auto *NewInsert = dyn_cast(NewV)) return Ctx.createInsertElementInst(NewInsert); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Value *ExtractElementInst::create(Value *Vec, Value *Idx, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateExtractElement(Vec->Val, Idx->Val, Name); if (auto *NewExtract = dyn_cast(NewV)) return Ctx.createExtractElementInst(NewExtract); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name); if (auto *NewShuffle = dyn_cast(NewV)) return Ctx.createShuffleVectorInst(NewShuffle); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef Mask, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name); if (auto *NewShuffle = dyn_cast(NewV)) return Ctx.createShuffleVectorInst(NewShuffle); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } void ShuffleVectorInst::setShuffleMask(ArrayRef Mask) { Ctx.getTracker().emplaceIfTracking(this); cast(Val)->setShuffleMask(Mask); } VectorType *ShuffleVectorInst::getType() const { return cast( Ctx.getType(cast(Val)->getType())); } void ShuffleVectorInst::commute() { Ctx.getTracker().emplaceIfTracking(this); Ctx.getTracker().emplaceIfTracking(getOperandUse(0), getOperandUse(1)); cast(Val)->commute(); } Constant *ShuffleVectorInst::getShuffleMaskForBitcode() const { return Ctx.getOrCreateConstant( cast(Val)->getShuffleMaskForBitcode()); } Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef Mask, Type *ResultTy) { return ResultTy->getContext().getOrCreateConstant( llvm::ShuffleVectorInst::convertShuffleMaskForBitcode(Mask, ResultTy->LLVMTy)); } VectorType *ExtractElementInst::getVectorOperandType() const { return cast(Ctx.getType(getVectorOperand()->getType()->LLVMTy)); } Value *ExtractValueInst::create(Value *Agg, ArrayRef Idxs, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateExtractValue(Agg->Val, Idxs, Name); if (auto *NewExtractValueInst = dyn_cast(NewV)) return Ctx.createExtractValueInst(NewExtractValueInst); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } Type *ExtractValueInst::getIndexedType(Type *Agg, ArrayRef Idxs) { auto *LLVMTy = llvm::ExtractValueInst::getIndexedType(Agg->LLVMTy, Idxs); return Agg->getContext().getType(LLVMTy); } Value *InsertValueInst::create(Value *Agg, Value *Val, ArrayRef Idxs, InsertPosition Pos, Context &Ctx, const Twine &Name) { auto &Builder = setInsertPos(Pos); llvm::Value *NewV = Builder.CreateInsertValue(Agg->Val, Val->Val, Idxs, Name); if (auto *NewInsertValueInst = dyn_cast(NewV)) return Ctx.createInsertValueInst(NewInsertValueInst); assert(isa(NewV) && "Expected constant"); return Ctx.getOrCreateConstant(cast(NewV)); } ConstantTokenNone *ConstantTokenNone::get(Context &Ctx) { auto *LLVMC = llvm::ConstantTokenNone::get(Ctx.LLVMCtx); return cast(Ctx.getOrCreateConstant(LLVMC)); } } // namespace llvm::sandboxir