X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FIR%2FInstrTypes.h;h=5091bb4078336a659a8edab75b5078611f8e759a;hb=ef112d46b98642b59c657f1560f7e1c21b13a0da;hp=d84e66c50a3e798dadc064b6f891634a6a0c3bda;hpb=226889eb73e83dea20c050047bcff71e1552a90f;p=oota-llvm.git diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index d84e66c50a3..5091bb40783 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -16,9 +16,12 @@ #ifndef LLVM_IR_INSTRTYPES_H #define LLVM_IR_INSTRTYPES_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/OperandTraits.h" namespace llvm { @@ -51,8 +54,8 @@ protected: virtual BasicBlock *getSuccessorV(unsigned idx) const = 0; virtual unsigned getNumSuccessorsV() const = 0; virtual void setSuccessorV(unsigned idx, BasicBlock *B) = 0; -public: +public: /// Return the number of successors that this terminator has. unsigned getNumSuccessors() const { return getNumSuccessorsV(); @@ -79,14 +82,11 @@ public: // \brief Returns true if this terminator relates to exception handling. bool isExceptional() const { switch (getOpcode()) { - case Instruction::CatchPad: - case Instruction::CatchEndPad: + case Instruction::CatchSwitch: case Instruction::CatchRet: - case Instruction::CleanupEndPad: case Instruction::CleanupRet: case Instruction::Invoke: case Instruction::Resume: - case Instruction::TerminatePad: return true; default: return false; @@ -271,7 +271,6 @@ public: } }; - //===----------------------------------------------------------------------===// // UnaryInstruction Class //===----------------------------------------------------------------------===// @@ -289,6 +288,7 @@ protected: : Instruction(Ty, iType, &Op<0>(), 1, IAE) { Op<0>() = V; } + public: // allocate space for exactly one operand void *operator new(size_t s) { @@ -327,6 +327,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryInstruction, Value) class BinaryOperator : public Instruction { void *operator new(size_t, unsigned) = delete; + protected: void init(BinaryOps iType); BinaryOperator(BinaryOps iType, Value *S1, Value *S2, Type *Ty, @@ -403,7 +404,7 @@ public: BO->setHasNoSignedWrap(true); return BO; } - + static BinaryOperator *CreateNUW(BinaryOps Opc, Value *V1, Value *V2, const Twine &Name = "") { BinaryOperator *BO = Create(Opc, V1, V2, Name); @@ -422,7 +423,7 @@ public: BO->setHasNoUnsignedWrap(true); return BO; } - + static BinaryOperator *CreateExact(BinaryOps Opc, Value *V1, Value *V2, const Twine &Name = "") { BinaryOperator *BO = Create(Opc, V1, V2, Name); @@ -441,29 +442,29 @@ public: BO->setIsExact(true); return BO; } - -#define DEFINE_HELPERS(OPC, NUWNSWEXACT) \ - static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ - (Value *V1, Value *V2, const Twine &Name = "") { \ - return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name); \ - } \ - static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ - (Value *V1, Value *V2, const Twine &Name, BasicBlock *BB) { \ - return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name, BB); \ - } \ - static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ - (Value *V1, Value *V2, const Twine &Name, Instruction *I) { \ - return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name, I); \ - } - - DEFINE_HELPERS(Add, NSW) // CreateNSWAdd - DEFINE_HELPERS(Add, NUW) // CreateNUWAdd - DEFINE_HELPERS(Sub, NSW) // CreateNSWSub - DEFINE_HELPERS(Sub, NUW) // CreateNUWSub - DEFINE_HELPERS(Mul, NSW) // CreateNSWMul - DEFINE_HELPERS(Mul, NUW) // CreateNUWMul - DEFINE_HELPERS(Shl, NSW) // CreateNSWShl - DEFINE_HELPERS(Shl, NUW) // CreateNUWShl + +#define DEFINE_HELPERS(OPC, NUWNSWEXACT) \ + static BinaryOperator *Create##NUWNSWEXACT##OPC(Value *V1, Value *V2, \ + const Twine &Name = "") { \ + return Create##NUWNSWEXACT(Instruction::OPC, V1, V2, Name); \ + } \ + static BinaryOperator *Create##NUWNSWEXACT##OPC( \ + Value *V1, Value *V2, const Twine &Name, BasicBlock *BB) { \ + return Create##NUWNSWEXACT(Instruction::OPC, V1, V2, Name, BB); \ + } \ + static BinaryOperator *Create##NUWNSWEXACT##OPC( \ + Value *V1, Value *V2, const Twine &Name, Instruction *I) { \ + return Create##NUWNSWEXACT(Instruction::OPC, V1, V2, Name, I); \ + } + + DEFINE_HELPERS(Add, NSW) // CreateNSWAdd + DEFINE_HELPERS(Add, NUW) // CreateNUWAdd + DEFINE_HELPERS(Sub, NSW) // CreateNSWSub + DEFINE_HELPERS(Sub, NUW) // CreateNUWSub + DEFINE_HELPERS(Mul, NSW) // CreateNSWMul + DEFINE_HELPERS(Mul, NUW) // CreateNUWMul + DEFINE_HELPERS(Shl, NSW) // CreateNSWShl + DEFINE_HELPERS(Shl, NUW) // CreateNUWShl DEFINE_HELPERS(SDiv, Exact) // CreateExactSDiv DEFINE_HELPERS(UDiv, Exact) // CreateExactUDiv @@ -471,7 +472,7 @@ public: DEFINE_HELPERS(LShr, Exact) // CreateExactLShr #undef DEFINE_HELPERS - + /// Helper functions to construct and inspect unary operations (NEG and NOT) /// via binary operators SUB and XOR: /// @@ -549,7 +550,7 @@ public: /// Convenience method to copy supported wrapping, exact, and fast-math flags /// from V to this instruction. void copyIRFlags(const Value *V); - + /// Logical 'and' of any supported wrapping, exact, and fast-math flags of /// V and this instruction. void andIRFlags(const Value *V); @@ -582,6 +583,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value) /// @brief Base class of casting instructions. class CastInst : public UnaryInstruction { void anchor() override; + protected: /// @brief Constructor with insert-before-instruction semantics for subclasses CastInst(Type *Ty, unsigned iType, Value *S, @@ -595,6 +597,7 @@ protected: : UnaryInstruction(Ty, iType, S, InsertAtEnd) { setName(NameStr); } + public: /// Provides a way to construct any of the CastInst subclasses using an /// opcode instead of the subclass's constructor. The opcode must be in the @@ -684,7 +687,7 @@ public: Value *S, ///< The pointer value to be casted (operand 0) Type *Ty, ///< The type to which cast should be made const Twine &Name = "", ///< Name for the instruction - Instruction *InsertBefore = 0 ///< Place to insert the instruction + Instruction *InsertBefore = nullptr ///< Place to insert the instruction ); /// @brief Create a BitCast, a PtrToInt, or an IntToPTr cast instruction. @@ -697,7 +700,7 @@ public: Value *S, ///< The pointer value to be casted (operand 0) Type *Ty, ///< The type to which cast should be made const Twine &Name = "", ///< Name for the instruction - Instruction *InsertBefore = 0 ///< Place to insert the instruction + Instruction *InsertBefore = nullptr ///< Place to insert the instruction ); /// @brief Create a ZExt, BitCast, or Trunc for int -> int casts. @@ -871,18 +874,6 @@ public: /// This class is the base class for the comparison instructions. /// @brief Abstract base class of comparison instructions. class CmpInst : public Instruction { - void *operator new(size_t, unsigned) = delete; - CmpInst() = delete; -protected: - CmpInst(Type *ty, Instruction::OtherOps op, unsigned short pred, - Value *LHS, Value *RHS, const Twine &Name = "", - Instruction *InsertBefore = nullptr); - - CmpInst(Type *ty, Instruction::OtherOps op, unsigned short pred, - Value *LHS, Value *RHS, const Twine &Name, - BasicBlock *InsertAtEnd); - - void anchor() override; // Out of line virtual method. public: /// This enumeration lists the possible predicates for CmpInst subclasses. /// Values in the range 0-31 are reserved for FCmpInst, while values in the @@ -924,6 +915,22 @@ public: BAD_ICMP_PREDICATE = ICMP_SLE + 1 }; +private: + void *operator new(size_t, unsigned) = delete; + CmpInst() = delete; + +protected: + CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred, + Value *LHS, Value *RHS, const Twine &Name = "", + Instruction *InsertBefore = nullptr); + + CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred, + Value *LHS, Value *RHS, const Twine &Name, + BasicBlock *InsertAtEnd); + + void anchor() override; // Out of line virtual method. + +public: // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); @@ -934,7 +941,7 @@ public: /// The specified Instruction is allowed to be a dereferenced end iterator. /// @brief Create a CmpInst static CmpInst *Create(OtherOps Op, - unsigned short predicate, Value *S1, + Predicate predicate, Value *S1, Value *S2, const Twine &Name = "", Instruction *InsertBefore = nullptr); @@ -942,7 +949,7 @@ public: /// two operands. Also automatically insert this instruction to the end of /// the BasicBlock specified. /// @brief Create a CmpInst - static CmpInst *Create(OtherOps Op, unsigned short predicate, Value *S1, + static CmpInst *Create(OtherOps Op, Predicate predicate, Value *S1, Value *S2, const Twine &Name, BasicBlock *InsertAtEnd); /// @brief Get the opcode casted to the right type @@ -969,7 +976,6 @@ public: bool isFPPredicate() const { return isFPPredicate(getPredicate()); } bool isIntPredicate() const { return isIntPredicate(getPredicate()); } - /// For example, EQ -> NE, UGT -> ULE, SLT -> SGE, /// OEQ -> UNE, UGT -> OLE, OLT -> UGE, etc. /// @returns the inverse predicate for the instruction's current predicate. @@ -1027,6 +1033,19 @@ public: return isUnsigned(getPredicate()); } + /// For example, ULT->SLT, ULE->SLE, UGT->SGT, UGE->SGE, SLT->Failed assert + /// @returns the signed version of the unsigned predicate pred. + /// @brief return the signed version of a predicate + static Predicate getSignedPredicate(Predicate pred); + + /// For example, ULT->SLT, ULE->SLE, UGT->SGT, UGE->SGE, SLT->Failed assert + /// @returns the signed version of the predicate for this instruction (which + /// has to be an unsigned predicate). + /// @brief return the signed version of a predicate + Predicate getSignedPredicate() { + return getSignedPredicate(getPredicate()); + } + /// This is just a convenience. /// @brief Determine if this is true when both operands are the same. bool isTrueWhenEqual() const { @@ -1041,23 +1060,23 @@ public: /// @returns true if the predicate is unsigned, false otherwise. /// @brief Determine if the predicate is an unsigned operation. - static bool isUnsigned(unsigned short predicate); + static bool isUnsigned(Predicate predicate); /// @returns true if the predicate is signed, false otherwise. /// @brief Determine if the predicate is an signed operation. - static bool isSigned(unsigned short predicate); + static bool isSigned(Predicate predicate); /// @brief Determine if the predicate is an ordered operation. - static bool isOrdered(unsigned short predicate); + static bool isOrdered(Predicate predicate); /// @brief Determine if the predicate is an unordered operation. - static bool isUnordered(unsigned short predicate); + static bool isUnordered(Predicate predicate); /// Determine if the predicate is true when comparing a value with itself. - static bool isTrueWhenEqual(unsigned short predicate); + static bool isTrueWhenEqual(Predicate predicate); /// Determine if the predicate is false when comparing a value with itself. - static bool isFalseWhenEqual(unsigned short predicate); + static bool isFalseWhenEqual(Predicate predicate); /// @brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { @@ -1076,6 +1095,7 @@ public: } return Type::getInt1Ty(opnd_type->getContext()); } + private: // Shadow Value::setValueSubclassData with a private forwarding method so that // subclasses cannot accidentally use it. @@ -1084,7 +1104,6 @@ private: } }; - // FIXME: these are redundant if CmpInst < BinaryOperator template <> struct OperandTraits : public FixedNumOperandTraits { @@ -1092,6 +1111,523 @@ struct OperandTraits : public FixedNumOperandTraits { DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CmpInst, Value) -} // End llvm namespace +//===----------------------------------------------------------------------===// +// FuncletPadInst Class +//===----------------------------------------------------------------------===// +class FuncletPadInst : public Instruction { +private: + void init(Value *ParentPad, ArrayRef Args, const Twine &NameStr); + + FuncletPadInst(const FuncletPadInst &CPI); + + explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad, + ArrayRef Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore); + explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad, + ArrayRef Args, unsigned Values, + const Twine &NameStr, BasicBlock *InsertAtEnd); + +protected: + // Note: Instruction needs to be a friend here to call cloneImpl. + friend class Instruction; + friend class CatchPadInst; + friend class CleanupPadInst; + FuncletPadInst *cloneImpl() const; + +public: + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + + /// getNumArgOperands - Return the number of funcletpad arguments. + /// + unsigned getNumArgOperands() const { return getNumOperands() - 1; } + + /// Convenience accessors + + /// \brief 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 { return Op<-1>(); } + void setParentPad(Value *ParentPad) { + assert(ParentPad); + Op<-1>() = ParentPad; + } + + /// getArgOperand/setArgOperand - Return/set the i-th funcletpad argument. + /// + Value *getArgOperand(unsigned i) const { return getOperand(i); } + void setArgOperand(unsigned i, Value *v) { setOperand(i, v); } + + /// arg_operands - iteration adapter for range-for loops. + op_range arg_operands() { return op_range(op_begin(), op_end() - 1); } + + /// arg_operands - iteration adapter for range-for loops. + const_op_range arg_operands() const { + return const_op_range(op_begin(), op_end() - 1); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Instruction *I) { return I->isFuncletPad(); } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +template <> +struct OperandTraits + : public VariadicOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(FuncletPadInst, Value) + +/// \brief A lightweight accessor for an operand bundle meant to be passed +/// around by value. +struct OperandBundleUse { + ArrayRef Inputs; + + OperandBundleUse() {} + explicit OperandBundleUse(StringMapEntry *Tag, ArrayRef Inputs) + : Inputs(Inputs), Tag(Tag) {} + + /// \brief Return true if the operand at index \p Idx in this operand bundle + /// has the attribute A. + bool operandHasAttr(unsigned Idx, Attribute::AttrKind A) const { + if (isDeoptOperandBundle()) + if (A == Attribute::ReadOnly || A == Attribute::NoCapture) + return Inputs[Idx]->getType()->isPointerTy(); + + // Conservative answer: no operands have any attributes. + return false; + }; + + /// \brief Return the tag of this operand bundle as a string. + StringRef getTagName() const { + return Tag->getKey(); + } + + /// \brief Return the tag of this operand bundle as an integer. + /// + /// Operand bundle tags are interned by LLVMContextImpl::getOrInsertBundleTag, + /// and this function returns the unique integer getOrInsertBundleTag + /// associated the tag of this operand bundle to. + uint32_t getTagID() const { + return Tag->getValue(); + } + + /// \brief Return true if this is a "deopt" operand bundle. + bool isDeoptOperandBundle() const { + return getTagID() == LLVMContext::OB_deopt; + } + + /// \brief Return true if this is a "funclet" operand bundle. + bool isFuncletOperandBundle() const { + return getTagID() == LLVMContext::OB_funclet; + } + +private: + /// \brief Pointer to an entry in LLVMContextImpl::getOrInsertBundleTag. + StringMapEntry *Tag; +}; + +/// \brief A container for an operand bundle being viewed as a set of values +/// rather than a set of uses. +/// +/// Unlike OperandBundleUse, OperandBundleDefT owns the memory it carries, and +/// so it is possible to create and pass around "self-contained" instances of +/// OperandBundleDef and ConstOperandBundleDef. +template class OperandBundleDefT { + std::string Tag; + std::vector Inputs; + +public: + explicit OperandBundleDefT(std::string Tag, std::vector Inputs) + : Tag(std::move(Tag)), Inputs(std::move(Inputs)) {} + explicit OperandBundleDefT(std::string Tag, ArrayRef Inputs) + : Tag(std::move(Tag)), Inputs(Inputs) {} + + explicit OperandBundleDefT(const OperandBundleUse &OBU) { + Tag = OBU.getTagName(); + Inputs.insert(Inputs.end(), OBU.Inputs.begin(), OBU.Inputs.end()); + } + + ArrayRef inputs() const { return Inputs; } + + typedef typename std::vector::const_iterator input_iterator; + size_t input_size() const { return Inputs.size(); } + input_iterator input_begin() const { return Inputs.begin(); } + input_iterator input_end() const { return Inputs.end(); } + + StringRef getTag() const { return Tag; } +}; + +typedef OperandBundleDefT OperandBundleDef; +typedef OperandBundleDefT ConstOperandBundleDef; + +/// \brief A mixin to add operand bundle functionality to llvm instruction +/// classes. +/// +/// OperandBundleUser uses the descriptor area co-allocated with the host User +/// to store some meta information about which operands are "normal" operands, +/// and which ones belong to some operand bundle. +/// +/// The layout of an operand bundle user is +/// +/// +-----------uint32_t End-------------------------------------+ +/// | | +/// | +--------uint32_t Begin--------------------+ | +/// | | | | +/// ^ ^ v v +/// |------|------|----|----|----|----|----|---------|----|---------|----|----- +/// | BOI0 | BOI1 | .. | DU | U0 | U1 | .. | BOI0_U0 | .. | BOI1_U0 | .. | Un +/// |------|------|----|----|----|----|----|---------|----|---------|----|----- +/// v v ^ ^ +/// | | | | +/// | +--------uint32_t Begin------------+ | +/// | | +/// +-----------uint32_t End-----------------------------+ +/// +/// +/// BOI0, BOI1 ... are descriptions of operand bundles in this User's use list. +/// These descriptions are installed and managed by this class, and they're all +/// instances of OperandBundleUser::BundleOpInfo. +/// +/// DU is an additional descriptor installed by User's 'operator new' to keep +/// track of the 'BOI0 ... BOIN' co-allocation. OperandBundleUser does not +/// access or modify DU in any way, it's an implementation detail private to +/// User. +/// +/// The regular Use& vector for the User starts at U0. The operand bundle uses +/// are part of the Use& vector, just like normal uses. In the diagram above, +/// the operand bundle uses start at BOI0_U0. Each instance of BundleOpInfo has +/// information about a contiguous set of uses constituting an operand bundle, +/// and the total set of operand bundle uses themselves form a contiguous set of +/// uses (i.e. there are no gaps between uses corresponding to individual +/// operand bundles). +/// +/// This class does not know the location of the set of operand bundle uses +/// within the use list -- that is decided by the User using this class via the +/// BeginIdx argument in populateBundleOperandInfos. +/// +/// Currently operand bundle users with hung-off operands are not supported. +template class OperandBundleUser { +public: + /// \brief Return the number of operand bundles associated with this User. + unsigned getNumOperandBundles() const { + return std::distance(bundle_op_info_begin(), bundle_op_info_end()); + } + + /// \brief Return true if this User has any operand bundles. + bool hasOperandBundles() const { return getNumOperandBundles() != 0; } + + /// \brief Return the index of the first bundle operand in the Use array. + unsigned getBundleOperandsStartIndex() const { + assert(hasOperandBundles() && "Don't call otherwise!"); + return bundle_op_info_begin()->Begin; + } + + /// \brief Return the index of the last bundle operand in the Use array. + unsigned getBundleOperandsEndIndex() const { + assert(hasOperandBundles() && "Don't call otherwise!"); + return bundle_op_info_end()[-1].End; + } + + /// \brief Return the total number operands (not operand bundles) used by + /// every operand bundle in this OperandBundleUser. + unsigned getNumTotalBundleOperands() const { + if (!hasOperandBundles()) + return 0; + + unsigned Begin = getBundleOperandsStartIndex(); + unsigned End = getBundleOperandsEndIndex(); + + assert(Begin <= End && "Should be!"); + return End - Begin; + } + + /// \brief Return the operand bundle at a specific index. + OperandBundleUse getOperandBundleAt(unsigned Index) const { + assert(Index < getNumOperandBundles() && "Index out of bounds!"); + return operandBundleFromBundleOpInfo(*(bundle_op_info_begin() + Index)); + } + + /// \brief Return the number of operand bundles with the tag Name attached to + /// this instruction. + unsigned countOperandBundlesOfType(StringRef Name) const { + unsigned Count = 0; + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) + if (getOperandBundleAt(i).getTagName() == Name) + Count++; + + return Count; + } + + /// \brief Return the number of operand bundles with the tag ID attached to + /// this instruction. + unsigned countOperandBundlesOfType(uint32_t ID) const { + unsigned Count = 0; + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) + if (getOperandBundleAt(i).getTagID() == ID) + Count++; + + return Count; + } + + /// \brief Return an operand bundle by name, if present. + /// + /// It is an error to call this for operand bundle types that may have + /// multiple instances of them on the same instruction. + Optional getOperandBundle(StringRef Name) const { + assert(countOperandBundlesOfType(Name) < 2 && "Precondition violated!"); + + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) { + OperandBundleUse U = getOperandBundleAt(i); + if (U.getTagName() == Name) + return U; + } + + return None; + } + + /// \brief Return an operand bundle by tag ID, if present. + /// + /// It is an error to call this for operand bundle types that may have + /// multiple instances of them on the same instruction. + Optional getOperandBundle(uint32_t ID) const { + assert(countOperandBundlesOfType(ID) < 2 && "Precondition violated!"); + + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) { + OperandBundleUse U = getOperandBundleAt(i); + if (U.getTagID() == ID) + return U; + } + + return None; + } + + /// \brief Return the list of operand bundles attached to this instruction as + /// a vector of OperandBundleDefs. + /// + /// This function copies the OperandBundeUse instances associated with this + /// OperandBundleUser to a vector of OperandBundleDefs. Note: + /// OperandBundeUses and OperandBundleDefs are non-trivially *different* + /// representations of operand bundles (see documentation above). + void getOperandBundlesAsDefs(SmallVectorImpl &Defs) const { + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) + Defs.emplace_back(getOperandBundleAt(i)); + } + + /// \brief Return the operand bundle for the operand at index OpIdx. + /// + /// It is an error to call this with an OpIdx that does not correspond to an + /// bundle operand. + OperandBundleUse getOperandBundleForOperand(unsigned OpIdx) const { + return operandBundleFromBundleOpInfo(getBundleOpInfoForOperand(OpIdx)); + } + + /// \brief Return true if this operand bundle user has operand bundles that + /// may read from the heap. + bool hasReadingOperandBundles() const { + // Implementation note: this is a conservative implementation of operand + // bundle semantics, where *any* operand bundle forces a callsite to be at + // least readonly. + return hasOperandBundles(); + } + + /// \brief Return true if this operand bundle user has operand bundles that + /// may write to the heap. + bool hasClobberingOperandBundles() const { + for (auto &BOI : bundle_op_infos()) { + if (BOI.Tag->second == LLVMContext::OB_deopt || + BOI.Tag->second == LLVMContext::OB_funclet) + continue; + + // This instruction has an operand bundle that is not known to us. + // Assume the worst. + return true; + } + + return false; + } + + /// \brief Return true if the bundle operand at index \p OpIdx has the + /// attribute \p A. + bool bundleOperandHasAttr(unsigned OpIdx, Attribute::AttrKind A) const { + auto &BOI = getBundleOpInfoForOperand(OpIdx); + auto OBU = operandBundleFromBundleOpInfo(BOI); + return OBU.operandHasAttr(OpIdx - BOI.Begin, A); + } + + /// \brief Return true if \p Other has the same sequence of operand bundle + /// tags with the same number of operands on each one of them as this + /// OperandBundleUser. + bool hasIdenticalOperandBundleSchema( + const OperandBundleUser &Other) const { + if (getNumOperandBundles() != Other.getNumOperandBundles()) + return false; + + return std::equal(bundle_op_info_begin(), bundle_op_info_end(), + Other.bundle_op_info_begin()); + }; + +protected: + /// \brief Is the function attribute S disallowed by some operand bundle on + /// this operand bundle user? + bool isFnAttrDisallowedByOpBundle(StringRef S) const { + // Operand bundles only possibly disallow readnone, readonly and argmenonly + // attributes. All String attributes are fine. + return false; + } + + /// \brief Is the function attribute A disallowed by some operand bundle on + /// this operand bundle user? + bool isFnAttrDisallowedByOpBundle(Attribute::AttrKind A) const { + switch (A) { + default: + return false; + + case Attribute::ArgMemOnly: + return hasReadingOperandBundles(); + + case Attribute::ReadNone: + return hasReadingOperandBundles(); + + case Attribute::ReadOnly: + return hasClobberingOperandBundles(); + } + + llvm_unreachable("switch has a default case!"); + } + + /// \brief Used to keep track of an operand bundle. See the main comment on + /// OperandBundleUser above. + struct BundleOpInfo { + /// \brief The operand bundle tag, interned by + /// LLVMContextImpl::getOrInsertBundleTag. + StringMapEntry *Tag; + + /// \brief The index in the Use& vector where operands for this operand + /// bundle starts. + uint32_t Begin; + + /// \brief The index in the Use& vector where operands for this operand + /// bundle ends. + uint32_t End; + + bool operator==(const BundleOpInfo &Other) const { + return Tag == Other.Tag && Begin == Other.Begin && End == Other.End; + } + }; + + /// \brief Simple helper function to map a BundleOpInfo to an + /// OperandBundleUse. + OperandBundleUse + operandBundleFromBundleOpInfo(const BundleOpInfo &BOI) const { + auto op_begin = static_cast(this)->op_begin(); + ArrayRef Inputs(op_begin + BOI.Begin, op_begin + BOI.End); + return OperandBundleUse(BOI.Tag, Inputs); + } + + typedef BundleOpInfo *bundle_op_iterator; + typedef const BundleOpInfo *const_bundle_op_iterator; + + /// \brief Return the start of the list of BundleOpInfo instances associated + /// with this OperandBundleUser. + bundle_op_iterator bundle_op_info_begin() { + if (!static_cast(this)->hasDescriptor()) + return nullptr; + + uint8_t *BytesBegin = static_cast(this)->getDescriptor().begin(); + return reinterpret_cast(BytesBegin); + } + + /// \brief Return the start of the list of BundleOpInfo instances associated + /// with this OperandBundleUser. + const_bundle_op_iterator bundle_op_info_begin() const { + auto *NonConstThis = + const_cast *>(this); + return NonConstThis->bundle_op_info_begin(); + } + + /// \brief Return the end of the list of BundleOpInfo instances associated + /// with this OperandBundleUser. + bundle_op_iterator bundle_op_info_end() { + if (!static_cast(this)->hasDescriptor()) + return nullptr; + + uint8_t *BytesEnd = static_cast(this)->getDescriptor().end(); + return reinterpret_cast(BytesEnd); + } + + /// \brief Return the end of the list of BundleOpInfo instances associated + /// with this OperandBundleUser. + const_bundle_op_iterator bundle_op_info_end() const { + auto *NonConstThis = + const_cast *>(this); + return NonConstThis->bundle_op_info_end(); + } + + /// \brief Return the range [\p bundle_op_info_begin, \p bundle_op_info_end). + iterator_range bundle_op_infos() { + return make_range(bundle_op_info_begin(), bundle_op_info_end()); + } + + /// \brief Return the range [\p bundle_op_info_begin, \p bundle_op_info_end). + iterator_range bundle_op_infos() const { + return make_range(bundle_op_info_begin(), bundle_op_info_end()); + } + + /// \brief Populate the BundleOpInfo instances and the Use& vector from \p + /// Bundles. Return the op_iterator pointing to the Use& one past the last + /// last bundle operand use. + /// + /// Each \p OperandBundleDef instance is tracked by a OperandBundleInfo + /// instance allocated in this User's descriptor. + OpIteratorTy populateBundleOperandInfos(ArrayRef Bundles, + const unsigned BeginIndex) { + auto It = static_cast(this)->op_begin() + BeginIndex; + for (auto &B : Bundles) + It = std::copy(B.input_begin(), B.input_end(), It); + + auto *ContextImpl = static_cast(this)->getContext().pImpl; + auto BI = Bundles.begin(); + unsigned CurrentIndex = BeginIndex; + + for (auto &BOI : bundle_op_infos()) { + assert(BI != Bundles.end() && "Incorrect allocation?"); + + BOI.Tag = ContextImpl->getOrInsertBundleTag(BI->getTag()); + BOI.Begin = CurrentIndex; + BOI.End = CurrentIndex + BI->input_size(); + CurrentIndex = BOI.End; + BI++; + } + + assert(BI == Bundles.end() && "Incorrect allocation?"); + + return It; + } + + /// \brief Return the BundleOpInfo for the operand at index OpIdx. + /// + /// It is an error to call this with an OpIdx that does not correspond to an + /// bundle operand. + const BundleOpInfo &getBundleOpInfoForOperand(unsigned OpIdx) const { + for (auto &BOI : bundle_op_infos()) + if (BOI.Begin <= OpIdx && OpIdx < BOI.End) + return BOI; + + llvm_unreachable("Did not find operand bundle for operand!"); + } + + /// \brief Return the total number of values used in \p Bundles. + static unsigned CountBundleInputs(ArrayRef Bundles) { + unsigned Total = 0; + for (auto &B : Bundles) + Total += B.input_size(); + return Total; + } +}; + +} // end llvm namespace -#endif +#endif // LLVM_IR_INSTRTYPES_H