//===- SandboxIR.h ----------------------------------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // Sandbox IR is a lightweight overlay transactional IR on top of LLVM IR. // Features: // - You can save/rollback the state of the IR at any time. // - Any changes made to Sandbox IR will automatically update the underlying // LLVM IR so both IRs are always in sync. // - Feels like LLVM IR, similar API. // // SandboxIR forms a class hierarchy that resembles that of LLVM IR // but is in the `sandboxir` namespace: // // namespace sandboxir { // // Value -+- Argument // | // +- BasicBlock // | // +- User ------+- Constant ------ Function // | // +- Instruction -+- BinaryOperator // | // +- BranchInst // | // +- CastInst --------+- AddrSpaceCastInst // | | // | +- BitCastInst // | | // | +- FPExtInst // | | // | +- FPToSIInst // | | // | +- FPToUIInst // | | // | +- FPTruncInst // | | // | +- IntToPtrInst // | | // | +- PtrToIntInst // | | // | +- SExtInst // | | // | +- SIToFPInst // | | // | +- TruncInst // | | // | +- UIToFPInst // | | // | +- ZExtInst // | // +- CallBase -----------+- CallBrInst // | | // +- CmpInst +- CallInst // | | // +- ExtractElementInst +- InvokeInst // | // +- GetElementPtrInst // | // +- InsertElementInst // | // +- OpaqueInst // | // +- PHINode // | // +- ReturnInst // | // +- SelectInst // | // +- ShuffleVectorInst // | // +- StoreInst // | // +- UnaryInstruction -+- LoadInst // | | // | +- CastInst // | // +- UnaryOperator // | // +- UnreachableInst // // Use // // } // namespace sandboxir // #ifndef LLVM_SANDBOXIR_SANDBOXIR_H #define LLVM_SANDBOXIR_SANDBOXIR_H #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/SandboxIR/Tracker.h" #include "llvm/SandboxIR/Use.h" #include "llvm/Support/raw_ostream.h" #include namespace llvm { namespace sandboxir { class BasicBlock; class ConstantInt; class Context; class Function; class Instruction; class SelectInst; class ExtractElementInst; class InsertElementInst; class ShuffleVectorInst; class BranchInst; class UnaryInstruction; class LoadInst; class ReturnInst; class StoreInst; class User; class UnreachableInst; class Value; class CallBase; class CallInst; class InvokeInst; class CallBrInst; class FuncletPadInst; class CatchPadInst; class CleanupPadInst; class CatchReturnInst; class GetElementPtrInst; class CastInst; class PtrToIntInst; class BitCastInst; class AllocaInst; class CatchSwitchInst; class SwitchInst; class UnaryOperator; class BinaryOperator; class AtomicRMWInst; class AtomicCmpXchgInst; /// Iterator for the `Use` edges of a User's operands. /// \Returns the operand `Use` when dereferenced. class OperandUseIterator { sandboxir::Use Use; /// Don't let the user create a non-empty OperandUseIterator. OperandUseIterator(const class Use &Use) : Use(Use) {} friend class User; // For constructor #define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; // For constructor #include "llvm/SandboxIR/SandboxIRValues.def" public: using difference_type = std::ptrdiff_t; using value_type = sandboxir::Use; using pointer = value_type *; using reference = value_type &; using iterator_category = std::input_iterator_tag; OperandUseIterator() = default; value_type operator*() const; OperandUseIterator &operator++(); OperandUseIterator operator++(int) { auto Copy = *this; this->operator++(); return Copy; } bool operator==(const OperandUseIterator &Other) const { return Use == Other.Use; } bool operator!=(const OperandUseIterator &Other) const { return !(*this == Other); } OperandUseIterator operator+(unsigned Num) const; OperandUseIterator operator-(unsigned Num) const; int operator-(const OperandUseIterator &Other) const; }; /// Iterator for the `Use` edges of a Value's users. /// \Returns a `Use` when dereferenced. class UserUseIterator { sandboxir::Use Use; /// Don't let the user create a non-empty UserUseIterator. UserUseIterator(const class Use &Use) : Use(Use) {} friend class Value; // For constructor public: using difference_type = std::ptrdiff_t; using value_type = sandboxir::Use; using pointer = value_type *; using reference = value_type &; using iterator_category = std::input_iterator_tag; UserUseIterator() = default; value_type operator*() const { return Use; } UserUseIterator &operator++(); bool operator==(const UserUseIterator &Other) const { return Use == Other.Use; } bool operator!=(const UserUseIterator &Other) const { return !(*this == Other); } const sandboxir::Use &getUse() const { return Use; } }; /// A SandboxIR Value has users. This is the base class. class Value { public: enum class ClassID : unsigned { #define DEF_VALUE(ID, CLASS) ID, #define DEF_USER(ID, CLASS) ID, #define DEF_INSTR(ID, OPC, CLASS) ID, #include "llvm/SandboxIR/SandboxIRValues.def" }; protected: static const char *getSubclassIDStr(ClassID ID) { switch (ID) { #define DEF_VALUE(ID, CLASS) \ case ClassID::ID: \ return #ID; #define DEF_USER(ID, CLASS) \ case ClassID::ID: \ return #ID; #define DEF_INSTR(ID, OPC, CLASS) \ case ClassID::ID: \ return #ID; #include "llvm/SandboxIR/SandboxIRValues.def" } llvm_unreachable("Unimplemented ID"); } /// For isa/dyn_cast. ClassID SubclassID; #ifndef NDEBUG /// A unique ID used for forming the name (used for debugging). unsigned UID; #endif /// The LLVM Value that corresponds to this SandboxIR Value. /// NOTE: Some sandboxir Instructions, like Packs, may include more than one /// value and in these cases `Val` points to the last instruction in program /// order. llvm::Value *Val = nullptr; friend class Context; // For getting `Val`. friend class User; // For getting `Val`. friend class Use; // For getting `Val`. friend class SelectInst; // For getting `Val`. friend class ExtractElementInst; // For getting `Val`. friend class InsertElementInst; // For getting `Val`. friend class ShuffleVectorInst; // For getting `Val`. friend class BranchInst; // For getting `Val`. friend class LoadInst; // For getting `Val`. friend class StoreInst; // For getting `Val`. friend class ReturnInst; // For getting `Val`. friend class CallBase; // For getting `Val`. friend class CallInst; // For getting `Val`. friend class InvokeInst; // For getting `Val`. friend class CallBrInst; // For getting `Val`. friend class FuncletPadInst; // For getting `Val`. friend class CatchPadInst; // For getting `Val`. friend class CleanupPadInst; // For getting `Val`. friend class CatchReturnInst; // For getting `Val`. friend class GetElementPtrInst; // For getting `Val`. friend class CatchSwitchInst; // For getting `Val`. friend class SwitchInst; // For getting `Val`. friend class UnaryOperator; // For getting `Val`. friend class BinaryOperator; // For getting `Val`. friend class AtomicRMWInst; // For getting `Val`. friend class AtomicCmpXchgInst; // For getting `Val`. friend class AllocaInst; // For getting `Val`. friend class CastInst; // For getting `Val`. friend class PHINode; // For getting `Val`. friend class UnreachableInst; // For getting `Val`. friend class CatchSwitchAddHandler; // For `Val`. /// All values point to the context. Context &Ctx; // This is used by eraseFromParent(). void clearValue() { Val = nullptr; } template friend class LLVMOpUserItToSBTy; Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx); /// Disable copies. Value(const Value &) = delete; Value &operator=(const Value &) = delete; public: virtual ~Value() = default; ClassID getSubclassID() const { return SubclassID; } using use_iterator = UserUseIterator; using const_use_iterator = UserUseIterator; use_iterator use_begin(); const_use_iterator use_begin() const { return const_cast(this)->use_begin(); } use_iterator use_end() { return use_iterator(Use(nullptr, nullptr, Ctx)); } const_use_iterator use_end() const { return const_cast(this)->use_end(); } iterator_range uses() { return make_range(use_begin(), use_end()); } iterator_range uses() const { return make_range(use_begin(), use_end()); } /// Helper for mapped_iterator. struct UseToUser { User *operator()(const Use &Use) const { return &*Use.getUser(); } }; using user_iterator = mapped_iterator; using const_user_iterator = user_iterator; user_iterator user_begin(); user_iterator user_end() { return user_iterator(Use(nullptr, nullptr, Ctx), UseToUser()); } const_user_iterator user_begin() const { return const_cast(this)->user_begin(); } const_user_iterator user_end() const { return const_cast(this)->user_end(); } iterator_range users() { return make_range(user_begin(), user_end()); } iterator_range users() const { return make_range(user_begin(), user_end()); } /// \Returns the number of user edges (not necessarily to unique users). /// WARNING: This is a linear-time operation. unsigned getNumUses() const; /// Return true if this value has N uses or more. /// This is logically equivalent to getNumUses() >= N. /// WARNING: This can be expensive, as it is linear to the number of users. bool hasNUsesOrMore(unsigned Num) const { unsigned Cnt = 0; for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) { if (++Cnt >= Num) return true; } return false; } /// Return true if this Value has exactly N uses. bool hasNUses(unsigned Num) const { unsigned Cnt = 0; for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) { if (++Cnt > Num) return false; } return Cnt == Num; } Type *getType() const { return Val->getType(); } Context &getContext() const { return Ctx; } void replaceUsesWithIf(Value *OtherV, llvm::function_ref ShouldReplace); void replaceAllUsesWith(Value *Other); /// \Returns the LLVM IR name of the bottom-most LLVM value. StringRef getName() const { return Val->getName(); } #ifndef NDEBUG /// Should crash if there is something wrong with the instruction. virtual void verify() const = 0; /// Returns the unique id in the form 'SB.' like 'SB1.' std::string getUid() const; virtual void dumpCommonHeader(raw_ostream &OS) const; void dumpCommonFooter(raw_ostream &OS) const; void dumpCommonPrefix(raw_ostream &OS) const; void dumpCommonSuffix(raw_ostream &OS) const; void printAsOperandCommon(raw_ostream &OS) const; friend raw_ostream &operator<<(raw_ostream &OS, const sandboxir::Value &V) { V.dumpOS(OS); return OS; } virtual void dumpOS(raw_ostream &OS) const = 0; LLVM_DUMP_METHOD void dump() const; #endif }; /// Argument of a sandboxir::Function. class Argument : public sandboxir::Value { Argument(llvm::Argument *Arg, sandboxir::Context &Ctx) : sandboxir::Value(ClassID::Argument, Arg, Ctx) {} friend class Context; // For constructor. public: static bool classof(const sandboxir::Value *From) { return From->getSubclassID() == ClassID::Argument; } #ifndef NDEBUG void verify() const final { assert(isa(Val) && "Expected Argument!"); } void printAsOperand(raw_ostream &OS) const; void dumpOS(raw_ostream &OS) const final; #endif }; /// A sandboxir::User has operands. class User : public Value { protected: User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {} /// \Returns the Use edge that corresponds to \p OpIdx. /// Note: This is the default implementation that works for instructions that /// match the underlying LLVM instruction. All others should use a different /// implementation. Use getOperandUseDefault(unsigned OpIdx, bool Verify) const; /// \Returns the Use for the \p OpIdx'th operand. This is virtual to allow /// instructions to deviate from the LLVM IR operands, which is a requirement /// for sandboxir Instructions that consist of more than one LLVM Instruction. virtual Use getOperandUseInternal(unsigned OpIdx, bool Verify) const = 0; friend class OperandUseIterator; // for getOperandUseInternal() /// The default implementation works only for single-LLVMIR-instruction /// Users and only if they match exactly the LLVM instruction. unsigned getUseOperandNoDefault(const Use &Use) const { return Use.LLVMUse->getOperandNo(); } /// \Returns the operand index of \p Use. virtual unsigned getUseOperandNo(const Use &Use) const = 0; friend unsigned Use::getOperandNo() const; // For getUseOperandNo() void swapOperandsInternal(unsigned OpIdxA, unsigned OpIdxB) { assert(OpIdxA < getNumOperands() && "OpIdxA out of bounds!"); assert(OpIdxB < getNumOperands() && "OpIdxB out of bounds!"); auto UseA = getOperandUse(OpIdxA); auto UseB = getOperandUse(OpIdxB); UseA.swap(UseB); } #ifndef NDEBUG void verifyUserOfLLVMUse(const llvm::Use &Use) const; #endif // NDEBUG public: /// For isa/dyn_cast. static bool classof(const Value *From); using op_iterator = OperandUseIterator; using const_op_iterator = OperandUseIterator; using op_range = iterator_range; using const_op_range = iterator_range; virtual op_iterator op_begin() { assert(isa(Val) && "Expect User value!"); return op_iterator(getOperandUseInternal(0, /*Verify=*/false)); } virtual op_iterator op_end() { assert(isa(Val) && "Expect User value!"); return op_iterator( getOperandUseInternal(getNumOperands(), /*Verify=*/false)); } virtual const_op_iterator op_begin() const { return const_cast(this)->op_begin(); } virtual const_op_iterator op_end() const { return const_cast(this)->op_end(); } op_range operands() { return make_range(op_begin(), op_end()); } const_op_range operands() const { return make_range(op_begin(), op_end()); } Value *getOperand(unsigned OpIdx) const { return getOperandUse(OpIdx).get(); } /// \Returns the operand edge for \p OpIdx. NOTE: This should also work for /// OpIdx == getNumOperands(), which is used for op_end(). Use getOperandUse(unsigned OpIdx) const { return getOperandUseInternal(OpIdx, /*Verify=*/true); } virtual unsigned getNumOperands() const { return isa(Val) ? cast(Val)->getNumOperands() : 0; } virtual void setOperand(unsigned OperandIdx, Value *Operand); /// Replaces any operands that match \p FromV with \p ToV. Returns whether any /// operands were replaced. bool replaceUsesOfWith(Value *FromV, Value *ToV); #ifndef NDEBUG void verify() const override { assert(isa(Val) && "Expected User!"); } void dumpCommonHeader(raw_ostream &OS) const final; void dumpOS(raw_ostream &OS) const override { // TODO: Remove this tmp implementation once we get the Instruction classes. } #endif }; class Constant : public sandboxir::User { Constant(llvm::Constant *C, sandboxir::Context &SBCtx) : sandboxir::User(ClassID::Constant, C, SBCtx) {} Constant(ClassID ID, llvm::Constant *C, sandboxir::Context &SBCtx) : sandboxir::User(ID, C, SBCtx) {} friend class ConstantInt; // For constructor. friend class Function; // For constructor friend class Context; // For constructor. Use getOperandUseInternal(unsigned OpIdx, bool Verify) const override { return getOperandUseDefault(OpIdx, Verify); } public: /// For isa/dyn_cast. static bool classof(const sandboxir::Value *From) { return From->getSubclassID() == ClassID::Constant || From->getSubclassID() == ClassID::ConstantInt || From->getSubclassID() == ClassID::Function; } sandboxir::Context &getParent() const { return getContext(); } unsigned getUseOperandNo(const Use &Use) const override { return getUseOperandNoDefault(Use); } #ifndef NDEBUG void verify() const override { assert(isa(Val) && "Expected Constant!"); } void dumpOS(raw_ostream &OS) const override; #endif }; class ConstantInt : public Constant { ConstantInt(llvm::ConstantInt *C, sandboxir::Context &Ctx) : Constant(ClassID::ConstantInt, C, Ctx) {} friend class Context; // For constructor. Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { llvm_unreachable("ConstantInt has no operands!"); } public: /// If Ty is a vector type, return a Constant with a splat of the given /// value. Otherwise return a ConstantInt for the given value. static ConstantInt *get(Type *Ty, uint64_t V, Context &Ctx, bool IsSigned = false); // TODO: Implement missing functions. /// For isa/dyn_cast. static bool classof(const sandboxir::Value *From) { return From->getSubclassID() == ClassID::ConstantInt; } unsigned getUseOperandNo(const Use &Use) const override { llvm_unreachable("ConstantInt has no operands!"); } #ifndef NDEBUG void verify() const override { assert(isa(Val) && "Expected a ConstantInst!"); } void dumpOS(raw_ostream &OS) const override { dumpCommonPrefix(OS); dumpCommonSuffix(OS); } #endif }; /// Iterator for `Instruction`s in a `BasicBlock. /// \Returns an sandboxir::Instruction & when derereferenced. class BBIterator { public: using difference_type = std::ptrdiff_t; using value_type = Instruction; using pointer = value_type *; using reference = value_type &; using iterator_category = std::bidirectional_iterator_tag; private: llvm::BasicBlock *BB; llvm::BasicBlock::iterator It; Context *Ctx; pointer getInstr(llvm::BasicBlock::iterator It) const; public: BBIterator() : BB(nullptr), Ctx(nullptr) {} BBIterator(llvm::BasicBlock *BB, llvm::BasicBlock::iterator It, Context *Ctx) : BB(BB), It(It), Ctx(Ctx) {} reference operator*() const { return *getInstr(It); } BBIterator &operator++(); BBIterator operator++(int) { auto Copy = *this; ++*this; return Copy; } BBIterator &operator--(); BBIterator operator--(int) { auto Copy = *this; --*this; return Copy; } bool operator==(const BBIterator &Other) const { assert(Ctx == Other.Ctx && "BBIterators in different context!"); return It == Other.It; } bool operator!=(const BBIterator &Other) const { return !(*this == Other); } /// \Returns the SBInstruction that corresponds to this iterator, or null if /// the instruction is not found in the IR-to-SandboxIR tables. pointer get() const { return getInstr(It); } }; /// Contains a list of sandboxir::Instruction's. class BasicBlock : public Value { /// Builds a graph that contains all values in \p BB in their original form /// i.e., no vectorization is taking place here. void buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB); friend class Context; // For `buildBasicBlockFromIR` friend class Instruction; // For LLVM Val. BasicBlock(llvm::BasicBlock *BB, Context &SBCtx) : Value(ClassID::Block, BB, SBCtx) { buildBasicBlockFromLLVMIR(BB); } public: ~BasicBlock() = default; /// For isa/dyn_cast. static bool classof(const Value *From) { return From->getSubclassID() == Value::ClassID::Block; } Function *getParent() const; using iterator = BBIterator; iterator begin() const; iterator end() const { auto *BB = cast(Val); return iterator(BB, BB->end(), &Ctx); } std::reverse_iterator rbegin() const { return std::make_reverse_iterator(end()); } std::reverse_iterator rend() const { return std::make_reverse_iterator(begin()); } Context &getContext() const { return Ctx; } Instruction *getTerminator() const; bool empty() const { return begin() == end(); } Instruction &front() const; Instruction &back() const; #ifndef NDEBUG void verify() const final { assert(isa(Val) && "Expected BasicBlock!"); } void dumpOS(raw_ostream &OS) const final; #endif }; /// A sandboxir::User with operands, opcode and linked with previous/next /// instructions in an instruction list. class Instruction : public sandboxir::User { public: enum class Opcode { #define OP(OPC) OPC, #define OPCODES(...) __VA_ARGS__ #define DEF_INSTR(ID, OPC, CLASS) OPC #include "llvm/SandboxIR/SandboxIRValues.def" }; protected: Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I, sandboxir::Context &SBCtx) : sandboxir::User(ID, I, SBCtx), Opc(Opc) {} Opcode Opc; /// A SandboxIR Instruction may map to multiple LLVM IR Instruction. This /// returns its topmost LLVM IR instruction. llvm::Instruction *getTopmostLLVMInstruction() const; friend class SelectInst; // For getTopmostLLVMInstruction(). friend class ExtractElementInst; // For getTopmostLLVMInstruction(). friend class InsertElementInst; // For getTopmostLLVMInstruction(). friend class ShuffleVectorInst; // For getTopmostLLVMInstruction(). friend class BranchInst; // For getTopmostLLVMInstruction(). friend class LoadInst; // For getTopmostLLVMInstruction(). friend class StoreInst; // For getTopmostLLVMInstruction(). friend class ReturnInst; // For getTopmostLLVMInstruction(). friend class CallInst; // For getTopmostLLVMInstruction(). friend class InvokeInst; // For getTopmostLLVMInstruction(). friend class CallBrInst; // For getTopmostLLVMInstruction(). friend class CatchPadInst; // For getTopmostLLVMInstruction(). friend class CleanupPadInst; // For getTopmostLLVMInstruction(). friend class CatchReturnInst; // For getTopmostLLVMInstruction(). friend class GetElementPtrInst; // For getTopmostLLVMInstruction(). friend class CatchSwitchInst; // For getTopmostLLVMInstruction(). friend class SwitchInst; // For getTopmostLLVMInstruction(). friend class UnaryOperator; // For getTopmostLLVMInstruction(). friend class BinaryOperator; // For getTopmostLLVMInstruction(). friend class AtomicRMWInst; // For getTopmostLLVMInstruction(). friend class AtomicCmpXchgInst; // For getTopmostLLVMInstruction(). friend class AllocaInst; // For getTopmostLLVMInstruction(). friend class CastInst; // For getTopmostLLVMInstruction(). friend class PHINode; // For getTopmostLLVMInstruction(). friend class UnreachableInst; // For getTopmostLLVMInstruction(). /// \Returns the LLVM IR Instructions that this SandboxIR maps to in program /// order. virtual SmallVector getLLVMInstrs() const = 0; friend class EraseFromParent; // For getLLVMInstrs(). public: static const char *getOpcodeName(Opcode Opc); /// This is used by BasicBlock::iterator. virtual unsigned getNumOfIRInstrs() const = 0; /// \Returns a BasicBlock::iterator for this Instruction. BBIterator getIterator() const; /// \Returns the next sandboxir::Instruction in the block, or nullptr if at /// the end of the block. Instruction *getNextNode() const; /// \Returns the previous sandboxir::Instruction in the block, or nullptr if /// at the beginning of the block. Instruction *getPrevNode() const; /// \Returns this Instruction's opcode. Note that SandboxIR has its own opcode /// state to allow for new SandboxIR-specific instructions. Opcode getOpcode() const { return Opc; } /// Detach this from its parent BasicBlock without deleting it. void removeFromParent(); /// Detach this Value from its parent and delete it. void eraseFromParent(); /// Insert this detached instruction before \p BeforeI. void insertBefore(Instruction *BeforeI); /// Insert this detached instruction after \p AfterI. void insertAfter(Instruction *AfterI); /// Insert this detached instruction into \p BB at \p WhereIt. void insertInto(BasicBlock *BB, const BBIterator &WhereIt); /// Move this instruction to \p WhereIt. void moveBefore(BasicBlock &BB, const BBIterator &WhereIt); /// Move this instruction before \p Before. void moveBefore(Instruction *Before) { moveBefore(*Before->getParent(), Before->getIterator()); } /// Move this instruction after \p After. void moveAfter(Instruction *After) { moveBefore(*After->getParent(), std::next(After->getIterator())); } /// \Returns the BasicBlock containing this Instruction, or null if it is /// detached. BasicBlock *getParent() const; /// For isa/dyn_cast. static bool classof(const sandboxir::Value *From); /// Determine whether the no signed wrap flag is set. bool hasNoUnsignedWrap() const { return cast(Val)->hasNoUnsignedWrap(); } /// Set or clear the nuw flag on this instruction, which must be an operator /// which supports this flag. See LangRef.html for the meaning of this flag. void setHasNoUnsignedWrap(bool B = true); /// Determine whether the no signed wrap flag is set. bool hasNoSignedWrap() const { return cast(Val)->hasNoSignedWrap(); } /// Set or clear the nsw flag on this instruction, which must be an operator /// which supports this flag. See LangRef.html for the meaning of this flag. void setHasNoSignedWrap(bool B = true); /// Determine whether all fast-math-flags are set. bool isFast() const { return cast(Val)->isFast(); } /// Set or clear all fast-math-flags on this instruction, which must be an /// operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setFast(bool B); /// Determine whether the allow-reassociation flag is set. bool hasAllowReassoc() const { return cast(Val)->hasAllowReassoc(); } /// Set or clear the reassociation flag on this instruction, which must be /// an operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasAllowReassoc(bool B); /// Determine whether the exact flag is set. bool isExact() const { return cast(Val)->isExact(); } /// Set or clear the exact flag on this instruction, which must be an operator /// which supports this flag. See LangRef.html for the meaning of this flag. void setIsExact(bool B = true); /// Determine whether the no-NaNs flag is set. bool hasNoNaNs() const { return cast(Val)->hasNoNaNs(); } /// Set or clear the no-nans flag on this instruction, which must be an /// operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasNoNaNs(bool B); /// Determine whether the no-infs flag is set. bool hasNoInfs() const { return cast(Val)->hasNoInfs(); } /// Set or clear the no-infs flag on this instruction, which must be an /// operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasNoInfs(bool B); /// Determine whether the no-signed-zeros flag is set. bool hasNoSignedZeros() const { return cast(Val)->hasNoSignedZeros(); } /// Set or clear the no-signed-zeros flag on this instruction, which must be /// an operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasNoSignedZeros(bool B); /// Determine whether the allow-reciprocal flag is set. bool hasAllowReciprocal() const { return cast(Val)->hasAllowReciprocal(); } /// Set or clear the allow-reciprocal flag on this instruction, which must be /// an operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasAllowReciprocal(bool B); /// Determine whether the allow-contract flag is set. bool hasAllowContract() const { return cast(Val)->hasAllowContract(); } /// Set or clear the allow-contract flag on this instruction, which must be /// an operator which supports this flag. See LangRef.html for the meaning of /// this flag. void setHasAllowContract(bool B); /// Determine whether the approximate-math-functions flag is set. bool hasApproxFunc() const { return cast(Val)->hasApproxFunc(); } /// Set or clear the approximate-math-functions flag on this instruction, /// which must be an operator which supports this flag. See LangRef.html for /// the meaning of this flag. void setHasApproxFunc(bool B); /// Convenience function for getting all the fast-math flags, which must be an /// operator which supports these flags. See LangRef.html for the meaning of /// these flags. FastMathFlags getFastMathFlags() const { return cast(Val)->getFastMathFlags(); } /// Convenience function for setting multiple fast-math flags on this /// instruction, which must be an operator which supports these flags. See /// LangRef.html for the meaning of these flags. void setFastMathFlags(FastMathFlags FMF); /// Convenience function for transferring all fast-math flag values to this /// instruction, which must be an operator which supports these flags. See /// LangRef.html for the meaning of these flags. void copyFastMathFlags(FastMathFlags FMF); #ifndef NDEBUG void dumpOS(raw_ostream &OS) const override; #endif }; /// Instructions that contain a single LLVM Instruction can inherit from this. template class SingleLLVMInstructionImpl : public Instruction { SingleLLVMInstructionImpl(ClassID ID, Opcode Opc, llvm::Instruction *I, sandboxir::Context &SBCtx) : Instruction(ID, Opc, I, SBCtx) {} // All instructions are friends with this so they can call the constructor. #define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; #include "llvm/SandboxIR/SandboxIRValues.def" friend class UnaryInstruction; friend class CallBase; friend class FuncletPadInst; Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { return getOperandUseDefault(OpIdx, Verify); } SmallVector getLLVMInstrs() const final { return {cast(Val)}; } public: unsigned getUseOperandNo(const Use &Use) const final { return getUseOperandNoDefault(Use); } unsigned getNumOfIRInstrs() const final { return 1u; } #ifndef NDEBUG void verify() const final { assert(isa(Val) && "Expected LLVMT!"); } void dumpOS(raw_ostream &OS) const override { dumpCommonPrefix(OS); dumpCommonSuffix(OS); } #endif }; class SelectInst : public SingleLLVMInstructionImpl { /// Use Context::createSelectInst(). Don't call the /// constructor directly. SelectInst(llvm::SelectInst *CI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Select, Opcode::Select, CI, Ctx) {} friend Context; // for SelectInst() static Value *createCommon(Value *Cond, Value *True, Value *False, const Twine &Name, IRBuilder<> &Builder, Context &Ctx); public: static Value *create(Value *Cond, Value *True, Value *False, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Value *Cond, Value *True, Value *False, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); Value *getCondition() { return getOperand(0); } Value *getTrueValue() { return getOperand(1); } Value *getFalseValue() { return getOperand(2); } void setCondition(Value *New) { setOperand(0, New); } void setTrueValue(Value *New) { setOperand(1, New); } void setFalseValue(Value *New) { setOperand(2, New); } void swapValues() { cast(Val)->swapValues(); } /// For isa/dyn_cast. static bool classof(const Value *From); }; class InsertElementInst final : public SingleLLVMInstructionImpl { /// Use Context::createInsertElementInst() instead. InsertElementInst(llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::InsertElement, Opcode::InsertElement, I, Ctx) {} friend class Context; // For accessing the constructor in create*() public: static Value *create(Value *Vec, Value *NewElt, Value *Idx, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Value *Vec, Value *NewElt, Value *Idx, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::InsertElement; } static bool isValidOperands(const Value *Vec, const Value *NewElt, const Value *Idx) { return llvm::InsertElementInst::isValidOperands(Vec->Val, NewElt->Val, Idx->Val); } }; class ExtractElementInst final : public SingleLLVMInstructionImpl { /// Use Context::createExtractElementInst() instead. ExtractElementInst(llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::ExtractElement, Opcode::ExtractElement, I, Ctx) {} friend class Context; // For accessing the constructor in // create*() public: static Value *create(Value *Vec, Value *Idx, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Value *Vec, Value *Idx, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::ExtractElement; } static bool isValidOperands(const Value *Vec, const Value *Idx) { return llvm::ExtractElementInst::isValidOperands(Vec->Val, Idx->Val); } Value *getVectorOperand() { return getOperand(0); } Value *getIndexOperand() { return getOperand(1); } const Value *getVectorOperand() const { return getOperand(0); } const Value *getIndexOperand() const { return getOperand(1); } VectorType *getVectorOperandType() const { return cast(getVectorOperand()->getType()); } }; class ShuffleVectorInst final : public SingleLLVMInstructionImpl { /// Use Context::createShuffleVectorInst() instead. ShuffleVectorInst(llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::ShuffleVector, Opcode::ShuffleVector, I, Ctx) {} friend class Context; // For accessing the constructor in create*() public: static Value *create(Value *V1, Value *V2, Value *Mask, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Value *V1, Value *V2, Value *Mask, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static Value *create(Value *V1, Value *V2, ArrayRef Mask, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Value *V1, Value *V2, ArrayRef Mask, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::ShuffleVector; } /// Swap the operands and adjust the mask to preserve the semantics of the /// instruction. void commute() { cast(Val)->commute(); } /// Return true if a shufflevector instruction can be formed with the /// specified operands. static bool isValidOperands(const Value *V1, const Value *V2, const Value *Mask) { return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask->Val); } static bool isValidOperands(const Value *V1, const Value *V2, ArrayRef Mask) { return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask); } /// Overload to return most specific vector type. VectorType *getType() const { return cast(Val)->getType(); } /// Return the shuffle mask value of this instruction for the given element /// index. Return PoisonMaskElem if the element is undef. int getMaskValue(unsigned Elt) const { return cast(Val)->getMaskValue(Elt); } /// Convert the input shuffle mask operand to a vector of integers. Undefined /// elements of the mask are returned as PoisonMaskElem. static void getShuffleMask(const Constant *Mask, SmallVectorImpl &Result) { llvm::ShuffleVectorInst::getShuffleMask(cast(Mask->Val), Result); } /// Return the mask for this instruction as a vector of integers. Undefined /// elements of the mask are returned as PoisonMaskElem. void getShuffleMask(SmallVectorImpl &Result) const { cast(Val)->getShuffleMask(Result); } /// Return the mask for this instruction, for use in bitcode. Constant *getShuffleMaskForBitcode() const; static Constant *convertShuffleMaskForBitcode(ArrayRef Mask, Type *ResultTy, Context &Ctx); void setShuffleMask(ArrayRef Mask); ArrayRef getShuffleMask() const { return cast(Val)->getShuffleMask(); } /// Return true if this shuffle returns a vector with a different number of /// elements than its source vectors. /// Examples: shufflevector <4 x n> A, <4 x n> B, <1,2,3> /// shufflevector <4 x n> A, <4 x n> B, <1,2,3,4,5> bool changesLength() const { return cast(Val)->changesLength(); } /// Return true if this shuffle returns a vector with a greater number of /// elements than its source vectors. /// Example: shufflevector <2 x n> A, <2 x n> B, <1,2,3> bool increasesLength() const { return cast(Val)->increasesLength(); } /// Return true if this shuffle mask chooses elements from exactly one source /// vector. /// Example: <7,5,undef,7> /// This assumes that vector operands (of length \p NumSrcElts) are the same /// length as the mask. static bool isSingleSourceMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isSingleSourceMask(Mask, NumSrcElts); } static bool isSingleSourceMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isSingleSourceMask( cast(Mask->Val), NumSrcElts); } /// Return true if this shuffle chooses elements from exactly one source /// vector without changing the length of that vector. /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3> bool isSingleSource() const { return cast(Val)->isSingleSource(); } /// Return true if this shuffle mask chooses elements from exactly one source /// vector without lane crossings. A shuffle using this mask is not /// necessarily a no-op because it may change the number of elements from its /// input vectors or it may provide demanded bits knowledge via undef lanes. /// Example: static bool isIdentityMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts); } static bool isIdentityMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isIdentityMask( cast(Mask->Val), NumSrcElts); } /// Return true if this shuffle chooses elements from exactly one source /// vector without lane crossings and does not change the number of elements /// from its input vectors. /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef> bool isIdentity() const { return cast(Val)->isIdentity(); } /// Return true if this shuffle lengthens exactly one source vector with /// undefs in the high elements. bool isIdentityWithPadding() const { return cast(Val)->isIdentityWithPadding(); } /// Return true if this shuffle extracts the first N elements of exactly one /// source vector. bool isIdentityWithExtract() const { return cast(Val)->isIdentityWithExtract(); } /// Return true if this shuffle concatenates its 2 source vectors. This /// returns false if either input is undefined. In that case, the shuffle is /// is better classified as an identity with padding operation. bool isConcat() const { return cast(Val)->isConcat(); } /// Return true if this shuffle mask chooses elements from its source vectors /// without lane crossings. A shuffle using this mask would be /// equivalent to a vector select with a constant condition operand. /// Example: <4,1,6,undef> /// This returns false if the mask does not choose from both input vectors. /// In that case, the shuffle is better classified as an identity shuffle. /// This assumes that vector operands are the same length as the mask /// (a length-changing shuffle can never be equivalent to a vector select). static bool isSelectMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isSelectMask(Mask, NumSrcElts); } static bool isSelectMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isSelectMask( cast(Mask->Val), NumSrcElts); } /// Return true if this shuffle chooses elements from its source vectors /// without lane crossings and all operands have the same number of elements. /// In other words, this shuffle is equivalent to a vector select with a /// constant condition operand. /// Example: shufflevector <4 x n> A, <4 x n> B, /// This returns false if the mask does not choose from both input vectors. /// In that case, the shuffle is better classified as an identity shuffle. bool isSelect() const { return cast(Val)->isSelect(); } /// Return true if this shuffle mask swaps the order of elements from exactly /// one source vector. /// Example: <7,6,undef,4> /// This assumes that vector operands (of length \p NumSrcElts) are the same /// length as the mask. static bool isReverseMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isReverseMask(Mask, NumSrcElts); } static bool isReverseMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isReverseMask( cast(Mask->Val), NumSrcElts); } /// Return true if this shuffle swaps the order of elements from exactly /// one source vector. /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef> bool isReverse() const { return cast(Val)->isReverse(); } /// Return true if this shuffle mask chooses all elements with the same value /// as the first element of exactly one source vector. /// Example: <4,undef,undef,4> /// This assumes that vector operands (of length \p NumSrcElts) are the same /// length as the mask. static bool isZeroEltSplatMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isZeroEltSplatMask(Mask, NumSrcElts); } static bool isZeroEltSplatMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isZeroEltSplatMask( cast(Mask->Val), NumSrcElts); } /// Return true if all elements of this shuffle are the same value as the /// first element of exactly one source vector without changing the length /// of that vector. /// Example: shufflevector <4 x n> A, <4 x n> B, bool isZeroEltSplat() const { return cast(Val)->isZeroEltSplat(); } /// Return true if this shuffle mask is a transpose mask. /// Transpose vector masks transpose a 2xn matrix. They read corresponding /// even- or odd-numbered vector elements from two n-dimensional source /// vectors and write each result into consecutive elements of an /// n-dimensional destination vector. Two shuffles are necessary to complete /// the transpose, one for the even elements and another for the odd elements. /// This description closely follows how the TRN1 and TRN2 AArch64 /// instructions operate. /// /// For example, a simple 2x2 matrix can be transposed with: /// /// ; Original matrix /// m0 = < a, b > /// m1 = < c, d > /// /// ; Transposed matrix /// t0 = < a, c > = shufflevector m0, m1, < 0, 2 > /// t1 = < b, d > = shufflevector m0, m1, < 1, 3 > /// /// For matrices having greater than n columns, the resulting nx2 transposed /// matrix is stored in two result vectors such that one vector contains /// interleaved elements from all the even-numbered rows and the other vector /// contains interleaved elements from all the odd-numbered rows. For example, /// a 2x4 matrix can be transposed with: /// /// ; Original matrix /// m0 = < a, b, c, d > /// m1 = < e, f, g, h > /// /// ; Transposed matrix /// t0 = < a, e, c, g > = shufflevector m0, m1 < 0, 4, 2, 6 > /// t1 = < b, f, d, h > = shufflevector m0, m1 < 1, 5, 3, 7 > static bool isTransposeMask(ArrayRef Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isTransposeMask(Mask, NumSrcElts); } static bool isTransposeMask(const Constant *Mask, int NumSrcElts) { return llvm::ShuffleVectorInst::isTransposeMask( cast(Mask->Val), NumSrcElts); } /// Return true if this shuffle transposes the elements of its inputs without /// changing the length of the vectors. This operation may also be known as a /// merge or interleave. See the description for isTransposeMask() for the /// exact specification. /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6> bool isTranspose() const { return cast(Val)->isTranspose(); } /// Return true if this shuffle mask is a splice mask, concatenating the two /// inputs together and then extracts an original width vector starting from /// the splice index. /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4> /// This assumes that vector operands (of length \p NumSrcElts) are the same /// length as the mask. static bool isSpliceMask(ArrayRef Mask, int NumSrcElts, int &Index) { return llvm::ShuffleVectorInst::isSpliceMask(Mask, NumSrcElts, Index); } static bool isSpliceMask(const Constant *Mask, int NumSrcElts, int &Index) { return llvm::ShuffleVectorInst::isSpliceMask( cast(Mask->Val), NumSrcElts, Index); } /// Return true if this shuffle splices two inputs without changing the length /// of the vectors. This operation concatenates the two inputs together and /// then extracts an original width vector starting from the splice index. /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4> bool isSplice(int &Index) const { return cast(Val)->isSplice(Index); } /// Return true if this shuffle mask is an extract subvector mask. /// A valid extract subvector mask returns a smaller vector from a single /// source operand. The base extraction index is returned as well. static bool isExtractSubvectorMask(ArrayRef Mask, int NumSrcElts, int &Index) { return llvm::ShuffleVectorInst::isExtractSubvectorMask(Mask, NumSrcElts, Index); } static bool isExtractSubvectorMask(const Constant *Mask, int NumSrcElts, int &Index) { return llvm::ShuffleVectorInst::isExtractSubvectorMask( cast(Mask->Val), NumSrcElts, Index); } /// Return true if this shuffle mask is an extract subvector mask. bool isExtractSubvectorMask(int &Index) const { return cast(Val)->isExtractSubvectorMask(Index); } /// Return true if this shuffle mask is an insert subvector mask. /// A valid insert subvector mask inserts the lowest elements of a second /// source operand into an in-place first source operand. /// Both the sub vector width and the insertion index is returned. static bool isInsertSubvectorMask(ArrayRef Mask, int NumSrcElts, int &NumSubElts, int &Index) { return llvm::ShuffleVectorInst::isInsertSubvectorMask(Mask, NumSrcElts, NumSubElts, Index); } static bool isInsertSubvectorMask(const Constant *Mask, int NumSrcElts, int &NumSubElts, int &Index) { return llvm::ShuffleVectorInst::isInsertSubvectorMask( cast(Mask->Val), NumSrcElts, NumSubElts, Index); } /// Return true if this shuffle mask is an insert subvector mask. bool isInsertSubvectorMask(int &NumSubElts, int &Index) const { return cast(Val)->isInsertSubvectorMask(NumSubElts, Index); } /// Return true if this shuffle mask replicates each of the \p VF elements /// in a vector \p ReplicationFactor times. /// For example, the mask for \p ReplicationFactor=3 and \p VF=4 is: /// <0,0,0,1,1,1,2,2,2,3,3,3> static bool isReplicationMask(ArrayRef Mask, int &ReplicationFactor, int &VF) { return llvm::ShuffleVectorInst::isReplicationMask(Mask, ReplicationFactor, VF); } static bool isReplicationMask(const Constant *Mask, int &ReplicationFactor, int &VF) { return llvm::ShuffleVectorInst::isReplicationMask( cast(Mask->Val), ReplicationFactor, VF); } /// Return true if this shuffle mask is a replication mask. bool isReplicationMask(int &ReplicationFactor, int &VF) const { return cast(Val)->isReplicationMask( ReplicationFactor, VF); } /// Return true if this shuffle mask represents "clustered" mask of size VF, /// i.e. each index between [0..VF) is used exactly once in each submask of /// size VF. /// For example, the mask for \p VF=4 is: /// 0, 1, 2, 3, 3, 2, 0, 1 - "clustered", because each submask of size 4 /// (0,1,2,3 and 3,2,0,1) uses indices [0..VF) exactly one time. /// 0, 1, 2, 3, 3, 3, 1, 0 - not "clustered", because /// element 3 is used twice in the second submask /// (3,3,1,0) and index 2 is not used at all. static bool isOneUseSingleSourceMask(ArrayRef Mask, int VF) { return llvm::ShuffleVectorInst::isOneUseSingleSourceMask(Mask, VF); } /// Return true if this shuffle mask is a one-use-single-source("clustered") /// mask. bool isOneUseSingleSourceMask(int VF) const { return cast(Val)->isOneUseSingleSourceMask(VF); } /// Change values in a shuffle permute mask assuming the two vector operands /// of length InVecNumElts have swapped position. static void commuteShuffleMask(MutableArrayRef Mask, unsigned InVecNumElts) { llvm::ShuffleVectorInst::commuteShuffleMask(Mask, InVecNumElts); } /// Return if this shuffle interleaves its two input vectors together. bool isInterleave(unsigned Factor) const { return cast(Val)->isInterleave(Factor); } /// Return true if the mask interleaves one or more input vectors together. /// /// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...> /// E.g. For a Factor of 2 (LaneLen=4): /// <0, 4, 1, 5, 2, 6, 3, 7> /// E.g. For a Factor of 3 (LaneLen=4): /// <4, 0, 9, 5, 1, 10, 6, 2, 11, 7, 3, 12> /// E.g. For a Factor of 4 (LaneLen=2): /// <0, 2, 6, 4, 1, 3, 7, 5> /// /// NumInputElts is the total number of elements in the input vectors. /// /// StartIndexes are the first indexes of each vector being interleaved, /// substituting any indexes that were undef /// E.g. <4, -1, 2, 5, 1, 3> (Factor=3): StartIndexes=<4, 0, 2> /// /// Note that this does not check if the input vectors are consecutive: /// It will return true for masks such as /// <0, 4, 6, 1, 5, 7> (Factor=3, LaneLen=2) static bool isInterleaveMask(ArrayRef Mask, unsigned Factor, unsigned NumInputElts, SmallVectorImpl &StartIndexes) { return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts, StartIndexes); } static bool isInterleaveMask(ArrayRef Mask, unsigned Factor, unsigned NumInputElts) { return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts); } /// Check if the mask is a DE-interleave mask of the given factor /// \p Factor like: /// static bool isDeInterleaveMaskOfFactor(ArrayRef Mask, unsigned Factor, unsigned &Index) { return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor, Index); } static bool isDeInterleaveMaskOfFactor(ArrayRef Mask, unsigned Factor) { return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor); } /// Checks if the shuffle is a bit rotation of the first operand across /// multiple subelements, e.g: /// /// shuffle <8 x i8> %a, <8 x i8> poison, <8 x i32> <1, 0, 3, 2, 5, 4, 7, 6> /// /// could be expressed as /// /// rotl <4 x i16> %a, 8 /// /// If it can be expressed as a rotation, returns the number of subelements to /// group by in NumSubElts and the number of bits to rotate left in RotateAmt. static bool isBitRotateMask(ArrayRef Mask, unsigned EltSizeInBits, unsigned MinSubElts, unsigned MaxSubElts, unsigned &NumSubElts, unsigned &RotateAmt) { return llvm::ShuffleVectorInst::isBitRotateMask( Mask, EltSizeInBits, MinSubElts, MaxSubElts, NumSubElts, RotateAmt); } }; class BranchInst : public SingleLLVMInstructionImpl { /// Use Context::createBranchInst(). Don't call the constructor directly. BranchInst(llvm::BranchInst *BI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Br, Opcode::Br, BI, Ctx) {} friend Context; // for BranchInst() public: static BranchInst *create(BasicBlock *IfTrue, Instruction *InsertBefore, Context &Ctx); static BranchInst *create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd, Context &Ctx); static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, Instruction *InsertBefore, Context &Ctx); static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BasicBlock *InsertAtEnd, Context &Ctx); /// For isa/dyn_cast. static bool classof(const Value *From); bool isUnconditional() const { return cast(Val)->isUnconditional(); } bool isConditional() const { return cast(Val)->isConditional(); } Value *getCondition() const; void setCondition(Value *V) { setOperand(0, V); } unsigned getNumSuccessors() const { return 1 + isConditional(); } BasicBlock *getSuccessor(unsigned SuccIdx) const; void setSuccessor(unsigned Idx, BasicBlock *NewSucc); void swapSuccessors() { swapOperandsInternal(1, 2); } private: struct LLVMBBToSBBB { Context &Ctx; LLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {} BasicBlock *operator()(llvm::BasicBlock *BB) const; }; struct ConstLLVMBBToSBBB { Context &Ctx; ConstLLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {} const BasicBlock *operator()(const llvm::BasicBlock *BB) const; }; public: using sb_succ_op_iterator = mapped_iterator; iterator_range successors() { iterator_range LLVMRange = cast(Val)->successors(); LLVMBBToSBBB BBMap(Ctx); sb_succ_op_iterator MappedBegin = map_iterator(LLVMRange.begin(), BBMap); sb_succ_op_iterator MappedEnd = map_iterator(LLVMRange.end(), BBMap); return make_range(MappedBegin, MappedEnd); } using const_sb_succ_op_iterator = mapped_iterator; iterator_range successors() const { iterator_range ConstLLVMRange = static_cast(cast(Val)) ->successors(); ConstLLVMBBToSBBB ConstBBMap(Ctx); const_sb_succ_op_iterator ConstMappedBegin = map_iterator(ConstLLVMRange.begin(), ConstBBMap); const_sb_succ_op_iterator ConstMappedEnd = map_iterator(ConstLLVMRange.end(), ConstBBMap); return make_range(ConstMappedBegin, ConstMappedEnd); } }; /// An abstract class, parent of unary instructions. class UnaryInstruction : public SingleLLVMInstructionImpl { protected: UnaryInstruction(ClassID ID, Opcode Opc, llvm::Instruction *LLVMI, Context &Ctx) : SingleLLVMInstructionImpl(ID, Opc, LLVMI, Ctx) {} public: static bool classof(const Instruction *I) { return isa(I) || isa(I); } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; class LoadInst final : public UnaryInstruction { /// Use LoadInst::create() instead of calling the constructor. LoadInst(llvm::LoadInst *LI, Context &Ctx) : UnaryInstruction(ClassID::Load, Opcode::Load, LI, Ctx) {} friend Context; // for LoadInst() public: /// Return true if this is a load from a volatile memory location. bool isVolatile() const { return cast(Val)->isVolatile(); } /// Specify whether this is a volatile load or not. void setVolatile(bool V); static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, Instruction *InsertBefore, bool IsVolatile, Context &Ctx, const Twine &Name = ""); static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, BasicBlock *InsertAtEnd, bool IsVolatile, Context &Ctx, const Twine &Name = ""); /// For isa/dyn_cast. static bool classof(const Value *From); Value *getPointerOperand() const; Align getAlign() const { return cast(Val)->getAlign(); } bool isUnordered() const { return cast(Val)->isUnordered(); } bool isSimple() const { return cast(Val)->isSimple(); } }; class StoreInst final : public SingleLLVMInstructionImpl { /// Use StoreInst::create(). StoreInst(llvm::StoreInst *SI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Store, Opcode::Store, SI, Ctx) {} friend Context; // for StoreInst() public: /// Return true if this is a store from a volatile memory location. bool isVolatile() const { return cast(Val)->isVolatile(); } /// Specify whether this is a volatile store or not. void setVolatile(bool V); static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, Instruction *InsertBefore, Context &Ctx); static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, Instruction *InsertBefore, bool IsVolatile, Context &Ctx); static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, BasicBlock *InsertAtEnd, Context &Ctx); static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, BasicBlock *InsertAtEnd, bool IsVolatile, Context &Ctx); /// For isa/dyn_cast. static bool classof(const Value *From); Value *getValueOperand() const; Value *getPointerOperand() const; Align getAlign() const { return cast(Val)->getAlign(); } bool isSimple() const { return cast(Val)->isSimple(); } bool isUnordered() const { return cast(Val)->isUnordered(); } }; class UnreachableInst final : public Instruction { /// Use UnreachableInst::create() instead of calling the constructor. UnreachableInst(llvm::UnreachableInst *I, Context &Ctx) : Instruction(ClassID::Unreachable, Opcode::Unreachable, I, Ctx) {} friend Context; Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { return getOperandUseDefault(OpIdx, Verify); } SmallVector getLLVMInstrs() const final { return {cast(Val)}; } public: static UnreachableInst *create(Instruction *InsertBefore, Context &Ctx); static UnreachableInst *create(BasicBlock *InsertAtEnd, Context &Ctx); static bool classof(const Value *From); unsigned getNumSuccessors() const { return 0; } unsigned getUseOperandNo(const Use &Use) const final { llvm_unreachable("UnreachableInst has no operands!"); } unsigned getNumOfIRInstrs() const final { return 1u; } }; class ReturnInst final : public SingleLLVMInstructionImpl { /// Use ReturnInst::create() instead of calling the constructor. ReturnInst(llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Ret, Opcode::Ret, I, Ctx) {} ReturnInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(SubclassID, Opcode::Ret, I, Ctx) {} friend class Context; // For accessing the constructor in create*() static ReturnInst *createCommon(Value *RetVal, IRBuilder<> &Builder, Context &Ctx); public: static ReturnInst *create(Value *RetVal, Instruction *InsertBefore, Context &Ctx); static ReturnInst *create(Value *RetVal, BasicBlock *InsertAtEnd, Context &Ctx); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::Ret; } /// \Returns null if there is no return value. Value *getReturnValue() const; }; class CallBase : public SingleLLVMInstructionImpl { CallBase(ClassID ID, Opcode Opc, llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ID, Opc, I, Ctx) {} friend class CallInst; // For constructor. friend class InvokeInst; // For constructor. friend class CallBrInst; // For constructor. public: static bool classof(const Value *From) { auto Opc = From->getSubclassID(); return Opc == Instruction::ClassID::Call || Opc == Instruction::ClassID::Invoke || Opc == Instruction::ClassID::CallBr; } FunctionType *getFunctionType() const { return cast(Val)->getFunctionType(); } op_iterator data_operands_begin() { return op_begin(); } const_op_iterator data_operands_begin() const { return const_cast(this)->data_operands_begin(); } op_iterator data_operands_end() { auto *LLVMCB = cast(Val); auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin(); return op_begin() + Dist; } const_op_iterator data_operands_end() const { auto *LLVMCB = cast(Val); auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin(); return op_begin() + Dist; } iterator_range data_ops() { return make_range(data_operands_begin(), data_operands_end()); } iterator_range data_ops() const { return make_range(data_operands_begin(), data_operands_end()); } bool data_operands_empty() const { return data_operands_end() == data_operands_begin(); } unsigned data_operands_size() const { return std::distance(data_operands_begin(), data_operands_end()); } bool isDataOperand(Use U) const { assert(this == U.getUser() && "Only valid to query with a use of this instruction!"); return cast(Val)->isDataOperand(U.LLVMUse); } unsigned getDataOperandNo(Use U) const { assert(isDataOperand(U) && "Data operand # out of range!"); return cast(Val)->getDataOperandNo(U.LLVMUse); } /// Return the total number operands (not operand bundles) used by /// every operand bundle in this OperandBundleUser. unsigned getNumTotalBundleOperands() const { return cast(Val)->getNumTotalBundleOperands(); } op_iterator arg_begin() { return op_begin(); } const_op_iterator arg_begin() const { return op_begin(); } op_iterator arg_end() { return data_operands_end() - getNumTotalBundleOperands(); } const_op_iterator arg_end() const { return const_cast(this)->arg_end(); } iterator_range args() { return make_range(arg_begin(), arg_end()); } iterator_range args() const { return make_range(arg_begin(), arg_end()); } bool arg_empty() const { return arg_end() == arg_begin(); } unsigned arg_size() const { return arg_end() - arg_begin(); } Value *getArgOperand(unsigned OpIdx) const { assert(OpIdx < arg_size() && "Out of bounds!"); return getOperand(OpIdx); } void setArgOperand(unsigned OpIdx, Value *NewOp) { assert(OpIdx < arg_size() && "Out of bounds!"); setOperand(OpIdx, NewOp); } Use getArgOperandUse(unsigned Idx) const { assert(Idx < arg_size() && "Out of bounds!"); return getOperandUse(Idx); } Use getArgOperandUse(unsigned Idx) { assert(Idx < arg_size() && "Out of bounds!"); return getOperandUse(Idx); } bool isArgOperand(Use U) const { return cast(Val)->isArgOperand(U.LLVMUse); } unsigned getArgOperandNo(Use U) const { return cast(Val)->getArgOperandNo(U.LLVMUse); } bool hasArgument(const Value *V) const { return is_contained(args(), V); } Value *getCalledOperand() const; Use getCalledOperandUse() const; Function *getCalledFunction() const; bool isIndirectCall() const { return cast(Val)->isIndirectCall(); } bool isCallee(Use U) const { return cast(Val)->isCallee(U.LLVMUse); } Function *getCaller(); const Function *getCaller() const { return const_cast(this)->getCaller(); } bool isMustTailCall() const { return cast(Val)->isMustTailCall(); } bool isTailCall() const { return cast(Val)->isTailCall(); } Intrinsic::ID getIntrinsicID() const { return cast(Val)->getIntrinsicID(); } void setCalledOperand(Value *V) { getCalledOperandUse().set(V); } void setCalledFunction(Function *F); CallingConv::ID getCallingConv() const { return cast(Val)->getCallingConv(); } bool isInlineAsm() const { return cast(Val)->isInlineAsm(); } }; class CallInst final : public CallBase { /// Use Context::createCallInst(). Don't call the /// constructor directly. CallInst(llvm::Instruction *I, Context &Ctx) : CallBase(ClassID::Call, Opcode::Call, I, Ctx) {} friend class Context; // For accessing the constructor in // create*() public: static CallInst *create(FunctionType *FTy, Value *Func, ArrayRef Args, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &NameStr = ""); static CallInst *create(FunctionType *FTy, Value *Func, ArrayRef Args, Instruction *InsertBefore, Context &Ctx, const Twine &NameStr = ""); static CallInst *create(FunctionType *FTy, Value *Func, ArrayRef Args, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &NameStr = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::Call; } }; class InvokeInst final : public CallBase { /// Use Context::createInvokeInst(). Don't call the /// constructor directly. InvokeInst(llvm::Instruction *I, Context &Ctx) : CallBase(ClassID::Invoke, Opcode::Invoke, I, Ctx) {} friend class Context; // For accessing the constructor in // create*() public: static InvokeInst *create(FunctionType *FTy, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &NameStr = ""); static InvokeInst *create(FunctionType *FTy, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, Instruction *InsertBefore, Context &Ctx, const Twine &NameStr = ""); static InvokeInst *create(FunctionType *FTy, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &NameStr = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::Invoke; } BasicBlock *getNormalDest() const; BasicBlock *getUnwindDest() const; void setNormalDest(BasicBlock *BB); void setUnwindDest(BasicBlock *BB); // TODO: Return a `LandingPadInst` once implemented. Instruction *getLandingPadInst() const; BasicBlock *getSuccessor(unsigned SuccIdx) const; void setSuccessor(unsigned SuccIdx, BasicBlock *NewSucc) { assert(SuccIdx < 2 && "Successor # out of range for invoke!"); if (SuccIdx == 0) setNormalDest(NewSucc); else setUnwindDest(NewSucc); } unsigned getNumSuccessors() const { return cast(Val)->getNumSuccessors(); } }; class CallBrInst final : public CallBase { /// Use Context::createCallBrInst(). Don't call the /// constructor directly. CallBrInst(llvm::Instruction *I, Context &Ctx) : CallBase(ClassID::CallBr, Opcode::CallBr, I, Ctx) {} friend class Context; // For accessing the constructor in // create*() public: static CallBrInst *create(FunctionType *FTy, Value *Func, BasicBlock *DefaultDest, ArrayRef IndirectDests, ArrayRef Args, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &NameStr = ""); static CallBrInst *create(FunctionType *FTy, Value *Func, BasicBlock *DefaultDest, ArrayRef IndirectDests, ArrayRef Args, Instruction *InsertBefore, Context &Ctx, const Twine &NameStr = ""); static CallBrInst *create(FunctionType *FTy, Value *Func, BasicBlock *DefaultDest, ArrayRef IndirectDests, ArrayRef Args, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &NameStr = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CallBr; } unsigned getNumIndirectDests() const { return cast(Val)->getNumIndirectDests(); } Value *getIndirectDestLabel(unsigned Idx) const; Value *getIndirectDestLabelUse(unsigned Idx) const; BasicBlock *getDefaultDest() const; BasicBlock *getIndirectDest(unsigned Idx) const; SmallVector getIndirectDests() const; void setDefaultDest(BasicBlock *BB); void setIndirectDest(unsigned Idx, BasicBlock *BB); BasicBlock *getSuccessor(unsigned Idx) const; unsigned getNumSuccessors() const { return cast(Val)->getNumSuccessors(); } }; class FuncletPadInst : public SingleLLVMInstructionImpl { FuncletPadInst(ClassID SubclassID, Opcode Opc, llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(SubclassID, Opc, I, Ctx) {} friend class CatchPadInst; // For constructor. friend class CleanupPadInst; // For constructor. public: /// Return the number of funcletpad arguments. unsigned arg_size() const { return cast(Val)->arg_size(); } /// Return the outer EH-pad this funclet is nested within. /// /// Note: This returns the associated CatchSwitchInst if this FuncletPadInst /// is a CatchPadInst. Value *getParentPad() const; void setParentPad(Value *ParentPad); /// Return the Idx-th funcletpad argument. Value *getArgOperand(unsigned Idx) const; /// Set the Idx-th funcletpad argument. void setArgOperand(unsigned Idx, Value *V); // TODO: Implement missing functions: arg_operands(). static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CatchPad || From->getSubclassID() == ClassID::CleanupPad; } }; class CatchPadInst : public FuncletPadInst { CatchPadInst(llvm::CatchPadInst *CPI, Context &Ctx) : FuncletPadInst(ClassID::CatchPad, Opcode::CatchPad, CPI, Ctx) {} friend class Context; // For constructor. public: CatchSwitchInst *getCatchSwitch() const; // TODO: We have not implemented setCatchSwitch() because we can't revert it // for now, as there is no CatchPadInst member function that can undo it. static CatchPadInst *create(Value *ParentPad, ArrayRef Args, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CatchPad; } }; class CleanupPadInst : public FuncletPadInst { CleanupPadInst(llvm::CleanupPadInst *CPI, Context &Ctx) : FuncletPadInst(ClassID::CleanupPad, Opcode::CleanupPad, CPI, Ctx) {} friend class Context; // For constructor. public: static CleanupPadInst *create(Value *ParentPad, ArrayRef Args, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CleanupPad; } }; class CatchReturnInst : public SingleLLVMInstructionImpl { CatchReturnInst(llvm::CatchReturnInst *CRI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::CatchRet, Opcode::CatchRet, CRI, Ctx) {} friend class Context; // For constructor. public: static CatchReturnInst *create(CatchPadInst *CatchPad, BasicBlock *BB, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx); CatchPadInst *getCatchPad() const; void setCatchPad(CatchPadInst *CatchPad); BasicBlock *getSuccessor() const; void setSuccessor(BasicBlock *NewSucc); unsigned getNumSuccessors() { return cast(Val)->getNumSuccessors(); } Value *getCatchSwitchParentPad() const; static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CatchRet; } }; class GetElementPtrInst final : public SingleLLVMInstructionImpl { /// Use Context::createGetElementPtrInst(). Don't call /// the constructor directly. GetElementPtrInst(llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::GetElementPtr, Opcode::GetElementPtr, I, Ctx) {} GetElementPtrInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx) : SingleLLVMInstructionImpl(SubclassID, Opcode::GetElementPtr, I, Ctx) {} friend class Context; // For accessing the constructor in // create*() public: static Value *create(Type *Ty, Value *Ptr, ArrayRef IdxList, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &NameStr = ""); static Value *create(Type *Ty, Value *Ptr, ArrayRef IdxList, Instruction *InsertBefore, Context &Ctx, const Twine &NameStr = ""); static Value *create(Type *Ty, Value *Ptr, ArrayRef IdxList, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &NameStr = ""); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::GetElementPtr; } Type *getSourceElementType() const { return cast(Val)->getSourceElementType(); } Type *getResultElementType() const { return cast(Val)->getResultElementType(); } unsigned getAddressSpace() const { return cast(Val)->getAddressSpace(); } inline op_iterator idx_begin() { return op_begin() + 1; } inline const_op_iterator idx_begin() const { return const_cast(this)->idx_begin(); } inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return const_cast(this)->idx_end(); } inline iterator_range indices() { return make_range(idx_begin(), idx_end()); } inline iterator_range indices() const { return const_cast(this)->indices(); } Value *getPointerOperand() const; static unsigned getPointerOperandIndex() { return llvm::GetElementPtrInst::getPointerOperandIndex(); } Type *getPointerOperandType() const { return cast(Val)->getPointerOperandType(); } unsigned getPointerAddressSpace() const { return cast(Val)->getPointerAddressSpace(); } unsigned getNumIndices() const { return cast(Val)->getNumIndices(); } bool hasIndices() const { return cast(Val)->hasIndices(); } bool hasAllConstantIndices() const { return cast(Val)->hasAllConstantIndices(); } GEPNoWrapFlags getNoWrapFlags() const { return cast(Val)->getNoWrapFlags(); } bool isInBounds() const { return cast(Val)->isInBounds(); } bool hasNoUnsignedSignedWrap() const { return cast(Val)->hasNoUnsignedSignedWrap(); } bool hasNoUnsignedWrap() const { return cast(Val)->hasNoUnsignedWrap(); } bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const { return cast(Val)->accumulateConstantOffset(DL, Offset); } // TODO: Add missing member functions. }; class CatchSwitchInst : public SingleLLVMInstructionImpl { public: CatchSwitchInst(llvm::CatchSwitchInst *CSI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::CatchSwitch, Opcode::CatchSwitch, CSI, Ctx) {} static CatchSwitchInst *create(Value *ParentPad, BasicBlock *UnwindBB, unsigned NumHandlers, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); Value *getParentPad() const; void setParentPad(Value *ParentPad); bool hasUnwindDest() const { return cast(Val)->hasUnwindDest(); } bool unwindsToCaller() const { return cast(Val)->unwindsToCaller(); } BasicBlock *getUnwindDest() const; void setUnwindDest(BasicBlock *UnwindDest); unsigned getNumHandlers() const { return cast(Val)->getNumHandlers(); } private: static BasicBlock *handler_helper(Value *V) { return cast(V); } static const BasicBlock *handler_helper(const Value *V) { return cast(V); } public: using DerefFnTy = BasicBlock *(*)(Value *); using handler_iterator = mapped_iterator; using handler_range = iterator_range; using ConstDerefFnTy = const BasicBlock *(*)(const Value *); using const_handler_iterator = mapped_iterator; using const_handler_range = iterator_range; handler_iterator handler_begin() { op_iterator It = op_begin() + 1; if (hasUnwindDest()) ++It; return handler_iterator(It, DerefFnTy(handler_helper)); } const_handler_iterator handler_begin() const { const_op_iterator It = op_begin() + 1; if (hasUnwindDest()) ++It; return const_handler_iterator(It, ConstDerefFnTy(handler_helper)); } handler_iterator handler_end() { return handler_iterator(op_end(), DerefFnTy(handler_helper)); } const_handler_iterator handler_end() const { return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper)); } handler_range handlers() { return make_range(handler_begin(), handler_end()); } const_handler_range handlers() const { return make_range(handler_begin(), handler_end()); } void addHandler(BasicBlock *Dest); // TODO: removeHandler() cannot be reverted because there is no equivalent // addHandler() with a handler_iterator to specify the position. So we can't // implement it for now. unsigned getNumSuccessors() const { return getNumOperands() - 1; } BasicBlock *getSuccessor(unsigned Idx) const { assert(Idx < getNumSuccessors() && "Successor # out of range for catchswitch!"); return cast(getOperand(Idx + 1)); } void setSuccessor(unsigned Idx, BasicBlock *NewSucc) { assert(Idx < getNumSuccessors() && "Successor # out of range for catchswitch!"); setOperand(Idx + 1, NewSucc); } static bool classof(const Value *From) { return From->getSubclassID() == ClassID::CatchSwitch; } }; class SwitchInst : public SingleLLVMInstructionImpl { public: SwitchInst(llvm::SwitchInst *SI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Switch, Opcode::Switch, SI, Ctx) {} static constexpr const unsigned DefaultPseudoIndex = llvm::SwitchInst::DefaultPseudoIndex; static SwitchInst *create(Value *V, BasicBlock *Dest, unsigned NumCases, BasicBlock::iterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); Value *getCondition() const; void setCondition(Value *V); BasicBlock *getDefaultDest() const; bool defaultDestUndefined() const { return cast(Val)->defaultDestUndefined(); } void setDefaultDest(BasicBlock *DefaultCase); unsigned getNumCases() const { return cast(Val)->getNumCases(); } using CaseHandle = llvm::SwitchInst::CaseHandleImpl; using ConstCaseHandle = llvm::SwitchInst::CaseHandleImpl; using CaseIt = llvm::SwitchInst::CaseIteratorImpl; using ConstCaseIt = llvm::SwitchInst::CaseIteratorImpl; /// Returns a read/write iterator that points to the first case in the /// SwitchInst. CaseIt case_begin() { return CaseIt(this, 0); } ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); } /// Returns a read/write iterator that points one past the last in the /// SwitchInst. CaseIt case_end() { return CaseIt(this, getNumCases()); } ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); } /// Iteration adapter for range-for loops. iterator_range cases() { return make_range(case_begin(), case_end()); } iterator_range cases() const { return make_range(case_begin(), case_end()); } CaseIt case_default() { return CaseIt(this, DefaultPseudoIndex); } ConstCaseIt case_default() const { return ConstCaseIt(this, DefaultPseudoIndex); } CaseIt findCaseValue(const ConstantInt *C) { return CaseIt( this, const_cast(this)->findCaseValue(C)->getCaseIndex()); } ConstCaseIt findCaseValue(const ConstantInt *C) const { ConstCaseIt I = llvm::find_if(cases(), [C](const ConstCaseHandle &Case) { return Case.getCaseValue() == C; }); if (I != case_end()) return I; return case_default(); } ConstantInt *findCaseDest(BasicBlock *BB); void addCase(ConstantInt *OnVal, BasicBlock *Dest); /// This method removes the specified case and its successor from the switch /// instruction. Note that this operation may reorder the remaining cases at /// index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, /// including the case_end() iterator. It returns an iterator for the next /// case. CaseIt removeCase(CaseIt It); unsigned getNumSuccessors() const { return cast(Val)->getNumSuccessors(); } BasicBlock *getSuccessor(unsigned Idx) const; void setSuccessor(unsigned Idx, BasicBlock *NewSucc); static bool classof(const Value *From) { return From->getSubclassID() == ClassID::Switch; } }; class UnaryOperator : public UnaryInstruction { static Opcode getUnaryOpcode(llvm::Instruction::UnaryOps UnOp) { switch (UnOp) { case llvm::Instruction::FNeg: return Opcode::FNeg; case llvm::Instruction::UnaryOpsEnd: llvm_unreachable("Bad UnOp!"); } llvm_unreachable("Unhandled UnOp!"); } UnaryOperator(llvm::UnaryOperator *UO, Context &Ctx) : UnaryInstruction(ClassID::UnOp, getUnaryOpcode(UO->getOpcode()), UO, Ctx) {} friend Context; // for constructor. public: static Value *create(Instruction::Opcode Op, Value *OpV, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static Value *create(Instruction::Opcode Op, Value *OpV, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Instruction::Opcode Op, Value *OpV, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV, Value *CopyFrom, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV, Value *CopyFrom, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV, Value *CopyFrom, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); /// For isa/dyn_cast. static bool classof(const Value *From) { return From->getSubclassID() == ClassID::UnOp; } }; class BinaryOperator : public SingleLLVMInstructionImpl { static Opcode getBinOpOpcode(llvm::Instruction::BinaryOps BinOp) { switch (BinOp) { case llvm::Instruction::Add: return Opcode::Add; case llvm::Instruction::FAdd: return Opcode::FAdd; case llvm::Instruction::Sub: return Opcode::Sub; case llvm::Instruction::FSub: return Opcode::FSub; case llvm::Instruction::Mul: return Opcode::Mul; case llvm::Instruction::FMul: return Opcode::FMul; case llvm::Instruction::UDiv: return Opcode::UDiv; case llvm::Instruction::SDiv: return Opcode::SDiv; case llvm::Instruction::FDiv: return Opcode::FDiv; case llvm::Instruction::URem: return Opcode::URem; case llvm::Instruction::SRem: return Opcode::SRem; case llvm::Instruction::FRem: return Opcode::FRem; case llvm::Instruction::Shl: return Opcode::Shl; case llvm::Instruction::LShr: return Opcode::LShr; case llvm::Instruction::AShr: return Opcode::AShr; case llvm::Instruction::And: return Opcode::And; case llvm::Instruction::Or: return Opcode::Or; case llvm::Instruction::Xor: return Opcode::Xor; case llvm::Instruction::BinaryOpsEnd: llvm_unreachable("Bad BinOp!"); } llvm_unreachable("Unhandled BinOp!"); } BinaryOperator(llvm::BinaryOperator *BinOp, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::BinaryOperator, getBinOpOpcode(BinOp->getOpcode()), BinOp, Ctx) {} friend class Context; // For constructor. public: static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS, Value *RHS, Value *CopyFrom, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS, Value *RHS, Value *CopyFrom, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS, Value *RHS, Value *CopyFrom, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); /// For isa/dyn_cast. static bool classof(const Value *From) { return From->getSubclassID() == ClassID::BinaryOperator; } void swapOperands() { swapOperandsInternal(0, 1); } }; class AtomicRMWInst : public SingleLLVMInstructionImpl { AtomicRMWInst(llvm::AtomicRMWInst *Atomic, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::AtomicRMW, Instruction::Opcode::AtomicRMW, Atomic, Ctx) { } friend class Context; // For constructor. public: using BinOp = llvm::AtomicRMWInst::BinOp; BinOp getOperation() const { return cast(Val)->getOperation(); } static StringRef getOperationName(BinOp Op) { return llvm::AtomicRMWInst::getOperationName(Op); } static bool isFPOperation(BinOp Op) { return llvm::AtomicRMWInst::isFPOperation(Op); } void setOperation(BinOp Op) { cast(Val)->setOperation(Op); } Align getAlign() const { return cast(Val)->getAlign(); } void setAlignment(Align Align); bool isVolatile() const { return cast(Val)->isVolatile(); } void setVolatile(bool V); AtomicOrdering getOrdering() const { return cast(Val)->getOrdering(); } void setOrdering(AtomicOrdering Ordering); SyncScope::ID getSyncScopeID() const { return cast(Val)->getSyncScopeID(); } void setSyncScopeID(SyncScope::ID SSID); Value *getPointerOperand(); const Value *getPointerOperand() const { return const_cast(this)->getPointerOperand(); } Value *getValOperand(); const Value *getValOperand() const { return const_cast(this)->getValOperand(); } unsigned getPointerAddressSpace() const { return cast(Val)->getPointerAddressSpace(); } bool isFloatingPointOperation() const { return cast(Val)->isFloatingPointOperation(); } static bool classof(const Value *From) { return From->getSubclassID() == ClassID::AtomicRMW; } static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, Instruction *InsertBefore, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, BasicBlock *InsertAtEnd, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); }; class AtomicCmpXchgInst : public SingleLLVMInstructionImpl { AtomicCmpXchgInst(llvm::AtomicCmpXchgInst *Atomic, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::AtomicCmpXchg, Instruction::Opcode::AtomicCmpXchg, Atomic, Ctx) {} friend class Context; // For constructor. public: /// Return the alignment of the memory that is being allocated by the /// instruction. Align getAlign() const { return cast(Val)->getAlign(); } void setAlignment(Align Align); /// Return true if this is a cmpxchg from a volatile memory /// location. bool isVolatile() const { return cast(Val)->isVolatile(); } /// Specify whether this is a volatile cmpxchg. void setVolatile(bool V); /// Return true if this cmpxchg may spuriously fail. bool isWeak() const { return cast(Val)->isWeak(); } void setWeak(bool IsWeak); static bool isValidSuccessOrdering(AtomicOrdering Ordering) { return llvm::AtomicCmpXchgInst::isValidSuccessOrdering(Ordering); } static bool isValidFailureOrdering(AtomicOrdering Ordering) { return llvm::AtomicCmpXchgInst::isValidFailureOrdering(Ordering); } AtomicOrdering getSuccessOrdering() const { return cast(Val)->getSuccessOrdering(); } void setSuccessOrdering(AtomicOrdering Ordering); AtomicOrdering getFailureOrdering() const { return cast(Val)->getFailureOrdering(); } void setFailureOrdering(AtomicOrdering Ordering); AtomicOrdering getMergedOrdering() const { return cast(Val)->getMergedOrdering(); } SyncScope::ID getSyncScopeID() const { return cast(Val)->getSyncScopeID(); } void setSyncScopeID(SyncScope::ID SSID); Value *getPointerOperand(); const Value *getPointerOperand() const { return const_cast(this)->getPointerOperand(); } Value *getCompareOperand(); const Value *getCompareOperand() const { return const_cast(this)->getCompareOperand(); } Value *getNewValOperand(); const Value *getNewValOperand() const { return const_cast(this)->getNewValOperand(); } /// Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return cast(Val)->getPointerAddressSpace(); } static AtomicCmpXchgInst * create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); static AtomicCmpXchgInst * create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, Instruction *InsertBefore, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); static AtomicCmpXchgInst * create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, BasicBlock *InsertAtEnd, Context &Ctx, SyncScope::ID SSID = SyncScope::System, const Twine &Name = ""); }; class AllocaInst final : public UnaryInstruction { AllocaInst(llvm::AllocaInst *AI, Context &Ctx) : UnaryInstruction(ClassID::Alloca, Instruction::Opcode::Alloca, AI, Ctx) {} friend class Context; // For constructor. public: static AllocaInst *create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, Value *ArraySize = nullptr, const Twine &Name = ""); static AllocaInst *create(Type *Ty, unsigned AddrSpace, Instruction *InsertBefore, Context &Ctx, Value *ArraySize = nullptr, const Twine &Name = ""); static AllocaInst *create(Type *Ty, unsigned AddrSpace, BasicBlock *InsertAtEnd, Context &Ctx, Value *ArraySize = nullptr, const Twine &Name = ""); /// Return true if there is an allocation size parameter to the allocation /// instruction that is not 1. bool isArrayAllocation() const { return cast(Val)->isArrayAllocation(); } /// Get the number of elements allocated. For a simple allocation of a single /// element, this will return a constant 1 value. Value *getArraySize(); const Value *getArraySize() const { return const_cast(this)->getArraySize(); } /// Overload to return most specific pointer type. PointerType *getType() const { return cast(Val)->getType(); } /// Return the address space for the allocation. unsigned getAddressSpace() const { return cast(Val)->getAddressSpace(); } /// Get allocation size in bytes. Returns std::nullopt if size can't be /// determined, e.g. in case of a VLA. std::optional getAllocationSize(const DataLayout &DL) const { return cast(Val)->getAllocationSize(DL); } /// Get allocation size in bits. Returns std::nullopt if size can't be /// determined, e.g. in case of a VLA. std::optional getAllocationSizeInBits(const DataLayout &DL) const { return cast(Val)->getAllocationSizeInBits(DL); } /// Return the type that is being allocated by the instruction. Type *getAllocatedType() const { return cast(Val)->getAllocatedType(); } /// for use only in special circumstances that need to generically /// transform a whole instruction (eg: IR linking and vectorization). void setAllocatedType(Type *Ty); /// Return the alignment of the memory that is being allocated by the /// instruction. Align getAlign() const { return cast(Val)->getAlign(); } void setAlignment(Align Align); /// Return true if this alloca is in the entry block of the function and is a /// constant size. If so, the code generator will fold it into the /// prolog/epilog code, so it is basically free. bool isStaticAlloca() const { return cast(Val)->isStaticAlloca(); } /// Return true if this alloca is used as an inalloca argument to a call. Such /// allocas are never considered static even if they are in the entry block. bool isUsedWithInAlloca() const { return cast(Val)->isUsedWithInAlloca(); } /// Specify whether this alloca is used to represent the arguments to a call. void setUsedWithInAlloca(bool V); static bool classof(const Value *From) { if (auto *I = dyn_cast(From)) return I->getSubclassID() == Instruction::ClassID::Alloca; return false; } }; class CastInst : public UnaryInstruction { static Opcode getCastOpcode(llvm::Instruction::CastOps CastOp) { switch (CastOp) { case llvm::Instruction::ZExt: return Opcode::ZExt; case llvm::Instruction::SExt: return Opcode::SExt; case llvm::Instruction::FPToUI: return Opcode::FPToUI; case llvm::Instruction::FPToSI: return Opcode::FPToSI; case llvm::Instruction::FPExt: return Opcode::FPExt; case llvm::Instruction::PtrToInt: return Opcode::PtrToInt; case llvm::Instruction::IntToPtr: return Opcode::IntToPtr; case llvm::Instruction::SIToFP: return Opcode::SIToFP; case llvm::Instruction::UIToFP: return Opcode::UIToFP; case llvm::Instruction::Trunc: return Opcode::Trunc; case llvm::Instruction::FPTrunc: return Opcode::FPTrunc; case llvm::Instruction::BitCast: return Opcode::BitCast; case llvm::Instruction::AddrSpaceCast: return Opcode::AddrSpaceCast; case llvm::Instruction::CastOpsEnd: llvm_unreachable("Bad CastOp!"); } llvm_unreachable("Unhandled CastOp!"); } /// Use Context::createCastInst(). Don't call the /// constructor directly. CastInst(llvm::CastInst *CI, Context &Ctx) : UnaryInstruction(ClassID::Cast, getCastOpcode(CI->getOpcode()), CI, Ctx) {} friend Context; // for SBCastInstruction() public: static Value *create(Type *DestTy, Opcode Op, Value *Operand, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = ""); static Value *create(Type *DestTy, Opcode Op, Value *Operand, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); static Value *create(Type *DestTy, Opcode Op, Value *Operand, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = ""); /// For isa/dyn_cast. static bool classof(const Value *From); Type *getSrcTy() const { return cast(Val)->getSrcTy(); } Type *getDestTy() const { return cast(Val)->getDestTy(); } }; // Helper class to simplify stamping out CastInst subclasses. template class CastInstImpl : public CastInst { public: static Value *create(Value *Src, Type *DestTy, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name = "") { return CastInst::create(DestTy, Op, Src, WhereIt, WhereBB, Ctx, Name); } static Value *create(Value *Src, Type *DestTy, Instruction *InsertBefore, Context &Ctx, const Twine &Name = "") { return create(Src, DestTy, InsertBefore->getIterator(), InsertBefore->getParent(), Ctx, Name); } static Value *create(Value *Src, Type *DestTy, BasicBlock *InsertAtEnd, Context &Ctx, const Twine &Name = "") { return create(Src, DestTy, InsertAtEnd->end(), InsertAtEnd, Ctx, Name); } static bool classof(const Value *From) { if (auto *I = dyn_cast(From)) return I->getOpcode() == Op; return false; } }; class TruncInst final : public CastInstImpl {}; class ZExtInst final : public CastInstImpl {}; class SExtInst final : public CastInstImpl {}; class FPTruncInst final : public CastInstImpl {}; class FPExtInst final : public CastInstImpl {}; class UIToFPInst final : public CastInstImpl {}; class SIToFPInst final : public CastInstImpl {}; class FPToUIInst final : public CastInstImpl {}; class FPToSIInst final : public CastInstImpl {}; class IntToPtrInst final : public CastInstImpl { }; class PtrToIntInst final : public CastInstImpl { }; class BitCastInst final : public CastInstImpl {}; class AddrSpaceCastInst final : public CastInstImpl { public: /// \Returns the pointer operand. Value *getPointerOperand() { return getOperand(0); } /// \Returns the pointer operand. const Value *getPointerOperand() const { return const_cast(this)->getPointerOperand(); } /// \Returns the operand index of the pointer operand. static unsigned getPointerOperandIndex() { return 0u; } /// \Returns the address space of the pointer operand. unsigned getSrcAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } /// \Returns the address space of the result. unsigned getDestAddressSpace() const { return getType()->getPointerAddressSpace(); } }; class PHINode final : public SingleLLVMInstructionImpl { /// Use Context::createPHINode(). Don't call the constructor directly. PHINode(llvm::PHINode *PHI, Context &Ctx) : SingleLLVMInstructionImpl(ClassID::PHI, Opcode::PHI, PHI, Ctx) {} friend Context; // for PHINode() /// Helper for mapped_iterator. struct LLVMBBToBB { Context &Ctx; LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {} BasicBlock *operator()(llvm::BasicBlock *LLVMBB) const; }; public: static PHINode *create(Type *Ty, unsigned NumReservedValues, Instruction *InsertBefore, Context &Ctx, const Twine &Name = ""); /// For isa/dyn_cast. static bool classof(const Value *From); using const_block_iterator = mapped_iterator; const_block_iterator block_begin() const { LLVMBBToBB BBGetter(Ctx); return const_block_iterator(cast(Val)->block_begin(), BBGetter); } const_block_iterator block_end() const { LLVMBBToBB BBGetter(Ctx); return const_block_iterator(cast(Val)->block_end(), BBGetter); } iterator_range blocks() const { return make_range(block_begin(), block_end()); } op_range incoming_values() { return operands(); } const_op_range incoming_values() const { return operands(); } unsigned getNumIncomingValues() const { return cast(Val)->getNumIncomingValues(); } Value *getIncomingValue(unsigned Idx) const; void setIncomingValue(unsigned Idx, Value *V); static unsigned getOperandNumForIncomingValue(unsigned Idx) { return llvm::PHINode::getOperandNumForIncomingValue(Idx); } static unsigned getIncomingValueNumForOperand(unsigned Idx) { return llvm::PHINode::getIncomingValueNumForOperand(Idx); } BasicBlock *getIncomingBlock(unsigned Idx) const; BasicBlock *getIncomingBlock(const Use &U) const; void setIncomingBlock(unsigned Idx, BasicBlock *BB); void addIncoming(Value *V, BasicBlock *BB); Value *removeIncomingValue(unsigned Idx); Value *removeIncomingValue(BasicBlock *BB); int getBasicBlockIndex(const BasicBlock *BB) const; Value *getIncomingValueForBlock(const BasicBlock *BB) const; Value *hasConstantValue() const; bool hasConstantOrUndefValue() const { return cast(Val)->hasConstantOrUndefValue(); } bool isComplete() const { return cast(Val)->isComplete(); } void replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New); void removeIncomingValueIf(function_ref Predicate); // TODO: Implement // void copyIncomingBlocks(iterator_range BBRange, // uint32_t ToIdx = 0) }; /// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to /// an OpaqueInstr. class OpaqueInst : public SingleLLVMInstructionImpl { OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx) : SingleLLVMInstructionImpl(ClassID::Opaque, Opcode::Opaque, I, Ctx) {} OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx) : SingleLLVMInstructionImpl(SubclassID, Opcode::Opaque, I, Ctx) {} friend class Context; // For constructor. public: static bool classof(const sandboxir::Value *From) { return From->getSubclassID() == ClassID::Opaque; } }; class Context { protected: LLVMContext &LLVMCtx; Tracker IRTracker; /// Maps LLVM Value to the corresponding sandboxir::Value. Owns all /// SandboxIR objects. DenseMap> LLVMValueToValueMap; /// Remove \p V from the maps and returns the unique_ptr. std::unique_ptr detachLLVMValue(llvm::Value *V); /// Remove \p SBV from all SandboxIR maps and stop owning it. This effectively /// detaches \p V from the underlying IR. std::unique_ptr detach(Value *V); friend void Instruction::eraseFromParent(); // For detach(). /// Take ownership of VPtr and store it in `LLVMValueToValueMap`. Value *registerValue(std::unique_ptr &&VPtr); friend class EraseFromParent; // For registerValue(). /// This is the actual function that creates sandboxir values for \p V, /// and among others handles all instruction types. Value *getOrCreateValueInternal(llvm::Value *V, llvm::User *U = nullptr); /// Get or create a sandboxir::Argument for an existing LLVM IR \p LLVMArg. Argument *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()); } /// Get or create a sandboxir::Value for an existing LLVM IR \p LLVMV. Value *getOrCreateValue(llvm::Value *LLVMV) { return getOrCreateValueInternal(LLVMV, 0); } /// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC. Constant *getOrCreateConstant(llvm::Constant *LLVMC) { return cast(getOrCreateValueInternal(LLVMC, 0)); } friend class ConstantInt; // For getOrCreateConstant(). /// Create a sandboxir::BasicBlock for an existing LLVM IR \p BB. This will /// also create all contents of the block. BasicBlock *createBasicBlock(llvm::BasicBlock *BB); friend class BasicBlock; // For getOrCreateValue(). IRBuilder LLVMIRBuilder; auto &getLLVMIRBuilder() { return LLVMIRBuilder; } SelectInst *createSelectInst(llvm::SelectInst *SI); friend SelectInst; // For createSelectInst() InsertElementInst *createInsertElementInst(llvm::InsertElementInst *IEI); friend InsertElementInst; // For createInsertElementInst() ExtractElementInst *createExtractElementInst(llvm::ExtractElementInst *EEI); friend ExtractElementInst; // For createExtractElementInst() ShuffleVectorInst *createShuffleVectorInst(llvm::ShuffleVectorInst *SVI); friend ShuffleVectorInst; // For createShuffleVectorInst() BranchInst *createBranchInst(llvm::BranchInst *I); friend BranchInst; // For createBranchInst() LoadInst *createLoadInst(llvm::LoadInst *LI); friend LoadInst; // For createLoadInst() StoreInst *createStoreInst(llvm::StoreInst *SI); friend StoreInst; // For createStoreInst() ReturnInst *createReturnInst(llvm::ReturnInst *I); friend ReturnInst; // For createReturnInst() CallInst *createCallInst(llvm::CallInst *I); friend CallInst; // For createCallInst() InvokeInst *createInvokeInst(llvm::InvokeInst *I); friend InvokeInst; // For createInvokeInst() CallBrInst *createCallBrInst(llvm::CallBrInst *I); friend CallBrInst; // For createCallBrInst() CatchPadInst *createCatchPadInst(llvm::CatchPadInst *I); friend CatchPadInst; // For createCatchPadInst() CleanupPadInst *createCleanupPadInst(llvm::CleanupPadInst *I); friend CleanupPadInst; // For createCleanupPadInst() CatchReturnInst *createCatchReturnInst(llvm::CatchReturnInst *I); friend CatchReturnInst; // For createCatchReturnInst() GetElementPtrInst *createGetElementPtrInst(llvm::GetElementPtrInst *I); friend GetElementPtrInst; // For createGetElementPtrInst() CatchSwitchInst *createCatchSwitchInst(llvm::CatchSwitchInst *I); friend CatchSwitchInst; // For createCatchSwitchInst() SwitchInst *createSwitchInst(llvm::SwitchInst *I); friend SwitchInst; // For createSwitchInst() UnaryOperator *createUnaryOperator(llvm::UnaryOperator *I); friend UnaryOperator; // For createUnaryOperator() BinaryOperator *createBinaryOperator(llvm::BinaryOperator *I); friend BinaryOperator; // For createBinaryOperator() AtomicRMWInst *createAtomicRMWInst(llvm::AtomicRMWInst *I); friend AtomicRMWInst; // For createAtomicRMWInst() AtomicCmpXchgInst *createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I); friend AtomicCmpXchgInst; // For createAtomicCmpXchgInst() AllocaInst *createAllocaInst(llvm::AllocaInst *I); friend AllocaInst; // For createAllocaInst() CastInst *createCastInst(llvm::CastInst *I); friend CastInst; // For createCastInst() PHINode *createPHINode(llvm::PHINode *I); friend PHINode; // For createPHINode() UnreachableInst *createUnreachableInst(llvm::UnreachableInst *UI); friend UnreachableInst; // For createUnreachableInst() public: Context(LLVMContext &LLVMCtx) : LLVMCtx(LLVMCtx), IRTracker(*this), LLVMIRBuilder(LLVMCtx, ConstantFolder()) {} Tracker &getTracker() { return IRTracker; } /// Convenience function for `getTracker().save()` void save() { IRTracker.save(); } /// Convenience function for `getTracker().revert()` void revert() { IRTracker.revert(); } /// Convenience function for `getTracker().accept()` void accept() { IRTracker.accept(); } sandboxir::Value *getValue(llvm::Value *V) const; const sandboxir::Value *getValue(const llvm::Value *V) const { return getValue(const_cast(V)); } /// Create a sandboxir::Function for an existing LLVM IR \p F, including all /// blocks and instructions. /// This is the main API function for creating Sandbox IR. Function *createFunction(llvm::Function *F); /// \Returns the number of values registered with Context. size_t getNumValues() const { return LLVMValueToValueMap.size(); } }; class Function : public Constant { /// Helper for mapped_iterator. struct LLVMBBToBB { Context &Ctx; LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {} BasicBlock &operator()(llvm::BasicBlock &LLVMBB) const { return *cast(Ctx.getValue(&LLVMBB)); } }; /// Use Context::createFunction() instead. Function(llvm::Function *F, sandboxir::Context &Ctx) : Constant(ClassID::Function, F, Ctx) {} friend class Context; // For constructor. public: /// For isa/dyn_cast. static bool classof(const sandboxir::Value *From) { return From->getSubclassID() == ClassID::Function; } Argument *getArg(unsigned Idx) const { llvm::Argument *Arg = cast(Val)->getArg(Idx); return cast(Ctx.getValue(Arg)); } size_t arg_size() const { return cast(Val)->arg_size(); } bool arg_empty() const { return cast(Val)->arg_empty(); } using iterator = mapped_iterator; iterator begin() const { LLVMBBToBB BBGetter(Ctx); return iterator(cast(Val)->begin(), BBGetter); } iterator end() const { LLVMBBToBB BBGetter(Ctx); return iterator(cast(Val)->end(), BBGetter); } FunctionType *getFunctionType() const { return cast(Val)->getFunctionType(); } #ifndef NDEBUG void verify() const final { assert(isa(Val) && "Expected Function!"); } void dumpNameAndArgs(raw_ostream &OS) const; void dumpOS(raw_ostream &OS) const final; #endif }; } // namespace sandboxir } // namespace llvm #endif // LLVM_SANDBOXIR_SANDBOXIR_H