diff options
Diffstat (limited to 'include/llvm/IR')
58 files changed, 3390 insertions, 1265 deletions
diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h index d8b280a66f18..6fc1dd2f285a 100644 --- a/include/llvm/IR/Argument.h +++ b/include/llvm/IR/Argument.h @@ -21,127 +21,110 @@ namespace llvm { -template <typename NodeTy> class SymbolTableListTraits; - -/// \brief LLVM Argument representation -/// /// This class represents an incoming formal argument to a Function. A formal /// argument, since it is ``formal'', does not contain an actual value but /// instead represents the type, argument number, and attributes of an argument /// for a specific function. When used in the body of said function, the /// argument of course represents the value of the actual argument that the /// function was called with. -class Argument : public Value, public ilist_node<Argument> { +class Argument : public Value { virtual void anchor(); Function *Parent; + unsigned ArgNo; - friend class SymbolTableListTraits<Argument>; + friend class Function; void setParent(Function *parent); public: - /// \brief Constructor. - /// - /// If \p F is specified, the argument is inserted at the end of the argument - /// list for \p F. - explicit Argument(Type *Ty, const Twine &Name = "", Function *F = nullptr); + /// Argument constructor. + explicit Argument(Type *Ty, const Twine &Name = "", Function *F = nullptr, + unsigned ArgNo = 0); inline const Function *getParent() const { return Parent; } inline Function *getParent() { return Parent; } - /// \brief Return the index of this formal argument in its containing - /// function. + /// Return the index of this formal argument in its containing function. /// /// For example in "void foo(int a, float b)" a is 0 and b is 1. - unsigned getArgNo() const; + unsigned getArgNo() const { + assert(Parent && "can't get number of unparented arg"); + return ArgNo; + } - /// \brief Return true if this argument has the nonnull attribute on it in - /// its containing function. Also returns true if at least one byte is known - /// to be dereferenceable and the pointer is in addrspace(0). + /// Return true if this argument has the nonnull attribute. Also returns true + /// if at least one byte is known to be dereferenceable and the pointer is in + /// addrspace(0). bool hasNonNullAttr() const; - /// \brief If this argument has the dereferenceable attribute on it in its - /// containing function, return the number of bytes known to be - /// dereferenceable. Otherwise, zero is returned. + /// If this argument has the dereferenceable attribute, return the number of + /// bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableBytes() const; - /// \brief If this argument has the dereferenceable_or_null attribute on - /// it in its containing function, return the number of bytes known to be - /// dereferenceable. Otherwise, zero is returned. + /// If this argument has the dereferenceable_or_null attribute, return the + /// number of bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableOrNullBytes() const; - /// \brief Return true if this argument has the byval attribute on it in its - /// containing function. + /// Return true if this argument has the byval attribute. bool hasByValAttr() const; - /// \brief Return true if this argument has the swiftself attribute. + /// Return true if this argument has the swiftself attribute. bool hasSwiftSelfAttr() const; - /// \brief Return true if this argument has the swifterror attribute. + /// Return true if this argument has the swifterror attribute. bool hasSwiftErrorAttr() const; - /// \brief Return true if this argument has the byval attribute or inalloca - /// attribute on it in its containing function. These attributes both - /// represent arguments being passed by value. + /// Return true if this argument has the byval attribute or inalloca + /// attribute. These attributes represent arguments being passed by value. bool hasByValOrInAllocaAttr() const; - /// \brief If this is a byval or inalloca argument, return its alignment. + /// If this is a byval or inalloca argument, return its alignment. unsigned getParamAlignment() const; - /// \brief Return true if this argument has the nest attribute on it in its - /// containing function. + /// Return true if this argument has the nest attribute. bool hasNestAttr() const; - /// \brief Return true if this argument has the noalias attribute on it in its - /// containing function. + /// Return true if this argument has the noalias attribute. bool hasNoAliasAttr() const; - /// \brief Return true if this argument has the nocapture attribute on it in - /// its containing function. + /// Return true if this argument has the nocapture attribute. bool hasNoCaptureAttr() const; - /// \brief Return true if this argument has the sret attribute on it in its - /// containing function. + /// Return true if this argument has the sret attribute. bool hasStructRetAttr() const; - /// \brief Return true if this argument has the returned attribute on it in - /// its containing function. + /// Return true if this argument has the returned attribute. bool hasReturnedAttr() const; - /// \brief Return true if this argument has the readonly or readnone attribute - /// on it in its containing function. + /// Return true if this argument has the readonly or readnone attribute. bool onlyReadsMemory() const; - /// \brief Return true if this argument has the inalloca attribute on it in - /// its containing function. + /// Return true if this argument has the inalloca attribute. bool hasInAllocaAttr() const; - /// \brief Return true if this argument has the zext attribute on it in its - /// containing function. + /// Return true if this argument has the zext attribute. bool hasZExtAttr() const; - /// \brief Return true if this argument has the sext attribute on it in its - /// containing function. + /// Return true if this argument has the sext attribute. bool hasSExtAttr() const; - /// \brief Add a Attribute to an argument. - void addAttr(AttributeSet AS); + /// Add attributes to an argument. + void addAttr(AttributeList AS); void addAttr(Attribute::AttrKind Kind) { - addAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + addAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind)); } - /// \brief Remove a Attribute from an argument. - void removeAttr(AttributeSet AS); + /// Remove attributes from an argument. + void removeAttr(AttributeList AS); void removeAttr(Attribute::AttrKind Kind) { - removeAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + removeAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind)); } - /// \brief Checks if an argument has a given attribute. + /// Check if an argument has a given attribute. bool hasAttribute(Attribute::AttrKind Kind) const; - /// \brief Method for support type inquiry through isa, cast, and - /// dyn_cast. + /// Method for support type inquiry through isa, cast, and dyn_cast. static inline bool classof(const Value *V) { return V->getValueID() == ArgumentVal; } diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 15783858dd32..121f57a433ac 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -1,4 +1,4 @@ -//===-- llvm/Attributes.h - Container for Attributes ------------*- C++ -*-===// +//===- llvm/Attributes.h - Container for Attributes -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,22 +18,24 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" -#include "llvm/Support/Compiler.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm-c/Types.h" #include <bitset> #include <cassert> +#include <cstdint> #include <map> #include <string> +#include <utility> namespace llvm { class AttrBuilder; class AttributeImpl; -class AttributeSetImpl; +class AttributeListImpl; class AttributeSetNode; -class Constant; template<typename T> struct DenseMapInfo; class Function; class LLVMContext; @@ -73,11 +75,12 @@ public: }; private: - AttributeImpl *pImpl; + AttributeImpl *pImpl = nullptr; + Attribute(AttributeImpl *A) : pImpl(A) {} public: - Attribute() : pImpl(nullptr) {} + Attribute() = default; //===--------------------------------------------------------------------===// // Attribute Construction @@ -194,13 +197,91 @@ inline Attribute unwrap(LLVMAttributeRef Attr) { //===----------------------------------------------------------------------===// /// \class +/// This class holds the attributes for a particular argument, parameter, +/// function, or return value. It is an immutable value type that is cheap to +/// copy. Adding and removing enum attributes is intended to be fast, but adding +/// and removing string or integer attributes involves a FoldingSet lookup. +class AttributeSet { + // TODO: Extract AvailableAttrs from AttributeSetNode and store them here. + // This will allow an efficient implementation of addAttribute and + // removeAttribute for enum attrs. + + /// Private implementation pointer. + AttributeSetNode *SetNode = nullptr; + + friend AttributeListImpl; + template <typename Ty> friend struct DenseMapInfo; + +private: + explicit AttributeSet(AttributeSetNode *ASN) : SetNode(ASN) {} + +public: + /// AttributeSet is a trivially copyable value type. + AttributeSet() = default; + AttributeSet(const AttributeSet &) = default; + ~AttributeSet() = default; + + static AttributeSet get(LLVMContext &C, const AttrBuilder &B); + static AttributeSet get(LLVMContext &C, ArrayRef<Attribute> Attrs); + + bool operator==(const AttributeSet &O) { return SetNode == O.SetNode; } + bool operator!=(const AttributeSet &O) { return !(*this == O); } + + unsigned getNumAttributes() const; + + bool hasAttributes() const { return SetNode != nullptr; } + + bool hasAttribute(Attribute::AttrKind Kind) const; + bool hasAttribute(StringRef Kind) const; + + Attribute getAttribute(Attribute::AttrKind Kind) const; + Attribute getAttribute(StringRef Kind) const; + + unsigned getAlignment() const; + unsigned getStackAlignment() const; + uint64_t getDereferenceableBytes() const; + uint64_t getDereferenceableOrNullBytes() const; + std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; + std::string getAsString(bool InAttrGrp = false) const; + + typedef const Attribute *iterator; + iterator begin() const; + iterator end() const; +}; + +//===----------------------------------------------------------------------===// +/// \class +/// \brief Provide DenseMapInfo for AttributeSet. +template <> struct DenseMapInfo<AttributeSet> { + static inline AttributeSet getEmptyKey() { + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<void *>::NumLowBitsAvailable; + return AttributeSet(reinterpret_cast<AttributeSetNode *>(Val)); + } + + static inline AttributeSet getTombstoneKey() { + uintptr_t Val = static_cast<uintptr_t>(-2); + Val <<= PointerLikeTypeTraits<void *>::NumLowBitsAvailable; + return AttributeSet(reinterpret_cast<AttributeSetNode *>(Val)); + } + + static unsigned getHashValue(AttributeSet AS) { + return (unsigned((uintptr_t)AS.SetNode) >> 4) ^ + (unsigned((uintptr_t)AS.SetNode) >> 9); + } + + static bool isEqual(AttributeSet LHS, AttributeSet RHS) { return LHS == RHS; } +}; + +//===----------------------------------------------------------------------===// +/// \class /// \brief This class holds the attributes for a function, its return value, and /// its parameters. You access the attributes for each of them via an index into -/// the AttributeSet object. The function attributes are at index -/// `AttributeSet::FunctionIndex', the return value is at index -/// `AttributeSet::ReturnIndex', and the attributes for the parameters start at +/// the AttributeList object. The function attributes are at index +/// `AttributeList::FunctionIndex', the return value is at index +/// `AttributeList::ReturnIndex', and the attributes for the parameters start at /// index `1'. -class AttributeSet { +class AttributeList { public: enum AttrIndex : unsigned { ReturnIndex = 0U, @@ -209,115 +290,137 @@ public: private: friend class AttrBuilder; - friend class AttributeSetImpl; + friend class AttributeListImpl; + friend class AttributeSet; friend class AttributeSetNode; + template <typename Ty> friend struct DenseMapInfo; /// \brief The attributes that we are managing. This can be null to represent /// the empty attributes list. - AttributeSetImpl *pImpl; - - /// \brief The attributes for the specified index are returned. - AttributeSetNode *getAttributes(unsigned Index) const; - - /// \brief Create an AttributeSet with the specified parameters in it. - static AttributeSet get(LLVMContext &C, - ArrayRef<std::pair<unsigned, Attribute> > Attrs); - static AttributeSet get(LLVMContext &C, - ArrayRef<std::pair<unsigned, - AttributeSetNode*> > Attrs); + AttributeListImpl *pImpl = nullptr; - static AttributeSet getImpl(LLVMContext &C, - ArrayRef<std::pair<unsigned, - AttributeSetNode*> > Attrs); +public: + /// \brief Create an AttributeList with the specified parameters in it. + static AttributeList get(LLVMContext &C, + ArrayRef<std::pair<unsigned, Attribute>> Attrs); + static AttributeList + get(LLVMContext &C, ArrayRef<std::pair<unsigned, AttributeSet>> Attrs); + + /// \brief Create an AttributeList from attribute sets for a function, its + /// return value, and all of its arguments. + static AttributeList get(LLVMContext &C, AttributeSet FnAttrs, + AttributeSet RetAttrs, + ArrayRef<AttributeSet> ArgAttrs); + + static AttributeList + getImpl(LLVMContext &C, + ArrayRef<std::pair<unsigned, AttributeSet>> Attrs); - explicit AttributeSet(AttributeSetImpl *LI) : pImpl(LI) {} +private: + explicit AttributeList(AttributeListImpl *LI) : pImpl(LI) {} public: - AttributeSet() : pImpl(nullptr) {} + AttributeList() = default; //===--------------------------------------------------------------------===// - // AttributeSet Construction and Mutation + // AttributeList Construction and Mutation //===--------------------------------------------------------------------===// - /// \brief Return an AttributeSet with the specified parameters in it. - static AttributeSet get(LLVMContext &C, ArrayRef<AttributeSet> Attrs); - static AttributeSet get(LLVMContext &C, unsigned Index, - ArrayRef<Attribute::AttrKind> Kinds); - static AttributeSet get(LLVMContext &C, unsigned Index, - ArrayRef<StringRef> Kind); - static AttributeSet get(LLVMContext &C, unsigned Index, const AttrBuilder &B); + /// \brief Return an AttributeList with the specified parameters in it. + static AttributeList get(LLVMContext &C, ArrayRef<AttributeList> Attrs); + static AttributeList get(LLVMContext &C, unsigned Index, + ArrayRef<Attribute::AttrKind> Kinds); + static AttributeList get(LLVMContext &C, unsigned Index, + ArrayRef<StringRef> Kind); + static AttributeList get(LLVMContext &C, unsigned Index, + const AttrBuilder &B); /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Kind) const; + AttributeList addAttribute(LLVMContext &C, unsigned Index, + Attribute::AttrKind Kind) const; /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, - StringRef Value = StringRef()) const; + AttributeList addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, + StringRef Value = StringRef()) const; /// Add an attribute to the attribute set at the given indices. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, ArrayRef<unsigned> Indices, - Attribute A) const; + AttributeList addAttribute(LLVMContext &C, ArrayRef<unsigned> Indices, + Attribute A) const; /// \brief Add attributes to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttributes(LLVMContext &C, unsigned Index, - AttributeSet Attrs) const; + AttributeList addAttributes(LLVMContext &C, unsigned Index, + AttributeList Attrs) const; + + AttributeList addAttributes(LLVMContext &C, unsigned Index, + AttributeSet AS) const; + + AttributeList addAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &B) const; /// \brief Remove the specified attribute at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Kind) const; + AttributeList removeAttribute(LLVMContext &C, unsigned Index, + Attribute::AttrKind Kind) const; /// \brief Remove the specified attribute at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - StringRef Kind) const; + AttributeList removeAttribute(LLVMContext &C, unsigned Index, + StringRef Kind) const; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttributes(LLVMContext &C, unsigned Index, - AttributeSet Attrs) const; + AttributeList removeAttributes(LLVMContext &C, unsigned Index, + AttributeList Attrs) const; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttributes(LLVMContext &C, unsigned Index, - const AttrBuilder &Attrs) const; + AttributeList removeAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &Attrs) const; + + /// \brief Remove all attributes at the specified index from this + /// attribute list. Because attribute lists are immutable, this returns the + /// new list. + AttributeList removeAttributes(LLVMContext &C, unsigned Index) const; /// \brief Add the dereferenceable attribute to the attribute set at the given /// index. Because attribute sets are immutable, this returns a new set. - AttributeSet addDereferenceableAttr(LLVMContext &C, unsigned Index, - uint64_t Bytes) const; + AttributeList addDereferenceableAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; /// \brief Add the dereferenceable_or_null attribute to the attribute set at /// the given index. Because attribute sets are immutable, this returns a new /// set. - AttributeSet addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index, - uint64_t Bytes) const; + AttributeList addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; /// Add the allocsize attribute to the attribute set at the given index. /// Because attribute sets are immutable, this returns a new set. - AttributeSet addAllocSizeAttr(LLVMContext &C, unsigned Index, - unsigned ElemSizeArg, - const Optional<unsigned> &NumElemsArg); + AttributeList addAllocSizeAttr(LLVMContext &C, unsigned Index, + unsigned ElemSizeArg, + const Optional<unsigned> &NumElemsArg); //===--------------------------------------------------------------------===// - // AttributeSet Accessors + // AttributeList Accessors //===--------------------------------------------------------------------===// /// \brief Retrieve the LLVM context. LLVMContext &getContext() const; /// \brief The attributes for the specified index are returned. - AttributeSet getParamAttributes(unsigned Index) const; + AttributeSet getAttributes(unsigned Index) const; + + /// \brief The attributes for the argument or parameter at the given index are + /// returned. + AttributeSet getParamAttributes(unsigned ArgNo) const; /// \brief The attributes for the ret value are returned. AttributeSet getRetAttributes() const; @@ -334,14 +437,17 @@ public: /// \brief Return true if attribute exists at the given index. bool hasAttributes(unsigned Index) const; - /// \brief Equivalent to hasAttribute(AttributeSet::FunctionIndex, Kind) but + /// \brief Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but /// may be faster. bool hasFnAttribute(Attribute::AttrKind Kind) const; - /// \brief Equivalent to hasAttribute(AttributeSet::FunctionIndex, Kind) but + /// \brief Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but /// may be faster. bool hasFnAttribute(StringRef Kind) const; + /// \brief Equivalent to hasAttribute(ArgNo + 1, Kind). + bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const; + /// \brief Return true if the specified attribute is set for at least one /// parameter or for the return value. If Index is not nullptr, the index /// of a parameter with the specified attribute is provided. @@ -380,15 +486,11 @@ public: iterator end(unsigned Slot) const; /// operator==/!= - Provide equality predicates. - bool operator==(const AttributeSet &RHS) const { - return pImpl == RHS.pImpl; - } - bool operator!=(const AttributeSet &RHS) const { - return pImpl != RHS.pImpl; - } + bool operator==(const AttributeList &RHS) const { return pImpl == RHS.pImpl; } + bool operator!=(const AttributeList &RHS) const { return pImpl != RHS.pImpl; } //===--------------------------------------------------------------------===// - // AttributeSet Introspection + // AttributeList Introspection //===--------------------------------------------------------------------===// /// \brief Return a raw pointer that uniquely identifies this attribute list. @@ -410,30 +512,35 @@ public: unsigned getSlotIndex(unsigned Slot) const; /// \brief Return the attributes at the given slot. - AttributeSet getSlotAttributes(unsigned Slot) const; + AttributeList getSlotAttributes(unsigned Slot) const; void dump() const; }; //===----------------------------------------------------------------------===// /// \class -/// \brief Provide DenseMapInfo for AttributeSet. -template<> struct DenseMapInfo<AttributeSet> { - static inline AttributeSet getEmptyKey() { +/// \brief Provide DenseMapInfo for AttributeList. +template <> struct DenseMapInfo<AttributeList> { + static inline AttributeList getEmptyKey() { uintptr_t Val = static_cast<uintptr_t>(-1); Val <<= PointerLikeTypeTraits<void*>::NumLowBitsAvailable; - return AttributeSet(reinterpret_cast<AttributeSetImpl*>(Val)); + return AttributeList(reinterpret_cast<AttributeListImpl *>(Val)); } - static inline AttributeSet getTombstoneKey() { + + static inline AttributeList getTombstoneKey() { uintptr_t Val = static_cast<uintptr_t>(-2); Val <<= PointerLikeTypeTraits<void*>::NumLowBitsAvailable; - return AttributeSet(reinterpret_cast<AttributeSetImpl*>(Val)); + return AttributeList(reinterpret_cast<AttributeListImpl *>(Val)); } - static unsigned getHashValue(AttributeSet AS) { + + static unsigned getHashValue(AttributeList AS) { return (unsigned((uintptr_t)AS.pImpl) >> 4) ^ (unsigned((uintptr_t)AS.pImpl) >> 9); } - static bool isEqual(AttributeSet LHS, AttributeSet RHS) { return LHS == RHS; } + + static bool isEqual(AttributeList LHS, AttributeList RHS) { + return LHS == RHS; + } }; //===----------------------------------------------------------------------===// @@ -445,22 +552,19 @@ template<> struct DenseMapInfo<AttributeSet> { class AttrBuilder { std::bitset<Attribute::EndAttrKinds> Attrs; std::map<std::string, std::string> TargetDepAttrs; - uint64_t Alignment; - uint64_t StackAlignment; - uint64_t DerefBytes; - uint64_t DerefOrNullBytes; - uint64_t AllocSizeArgs; + uint64_t Alignment = 0; + uint64_t StackAlignment = 0; + uint64_t DerefBytes = 0; + uint64_t DerefOrNullBytes = 0; + uint64_t AllocSizeArgs = 0; public: - AttrBuilder() - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0), AllocSizeArgs(0) {} - AttrBuilder(const Attribute &A) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0), AllocSizeArgs(0) { + AttrBuilder() = default; + AttrBuilder(const Attribute &A) { addAttribute(A); } - AttrBuilder(AttributeSet AS, unsigned Idx); + AttrBuilder(AttributeList AS, unsigned Idx); + AttrBuilder(AttributeSet AS); void clear(); @@ -477,7 +581,7 @@ public: AttrBuilder &removeAttribute(Attribute::AttrKind Val); /// \brief Remove the attributes from the builder. - AttrBuilder &removeAttributes(AttributeSet A, uint64_t Index); + AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex); /// \brief Remove the target-dependent attribute to the builder. AttrBuilder &removeAttribute(StringRef A); @@ -507,7 +611,7 @@ public: /// \brief Return true if the builder has any attribute that's in the /// specified attribute. - bool hasAttributes(AttributeSet A, uint64_t Index) const; + bool hasAttributes(AttributeList A, uint64_t Index) const; /// \brief Return true if the builder has an alignment attribute. bool hasAlignmentAttr() const; @@ -562,8 +666,8 @@ public: typedef std::pair<std::string, std::string> td_type; typedef std::map<std::string, std::string>::iterator td_iterator; typedef std::map<std::string, std::string>::const_iterator td_const_iterator; - typedef llvm::iterator_range<td_iterator> td_range; - typedef llvm::iterator_range<td_const_iterator> td_const_range; + typedef iterator_range<td_iterator> td_range; + typedef iterator_range<td_const_iterator> td_const_range; td_iterator td_begin() { return TargetDepAttrs.begin(); } td_iterator td_end() { return TargetDepAttrs.end(); } @@ -600,4 +704,4 @@ void mergeAttributesForInlining(Function &Caller, const Function &Callee); } // end llvm namespace -#endif +#endif // LLVM_IR_ATTRIBUTES_H diff --git a/include/llvm/IR/BasicBlock.h b/include/llvm/IR/BasicBlock.h index 93dbd573ee16..bd210e1abf31 100644 --- a/include/llvm/IR/BasicBlock.h +++ b/include/llvm/IR/BasicBlock.h @@ -105,27 +105,35 @@ public: /// /// Note: this is undefined behavior if the block does not have a parent. const Module *getModule() const; - Module *getModule(); + Module *getModule() { + return const_cast<Module *>( + static_cast<const BasicBlock *>(this)->getModule()); + } /// \brief Returns the terminator instruction if the block is well formed or /// null if the block is not well formed. - TerminatorInst *getTerminator(); - const TerminatorInst *getTerminator() const; + const TerminatorInst *getTerminator() const LLVM_READONLY; + TerminatorInst *getTerminator() { + return const_cast<TerminatorInst *>( + static_cast<const BasicBlock *>(this)->getTerminator()); + } /// \brief Returns the call instruction calling @llvm.experimental.deoptimize /// prior to the terminating return instruction of this basic block, if such a /// call is present. Otherwise, returns null. - CallInst *getTerminatingDeoptimizeCall(); - const CallInst *getTerminatingDeoptimizeCall() const { - return const_cast<BasicBlock *>(this)->getTerminatingDeoptimizeCall(); + const CallInst *getTerminatingDeoptimizeCall() const; + CallInst *getTerminatingDeoptimizeCall() { + return const_cast<CallInst *>( + static_cast<const BasicBlock *>(this)->getTerminatingDeoptimizeCall()); } /// \brief Returns the call instruction marked 'musttail' prior to the /// terminating return instruction of this basic block, if such a call is /// present. Otherwise, returns null. - CallInst *getTerminatingMustTailCall(); - const CallInst *getTerminatingMustTailCall() const { - return const_cast<BasicBlock *>(this)->getTerminatingMustTailCall(); + const CallInst *getTerminatingMustTailCall() const; + CallInst *getTerminatingMustTailCall() { + return const_cast<CallInst *>( + static_cast<const BasicBlock *>(this)->getTerminatingMustTailCall()); } /// \brief Returns a pointer to the first instruction in this block that is @@ -134,32 +142,36 @@ public: /// When adding instructions to the beginning of the basic block, they should /// be added before the returned value, not before the first instruction, /// which might be PHI. Returns 0 is there's no non-PHI instruction. - Instruction* getFirstNonPHI(); - const Instruction* getFirstNonPHI() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHI(); + const Instruction* getFirstNonPHI() const; + Instruction* getFirstNonPHI() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHI()); } /// \brief Returns a pointer to the first instruction in this block that is not /// a PHINode or a debug intrinsic. - Instruction* getFirstNonPHIOrDbg(); - const Instruction* getFirstNonPHIOrDbg() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbg(); + const Instruction* getFirstNonPHIOrDbg() const; + Instruction* getFirstNonPHIOrDbg() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHIOrDbg()); } /// \brief Returns a pointer to the first instruction in this block that is not /// a PHINode, a debug intrinsic, or a lifetime intrinsic. - Instruction* getFirstNonPHIOrDbgOrLifetime(); - const Instruction* getFirstNonPHIOrDbgOrLifetime() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbgOrLifetime(); + const Instruction* getFirstNonPHIOrDbgOrLifetime() const; + Instruction* getFirstNonPHIOrDbgOrLifetime() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHIOrDbgOrLifetime()); } /// \brief Returns an iterator to the first instruction in this block that is /// suitable for inserting a non-PHI instruction. /// /// In particular, it skips all PHIs and LandingPad instructions. - iterator getFirstInsertionPt(); - const_iterator getFirstInsertionPt() const { - return const_cast<BasicBlock*>(this)->getFirstInsertionPt(); + const_iterator getFirstInsertionPt() const; + iterator getFirstInsertionPt() { + return static_cast<const BasicBlock *>(this) + ->getFirstInsertionPt().getNonConst(); } /// \brief Unlink 'this' from the containing function, but do not delete it. @@ -188,9 +200,10 @@ public: /// \brief Return the predecessor of this block if it has a single predecessor /// block. Otherwise return a null pointer. - BasicBlock *getSinglePredecessor(); - const BasicBlock *getSinglePredecessor() const { - return const_cast<BasicBlock*>(this)->getSinglePredecessor(); + const BasicBlock *getSinglePredecessor() const; + BasicBlock *getSinglePredecessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getSinglePredecessor()); } /// \brief Return the predecessor of this block if it has a unique predecessor @@ -199,27 +212,30 @@ public: /// Note that unique predecessor doesn't mean single edge, there can be /// multiple edges from the unique predecessor to this block (for example a /// switch statement with multiple cases having the same destination). - BasicBlock *getUniquePredecessor(); - const BasicBlock *getUniquePredecessor() const { - return const_cast<BasicBlock*>(this)->getUniquePredecessor(); + const BasicBlock *getUniquePredecessor() const; + BasicBlock *getUniquePredecessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getUniquePredecessor()); } /// \brief Return the successor of this block if it has a single successor. /// Otherwise return a null pointer. /// /// This method is analogous to getSinglePredecessor above. - BasicBlock *getSingleSuccessor(); - const BasicBlock *getSingleSuccessor() const { - return const_cast<BasicBlock*>(this)->getSingleSuccessor(); + const BasicBlock *getSingleSuccessor() const; + BasicBlock *getSingleSuccessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getSingleSuccessor()); } /// \brief Return the successor of this block if it has a unique successor. /// Otherwise return a null pointer. /// /// This method is analogous to getUniquePredecessor above. - BasicBlock *getUniqueSuccessor(); - const BasicBlock *getUniqueSuccessor() const { - return const_cast<BasicBlock*>(this)->getUniqueSuccessor(); + const BasicBlock *getUniqueSuccessor() const; + BasicBlock *getUniqueSuccessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getUniqueSuccessor()); } //===--------------------------------------------------------------------===// @@ -321,8 +337,11 @@ public: bool isLandingPad() const; /// \brief Return the landingpad instruction associated with the landing pad. - LandingPadInst *getLandingPadInst(); const LandingPadInst *getLandingPadInst() const; + LandingPadInst *getLandingPadInst() { + return const_cast<LandingPadInst *>( + static_cast<const BasicBlock *>(this)->getLandingPadInst()); + } private: /// \brief Increment the internal refcount of the number of BlockAddresses diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index b02c89474146..79f59557a5d6 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -65,11 +65,9 @@ protected: explicit CallSiteBase(ValTy *II) { *this = get(II); } private: - /// CallSiteBase::get - This static method is sort of like a constructor. It - /// will create an appropriate call site for a Call or Invoke instruction, but - /// it can also create a null initialized CallSiteBase object for something - /// which is NOT a call site. - /// + /// This static method is like a constructor. It will create an appropriate + /// call site for a Call or Invoke instruction, but it can also create a null + /// initialized CallSiteBase object for something which is NOT a call site. static CallSiteBase get(ValTy *V) { if (InstrTy *II = dyn_cast<InstrTy>(V)) { if (II->getOpcode() == Instruction::Call) @@ -81,38 +79,47 @@ private: } public: - /// isCall - true if a CallInst is enclosed. - /// Note that !isCall() does not mean it is an InvokeInst enclosed, - /// it also could signify a NULL Instruction pointer. + /// Return true if a CallInst is enclosed. Note that !isCall() does not mean + /// an InvokeInst is enclosed. It may also signify a NULL instruction pointer. bool isCall() const { return I.getInt(); } - /// isInvoke - true if a InvokeInst is enclosed. - /// + /// Return true if a InvokeInst is enclosed. bool isInvoke() const { return getInstruction() && !I.getInt(); } InstrTy *getInstruction() const { return I.getPointer(); } InstrTy *operator->() const { return I.getPointer(); } explicit operator bool() const { return I.getPointer(); } - /// Get the basic block containing the call site + /// Get the basic block containing the call site. BBTy* getParent() const { return getInstruction()->getParent(); } - /// getCalledValue - Return the pointer to function that is being called. - /// + /// Return the pointer to function that is being called. ValTy *getCalledValue() const { assert(getInstruction() && "Not a call or invoke instruction!"); return *getCallee(); } - /// getCalledFunction - Return the function being called if this is a direct - /// call, otherwise return null (if it's an indirect call). - /// + /// Return the function being called if this is a direct call, otherwise + /// return null (if it's an indirect call). FunTy *getCalledFunction() const { return dyn_cast<FunTy>(getCalledValue()); } - /// setCalledFunction - Set the callee to the specified value. - /// + /// Return true if the callsite is an indirect call. + bool isIndirectCall() const { + Value *V = getCalledValue(); + if (!V) + return false; + if (isa<FunTy>(V) || isa<Constant>(V)) + return false; + if (CallInst *CI = dyn_cast<CallInst>(getInstruction())) { + if (CI->isInlineAsm()) + return false; + } + return true; + } + + /// Set the callee to the specified value. void setCalledFunction(Value *V) { assert(getInstruction() && "Not a call or invoke instruction!"); *getCallee() = V; @@ -129,8 +136,7 @@ public: return static_cast<Intrinsic::ID>(0); } - /// isCallee - Determine whether the passed iterator points to the - /// callee operand's Use. + /// Determine whether the passed iterator points to the callee operand's Use. bool isCallee(Value::const_user_iterator UI) const { return isCallee(&UI.getUse()); } @@ -138,24 +144,23 @@ public: /// Determine whether this Use is the callee operand's Use. bool isCallee(const Use *U) const { return getCallee() == U; } - /// \brief Determine whether the passed iterator points to an argument - /// operand. + /// Determine whether the passed iterator points to an argument operand. bool isArgOperand(Value::const_user_iterator UI) const { return isArgOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to an argument operand. + /// Determine whether the passed use points to an argument operand. bool isArgOperand(const Use *U) const { assert(getInstruction() == U->getUser()); return arg_begin() <= U && U < arg_end(); } - /// \brief Determine whether the passed iterator points to a bundle operand. + /// Determine whether the passed iterator points to a bundle operand. bool isBundleOperand(Value::const_user_iterator UI) const { return isBundleOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to a bundle operand. + /// Determine whether the passed use points to a bundle operand. bool isBundleOperand(const Use *U) const { assert(getInstruction() == U->getUser()); if (!hasOperandBundles()) @@ -165,12 +170,12 @@ public: OperandNo < getBundleOperandsEndIndex(); } - /// \brief Determine whether the passed iterator points to a data operand. + /// Determine whether the passed iterator points to a data operand. bool isDataOperand(Value::const_user_iterator UI) const { return isDataOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to a data operand. + /// Determine whether the passed use points to a data operand. bool isDataOperand(const Use *U) const { return data_operands_begin() <= U && U < data_operands_end(); } @@ -200,8 +205,8 @@ public: return U - arg_begin(); } - /// arg_iterator - The type of iterator to use when looping over actual - /// arguments at this call site. + /// The type of iterator to use when looping over actual arguments at this + /// call site. typedef IterTy arg_iterator; iterator_range<IterTy> args() const { @@ -210,8 +215,7 @@ public: bool arg_empty() const { return arg_end() == arg_begin(); } unsigned arg_size() const { return unsigned(arg_end() - arg_begin()); } - /// Given a value use iterator, returns the data operand that corresponds to - /// it. + /// Given a value use iterator, return the data operand corresponding to it. /// Iterator must actually correspond to a data operand. unsigned getDataOperandNo(Value::const_user_iterator UI) const { return getDataOperandNo(&UI.getUse()); @@ -253,21 +257,19 @@ public: return std::distance(data_operands_begin(), data_operands_end()); } - /// getType - Return the type of the instruction that generated this call site - /// + /// Return the type of the instruction that generated this call site. Type *getType() const { return (*this)->getType(); } - /// getCaller - Return the caller function for this call site - /// + /// Return the caller function for this call site. FunTy *getCaller() const { return (*this)->getParent()->getParent(); } - /// \brief Tests if this call site must be tail call optimized. Only a - /// CallInst can be tail call optimized. + /// Tests if this call site must be tail call optimized. Only a CallInst can + /// be tail call optimized. bool isMustTailCall() const { return isCall() && cast<CallInst>(getInstruction())->isMustTailCall(); } - /// \brief Tests if this call site is marked as a tail call. + /// Tests if this call site is marked as a tail call. bool isTailCall() const { return isCall() && cast<CallInst>(getInstruction())->isTailCall(); } @@ -303,11 +305,11 @@ public: return false; } - /// getCallingConv/setCallingConv - get or set the calling convention of the - /// call. + /// Get the calling convention of the call. CallingConv::ID getCallingConv() const { CALLSITE_DELEGATE_GETTER(getCallingConv()); } + /// Set the calling convention of the call. void setCallingConv(CallingConv::ID CC) { CALLSITE_DELEGATE_SETTER(setCallingConv(CC)); } @@ -320,12 +322,12 @@ public: CALLSITE_DELEGATE_SETTER(mutateFunctionType(Ty)); } - /// getAttributes/setAttributes - get or set the parameter attributes of - /// the call. - AttributeSet getAttributes() const { + /// Get the parameter attributes of the call. + AttributeList getAttributes() const { CALLSITE_DELEGATE_GETTER(getAttributes()); } - void setAttributes(AttributeSet PAL) { + /// Set the parameter attributes of the call. + void setAttributes(AttributeList PAL) { CALLSITE_DELEGATE_SETTER(setAttributes(PAL)); } @@ -345,19 +347,24 @@ public: CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); } - /// \brief Return true if this function has the given attribute. + /// Return true if this function has the given attribute. bool hasFnAttr(Attribute::AttrKind Kind) const { CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } - /// \brief Return true if this function has the given attribute. + /// Return true if this function has the given attribute. bool hasFnAttr(StringRef Kind) const { CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } - /// \brief Return true if the call or the callee has the given attribute. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(paramHasAttr(i, Kind)); + /// Return true if this return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(hasRetAttr(Kind)); + } + + /// Return true if the call or the callee has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(paramHasAttr(ArgNo, Kind)); } Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -368,8 +375,8 @@ public: CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); } - /// \brief Return true if the data operand at index \p i directly or - /// indirectly has the attribute \p A. + /// Return true if the data operand at index \p i directly or indirectly has + /// the attribute \p A. /// /// Normal call or invoke arguments have per operand attributes, as specified /// in the attribute set attached to this instruction, while operand bundle @@ -379,37 +386,36 @@ public: CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, Kind)); } - /// @brief Extract the alignment for a call or parameter (0=unknown). + /// Extract the alignment for a call or parameter (0=unknown). uint16_t getParamAlignment(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getParamAlignment(i)); } - /// @brief Extract the number of dereferenceable bytes for a call or - /// parameter (0=unknown). + /// Extract the number of dereferenceable bytes for a call or parameter + /// (0=unknown). uint64_t getDereferenceableBytes(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getDereferenceableBytes(i)); } - /// @brief Extract the number of dereferenceable_or_null bytes for a call or + /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i)); } - /// @brief Determine if the parameter or return value is marked with NoAlias + /// Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { CALLSITE_DELEGATE_GETTER(doesNotAlias(n)); } - /// \brief Return true if the call should not be treated as a call to a - /// builtin. + /// Return true if the call should not be treated as a call to a builtin. bool isNoBuiltin() const { CALLSITE_DELEGATE_GETTER(isNoBuiltin()); } - /// @brief Return true if the call should not be inlined. + /// Return true if the call should not be inlined. bool isNoInline() const { CALLSITE_DELEGATE_GETTER(isNoInline()); } @@ -417,7 +423,7 @@ public: CALLSITE_DELEGATE_SETTER(setIsNoInline(Value)); } - /// @brief Determine if the call does not access memory. + /// Determine if the call does not access memory. bool doesNotAccessMemory() const { CALLSITE_DELEGATE_GETTER(doesNotAccessMemory()); } @@ -425,7 +431,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotAccessMemory()); } - /// @brief Determine if the call does not access or only reads memory. + /// Determine if the call does not access or only reads memory. bool onlyReadsMemory() const { CALLSITE_DELEGATE_GETTER(onlyReadsMemory()); } @@ -433,7 +439,7 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory()); } - /// @brief Determine if the call does not access or only writes memory. + /// Determine if the call does not access or only writes memory. bool doesNotReadMemory() const { CALLSITE_DELEGATE_GETTER(doesNotReadMemory()); } @@ -441,7 +447,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory()); } - /// @brief Determine if the call can access memmory only using pointers based + /// Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { CALLSITE_DELEGATE_GETTER(onlyAccessesArgMemory()); @@ -450,7 +456,7 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyAccessesArgMemory()); } - /// @brief Determine if the call cannot return. + /// Determine if the call cannot return. bool doesNotReturn() const { CALLSITE_DELEGATE_GETTER(doesNotReturn()); } @@ -458,7 +464,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotReturn()); } - /// @brief Determine if the call cannot unwind. + /// Determine if the call cannot unwind. bool doesNotThrow() const { CALLSITE_DELEGATE_GETTER(doesNotThrow()); } @@ -466,7 +472,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotThrow()); } - /// @brief Determine if the call can be duplicated. + /// Determine if the call can be duplicated. bool cannotDuplicate() const { CALLSITE_DELEGATE_GETTER(cannotDuplicate()); } @@ -474,7 +480,7 @@ public: CALLSITE_DELEGATE_GETTER(setCannotDuplicate()); } - /// @brief Determine if the call is convergent. + /// Determine if the call is convergent. bool isConvergent() const { CALLSITE_DELEGATE_GETTER(isConvergent()); } @@ -546,31 +552,31 @@ public: cast<InvokeInst>(II)->getOperandBundlesAsDefs(Defs); } - /// @brief Determine whether this data operand is not captured. + /// Determine whether this data operand is not captured. bool doesNotCapture(unsigned OpNo) const { return dataOperandHasImpliedAttr(OpNo + 1, Attribute::NoCapture); } - /// @brief Determine whether this argument is passed by value. + /// Determine whether this argument is passed by value. bool isByValArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::ByVal); + return paramHasAttr(ArgNo, Attribute::ByVal); } - /// @brief Determine whether this argument is passed in an alloca. + /// Determine whether this argument is passed in an alloca. bool isInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::InAlloca); + return paramHasAttr(ArgNo, Attribute::InAlloca); } - /// @brief Determine whether this argument is passed by value or in an alloca. + /// Determine whether this argument is passed by value or in an alloca. bool isByValOrInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::ByVal) || - paramHasAttr(ArgNo + 1, Attribute::InAlloca); + return paramHasAttr(ArgNo, Attribute::ByVal) || + paramHasAttr(ArgNo, Attribute::InAlloca); } - /// @brief Determine if there are is an inalloca argument. Only the last - /// argument can have the inalloca attribute. + /// Determine if there are is an inalloca argument. Only the last argument can + /// have the inalloca attribute. bool hasInAllocaArgument() const { - return paramHasAttr(arg_size(), Attribute::InAlloca); + return !arg_empty() && paramHasAttr(arg_size() - 1, Attribute::InAlloca); } bool doesNotAccessMemory(unsigned OpNo) const { @@ -582,11 +588,16 @@ public: dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); } - /// @brief Return true if the return value is known to be not null. + bool doesNotReadMemory(unsigned OpNo) const { + return dataOperandHasImpliedAttr(OpNo + 1, Attribute::WriteOnly) || + dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); + } + + /// Return true if the return value is known to be not null. /// This may be because it has the nonnull attribute, or because at least /// one byte is dereferenceable and the pointer is in addrspace(0). bool isReturnNonNull() const { - if (paramHasAttr(0, Attribute::NonNull)) + if (hasRetAttr(Attribute::NonNull)) return true; else if (getDereferenceableBytes(0) > 0 && getType()->getPointerAddressSpace() == 0) @@ -595,8 +606,8 @@ public: return false; } - /// hasArgument - Returns true if this CallSite passes the given Value* as an - /// argument to the called function. + /// Returns true if this CallSite passes the given Value* as an argument to + /// the called function. bool hasArgument(const Value *Arg) const { for (arg_iterator AI = this->arg_begin(), E = this->arg_end(); AI != E; ++AI) @@ -661,7 +672,7 @@ template <> struct DenseMapInfo<CallSite> { } }; -/// ImmutableCallSite - establish a view to a call site for examination +/// Establish a view to a call site for examination. class ImmutableCallSite : public CallSiteBase<> { public: ImmutableCallSite() = default; diff --git a/include/llvm/IR/Comdat.h b/include/llvm/IR/Comdat.h index f4a391c31ae2..fa87093ca50a 100644 --- a/include/llvm/IR/Comdat.h +++ b/include/llvm/IR/Comdat.h @@ -1,4 +1,4 @@ -//===-- llvm/IR/Comdat.h - Comdat definitions -------------------*- C++ -*-===// +//===- llvm/IR/Comdat.h - Comdat definitions --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -51,8 +51,8 @@ private: Comdat(); // Points to the map in Module. - StringMapEntry<Comdat> *Name; - SelectionKind SK; + StringMapEntry<Comdat> *Name = nullptr; + SelectionKind SK = Any; }; inline raw_ostream &operator<<(raw_ostream &OS, const Comdat &C) { diff --git a/include/llvm/IR/Constant.h b/include/llvm/IR/Constant.h index 99c970ebb633..3b3694e7e60d 100644 --- a/include/llvm/IR/Constant.h +++ b/include/llvm/IR/Constant.h @@ -152,12 +152,13 @@ public: /// hanging off of the globals. void removeDeadConstantUsers() const; - Constant *stripPointerCasts() { + const Constant *stripPointerCasts() const { return cast<Constant>(Value::stripPointerCasts()); } - const Constant *stripPointerCasts() const { - return const_cast<Constant*>(this)->stripPointerCasts(); + Constant *stripPointerCasts() { + return const_cast<Constant*>( + static_cast<const Constant *>(this)->stripPointerCasts()); } }; diff --git a/include/llvm/IR/ConstantRange.h b/include/llvm/IR/ConstantRange.h index 27a9b1364448..6d704666933f 100644 --- a/include/llvm/IR/ConstantRange.h +++ b/include/llvm/IR/ConstantRange.h @@ -45,9 +45,6 @@ class MDNode; class ConstantRange { APInt Lower, Upper; - // If we have move semantics, pass APInts by value and move them into place. - typedef APInt APIntMoveTy; - public: /// Initialize a full (the default) or empty set for the specified bit width. /// @@ -55,12 +52,12 @@ public: /// Initialize a range to hold the single specified value. /// - ConstantRange(APIntMoveTy Value); + ConstantRange(APInt Value); /// @brief Initialize a range of values explicitly. This will assert out if /// Lower==Upper and Lower != Min or Max value for its type. It will also /// assert out if the two APInt's are not the same bit width. - ConstantRange(APIntMoveTy Lower, APIntMoveTy Upper); + ConstantRange(APInt Lower, APInt Upper); /// Produce the smallest range such that all values that may satisfy the given /// predicate with any value contained within Other is contained in the @@ -184,6 +181,10 @@ public: /// APInt getSetSize() const; + /// Compare set size of this range with the range CR. + /// + bool isSizeStrictlySmallerThanOf(const ConstantRange &CR) const; + /// Return the largest unsigned value contained in the ConstantRange. /// APInt getUnsignedMax() const; diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index cbefa3f05dfc..ad83b21c7bf3 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -138,7 +138,7 @@ public: static Constant *get(Type* Ty, const APInt& V); /// Return the constant as an APInt value reference. This allows clients to - /// obtain a copy of the value, with all its precision in tact. + /// obtain a full-precision copy of the value. /// @brief Return the constant's value. inline const APInt &getValue() const { return Val; diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h index 48cb7fe5df6f..69bd5c847a8d 100644 --- a/include/llvm/IR/DIBuilder.h +++ b/include/llvm/IR/DIBuilder.h @@ -105,13 +105,17 @@ namespace llvm { /// out into. /// \param Kind The kind of debug information to generate. /// \param DWOId The DWOId if this is a split skeleton compile unit. + /// \param SplitDebugInlining Whether to emit inline debug info. + /// \param DebugInfoForProfiling Whether to emit extra debug info for + /// profile collection. DICompileUnit * createCompileUnit(unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), DICompileUnit::DebugEmissionKind Kind = DICompileUnit::DebugEmissionKind::FullDebug, - uint64_t DWOId = 0, bool SplitDebugInlining = true); + uint64_t DWOId = 0, bool SplitDebugInlining = true, + bool DebugInfoForProfiling = false); /// Create a file descriptor to hold debugging information for a file. /// \param Filename File name. @@ -164,12 +168,15 @@ namespace llvm { DIDerivedType *createQualifiedType(unsigned Tag, DIType *FromTy); /// Create debugging information entry for a pointer. - /// \param PointeeTy Type pointed by this pointer. - /// \param SizeInBits Size. - /// \param AlignInBits Alignment. (optional) - /// \param Name Pointer type name. (optional) + /// \param PointeeTy Type pointed by this pointer. + /// \param SizeInBits Size. + /// \param AlignInBits Alignment. (optional) + /// \param DWARFAddressSpace DWARF address space. (optional) + /// \param Name Pointer type name. (optional) DIDerivedType *createPointerType(DIType *PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits = 0, + Optional<unsigned> DWARFAddressSpace = + None, StringRef Name = ""); /// Create debugging information entry for a pointer to member. @@ -186,7 +193,9 @@ namespace llvm { /// style reference or rvalue reference type. DIDerivedType *createReferenceType(unsigned Tag, DIType *RTy, uint64_t SizeInBits = 0, - uint32_t AlignInBits = 0); + uint32_t AlignInBits = 0, + Optional<unsigned> DWARFAddressSpace = + None); /// Create debugging information entry for a typedef. /// \param Ty Original type. @@ -431,13 +440,6 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, unsigned CC = 0); - /// Create an external type reference. - /// \param Tag Dwarf TAG. - /// \param File File in which the type is defined. - /// \param UniqueIdentifier A unique identifier for the type. - DICompositeType *createExternalTypeRef(unsigned Tag, DIFile *File, - StringRef UniqueIdentifier); - /// Create a new DIType* with "artificial" flag set. DIType *createArtificialType(DIType *Ty); diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index 6f37669f9768..1930d48577d4 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -104,6 +104,7 @@ private: /// Defaults to false. bool BigEndian; + unsigned AllocaAddrSpace; unsigned StackNaturalAlign; enum ManglingModeT { @@ -118,8 +119,19 @@ private: SmallVector<unsigned char, 8> LegalIntWidths; - /// \brief Primitive type alignment data. - SmallVector<LayoutAlignElem, 16> Alignments; + /// \brief Primitive type alignment data. This is sorted by type and bit + /// width during construction. + typedef SmallVector<LayoutAlignElem, 16> AlignmentsTy; + AlignmentsTy Alignments; + + AlignmentsTy::const_iterator + findAlignmentLowerBound(AlignTypeEnum AlignType, uint32_t BitWidth) const { + return const_cast<DataLayout *>(this)->findAlignmentLowerBound(AlignType, + BitWidth); + } + + AlignmentsTy::iterator + findAlignmentLowerBound(AlignTypeEnum AlignType, uint32_t BitWidth); /// \brief The string representation used to create this DataLayout std::string StringRepresentation; @@ -134,14 +146,6 @@ private: PointersTy::iterator findPointerLowerBound(uint32_t AddressSpace); - /// This member is a signal that a requested alignment type and bit width were - /// not found in the SmallVector. - static const LayoutAlignElem InvalidAlignmentElem; - - /// This member is a signal that a requested pointer type and bit width were - /// not found in the DenseSet. - static const PointerAlignElem InvalidPointerElem; - // The StructType -> StructLayout map. mutable void *LayoutMap; @@ -159,22 +163,6 @@ private: /// Internal helper method that returns requested alignment for type. unsigned getAlignment(Type *Ty, bool abi_or_pref) const; - /// \brief Valid alignment predicate. - /// - /// Predicate that tests a LayoutAlignElem reference returned by get() against - /// InvalidAlignmentElem. - bool validAlignment(const LayoutAlignElem &align) const { - return &align != &InvalidAlignmentElem; - } - - /// \brief Valid pointer predicate. - /// - /// Predicate that tests a PointerAlignElem reference returned by get() - /// against \c InvalidPointerElem. - bool validPointer(const PointerAlignElem &align) const { - return &align != &InvalidPointerElem; - } - /// Parses a target data specification string. Assert if the string is /// malformed. void parseSpecifier(StringRef LayoutDescription); @@ -199,6 +187,7 @@ public: clear(); StringRepresentation = DL.StringRepresentation; BigEndian = DL.isBigEndian(); + AllocaAddrSpace = DL.AllocaAddrSpace; StackNaturalAlign = DL.StackNaturalAlign; ManglingMode = DL.ManglingMode; LegalIntWidths = DL.LegalIntWidths; @@ -254,6 +243,7 @@ public: } unsigned getStackAlignment() const { return StackNaturalAlign; } + unsigned getAllocaAddrSpace() const { return AllocaAddrSpace; } bool hasMicrosoftFastStdCallMangling() const { return ManglingMode == MM_WinCOFFX86; diff --git a/include/llvm/IR/DebugInfoFlags.def b/include/llvm/IR/DebugInfoFlags.def index 87f3dc9dbdd3..7ea6346998fe 100644 --- a/include/llvm/IR/DebugInfoFlags.def +++ b/include/llvm/IR/DebugInfoFlags.def @@ -34,7 +34,8 @@ HANDLE_DI_FLAG((1 << 11), Vector) HANDLE_DI_FLAG((1 << 12), StaticMember) HANDLE_DI_FLAG((1 << 13), LValueReference) HANDLE_DI_FLAG((1 << 14), RValueReference) -HANDLE_DI_FLAG((1 << 15), ExternalTypeRef) +// 15 was formerly ExternalTypeRef, but this was never used. +HANDLE_DI_FLAG((1 << 15), Reserved) HANDLE_DI_FLAG((1 << 16), SingleInheritance) HANDLE_DI_FLAG((2 << 16), MultipleInheritance) HANDLE_DI_FLAG((3 << 16), VirtualInheritance) diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 187855225c50..8a924b40143a 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -629,7 +629,6 @@ public: bool isStaticMember() const { return getFlags() & FlagStaticMember; } bool isLValueReference() const { return getFlags() & FlagLValueReference; } bool isRValueReference() const { return getFlags() & FlagRValueReference; } - bool isExternalTypeRef() const { return getFlags() & FlagExternalTypeRef; } static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { @@ -710,37 +709,45 @@ class DIDerivedType : public DIType { friend class LLVMContextImpl; friend class MDNode; + /// \brief The DWARF address space of the memory pointed to or referenced by a + /// pointer or reference type respectively. + Optional<unsigned> DWARFAddressSpace; + DIDerivedType(LLVMContext &C, StorageType Storage, unsigned Tag, unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, ArrayRef<Metadata *> Ops) + uint64_t OffsetInBits, Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, ArrayRef<Metadata *> Ops) : DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits, - AlignInBits, OffsetInBits, Flags, Ops) {} + AlignInBits, OffsetInBits, Flags, Ops), + DWARFAddressSpace(DWARFAddressSpace) {} ~DIDerivedType() = default; static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, DIFile *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, - Metadata *ExtraData, StorageType Storage, - bool ShouldCreate = true) { + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, Metadata *ExtraData, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, - Flags, ExtraData, Storage, ShouldCreate); + DWARFAddressSpace, Flags, ExtraData, Storage, ShouldCreate); } static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, - Metadata *ExtraData, StorageType Storage, - bool ShouldCreate = true); + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, Metadata *ExtraData, + StorageType Storage, bool ShouldCreate = true); TempDIDerivedType cloneImpl() const { return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), getScope(), getBaseType(), getSizeInBits(), - getAlignInBits(), getOffsetInBits(), getFlags(), - getExtraData()); + getAlignInBits(), getOffsetInBits(), + getDWARFAddressSpace(), getFlags(), getExtraData()); } public: @@ -748,24 +755,32 @@ public: (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, DIFlags Flags, Metadata *ExtraData = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, ExtraData)) + AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, + ExtraData)) DEFINE_MDNODE_GET(DIDerivedType, (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, - DIFlags Flags, Metadata *ExtraData = nullptr), + Optional<unsigned> DWARFAddressSpace, DIFlags Flags, + Metadata *ExtraData = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, ExtraData)) + AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, + ExtraData)) TempDIDerivedType clone() const { return cloneImpl(); } - //// Get the base type this is derived from. + /// Get the base type this is derived from. DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } Metadata *getRawBaseType() const { return getOperand(3); } + /// \returns The DWARF address space of the memory pointed to or referenced by + /// a pointer or reference type respectively. + Optional<unsigned> getDWARFAddressSpace() const { return DWARFAddressSpace; } + /// Get extra data associated with this derived type. /// /// Class type for pointer-to-members, objective-c property node for ivars, @@ -1044,15 +1059,17 @@ private: unsigned EmissionKind; uint64_t DWOId; bool SplitDebugInlining; + bool DebugInfoForProfiling; DICompileUnit(LLVMContext &C, StorageType Storage, unsigned SourceLanguage, bool IsOptimized, unsigned RuntimeVersion, unsigned EmissionKind, uint64_t DWOId, bool SplitDebugInlining, - ArrayRef<Metadata *> Ops) + bool DebugInfoForProfiling, ArrayRef<Metadata *> Ops) : DIScope(C, DICompileUnitKind, Storage, dwarf::DW_TAG_compile_unit, Ops), SourceLanguage(SourceLanguage), IsOptimized(IsOptimized), RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind), - DWOId(DWOId), SplitDebugInlining(SplitDebugInlining) { + DWOId(DWOId), SplitDebugInlining(SplitDebugInlining), + DebugInfoForProfiling(DebugInfoForProfiling) { assert(Storage != Uniqued); } ~DICompileUnit() = default; @@ -1065,15 +1082,16 @@ private: DIScopeArray RetainedTypes, DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, - uint64_t DWOId, bool SplitDebugInlining, StorageType Storage, - bool ShouldCreate = true) { + uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, getCanonicalMDString(Context, SplitDebugFilename), EmissionKind, EnumTypes.get(), RetainedTypes.get(), GlobalVariables.get(), ImportedEntities.get(), Macros.get(), - DWOId, SplitDebugInlining, Storage, ShouldCreate); + DWOId, SplitDebugInlining, DebugInfoForProfiling, Storage, + ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, @@ -1082,7 +1100,8 @@ private: unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, - StorageType Storage, bool ShouldCreate = true); + bool DebugInfoForProfiling, StorageType Storage, + bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary(getContext(), getSourceLanguage(), getFile(), @@ -1090,7 +1109,8 @@ private: getRuntimeVersion(), getSplitDebugFilename(), getEmissionKind(), getEnumTypes(), getRetainedTypes(), getGlobalVariables(), getImportedEntities(), - getMacros(), DWOId, getSplitDebugInlining()); + getMacros(), DWOId, getSplitDebugInlining(), + getDebugInfoForProfiling()); } public: @@ -1105,10 +1125,11 @@ public: DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, - uint64_t DWOId, bool SplitDebugInlining), + uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, - GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining)) + GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, + DebugInfoForProfiling)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, @@ -1116,10 +1137,11 @@ public: MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, - bool SplitDebugInlining), + bool SplitDebugInlining, bool DebugInfoForProfiling), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, - GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining)) + GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, + DebugInfoForProfiling)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1129,6 +1151,7 @@ public: DebugEmissionKind getEmissionKind() const { return (DebugEmissionKind)EmissionKind; } + bool getDebugInfoForProfiling() const { return DebugInfoForProfiling; } StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } StringRef getSplitDebugFilename() const { return getStringOperand(3); } @@ -1246,6 +1269,28 @@ class DILocation : public MDNode { static_cast<Metadata *>(InlinedAt), Storage, ShouldCreate); } + /// With a given unsigned int \p U, use up to 13 bits to represent it. + /// old_bit 1~5 --> new_bit 1~5 + /// old_bit 6~12 --> new_bit 7~13 + /// new_bit_6 is 0 if higher bits (7~13) are all 0 + static unsigned getPrefixEncodingFromUnsigned(unsigned U) { + U &= 0xfff; + return U > 0x1f ? (((U & 0xfe0) << 1) | (U & 0x1f) | 0x20) : U; + } + + /// Reverse transformation as getPrefixEncodingFromUnsigned. + static unsigned getUnsignedFromPrefixEncoding(unsigned U) { + return (U & 0x20) ? (((U >> 1) & 0xfe0) | (U & 0x1f)) : (U & 0x1f); + } + + /// Returns the next component stored in discriminator. + static unsigned getNextComponentInDiscriminator(unsigned D) { + if ((D & 1) == 0) + return D >> ((D & 0x40) ? 14 : 7); + else + return D >> 1; + } + TempDILocation cloneImpl() const { // Get the raw scope/inlinedAt since it is possible to invoke this on // a DILocation containing temporary metadata. @@ -1307,10 +1352,48 @@ public: /// /// DWARF discriminators distinguish identical file locations between /// instructions that are on different basic blocks. + /// + /// There are 3 components stored in discriminator, from lower bits: + /// + /// Base discriminator: assigned by AddDiscriminators pass to identify IRs + /// that are defined by the same source line, but + /// different basic blocks. + /// Duplication factor: assigned by optimizations that will scale down + /// the execution frequency of the original IR. + /// Copy Identifier: assigned by optimizations that clones the IR. + /// Each copy of the IR will be assigned an identifier. + /// + /// Encoding: + /// + /// The above 3 components are encoded into a 32bit unsigned integer in + /// order. If the lowest bit is 1, the current component is empty, and the + /// next component will start in the next bit. Otherwise, the the current + /// component is non-empty, and its content starts in the next bit. The + /// length of each components is either 5 bit or 12 bit: if the 7th bit + /// is 0, the bit 2~6 (5 bits) are used to represent the component; if the + /// 7th bit is 1, the bit 2~6 (5 bits) and 8~14 (7 bits) are combined to + /// represent the component. + inline unsigned getDiscriminator() const; /// Returns a new DILocation with updated \p Discriminator. - inline DILocation *cloneWithDiscriminator(unsigned Discriminator) const; + inline const DILocation *cloneWithDiscriminator(unsigned Discriminator) const; + + /// Returns a new DILocation with updated base discriminator \p BD. + inline const DILocation *setBaseDiscriminator(unsigned BD) const; + + /// Returns the duplication factor stored in the discriminator. + inline unsigned getDuplicationFactor() const; + + /// Returns the copy identifier stored in the discriminator. + inline unsigned getCopyIdentifier() const; + + /// Returns the base discriminator stored in the discriminator. + inline unsigned getBaseDiscriminator() const; + + /// Returns a new DILocation with duplication factor \p DF encoded in the + /// discriminator. + inline const DILocation *cloneWithDuplicationFactor(unsigned DF) const; /// When two instructions are combined into a single instruction we also /// need to combine the original locations into a single location. @@ -1333,6 +1416,30 @@ public: return nullptr; } + /// Returns the base discriminator for a given encoded discriminator \p D. + static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { + if ((D & 1) == 0) + return getUnsignedFromPrefixEncoding(D >> 1); + else + return 0; + } + + /// Returns the duplication factor for a given encoded discriminator \p D. + static unsigned getDuplicationFactorFromDiscriminator(unsigned D) { + D = getNextComponentInDiscriminator(D); + if (D == 0 || (D & 1)) + return 1; + else + return getUnsignedFromPrefixEncoding(D >> 1); + } + + /// Returns the copy identifier for a given encoded discriminator \p D. + static unsigned getCopyIdentifierFromDiscriminator(unsigned D) { + return getUnsignedFromPrefixEncoding(getNextComponentInDiscriminator( + getNextComponentInDiscriminator(D))); + } + + Metadata *getRawScope() const { return getOperand(0); } Metadata *getRawInlinedAt() const { if (getNumOperands() == 2) @@ -1343,6 +1450,7 @@ public: static bool classof(const Metadata *MD) { return MD->getMetadataID() == DILocationKind; } + }; /// Subprogram description. @@ -1676,7 +1784,8 @@ unsigned DILocation::getDiscriminator() const { return 0; } -DILocation *DILocation::cloneWithDiscriminator(unsigned Discriminator) const { +const DILocation * +DILocation::cloneWithDiscriminator(unsigned Discriminator) const { DIScope *Scope = getScope(); // Skip all parent DILexicalBlockFile that already have a discriminator // assigned. We do not want to have nested DILexicalBlockFiles that have @@ -1692,6 +1801,42 @@ DILocation *DILocation::cloneWithDiscriminator(unsigned Discriminator) const { getInlinedAt()); } +unsigned DILocation::getBaseDiscriminator() const { + return getBaseDiscriminatorFromDiscriminator(getDiscriminator()); +} + +unsigned DILocation::getDuplicationFactor() const { + return getDuplicationFactorFromDiscriminator(getDiscriminator()); +} + +unsigned DILocation::getCopyIdentifier() const { + return getCopyIdentifierFromDiscriminator(getDiscriminator()); +} + +const DILocation *DILocation::setBaseDiscriminator(unsigned D) const { + if (D == 0) + return this; + else + return cloneWithDiscriminator(getPrefixEncodingFromUnsigned(D) << 1); +} + +const DILocation *DILocation::cloneWithDuplicationFactor(unsigned DF) const { + DF *= getDuplicationFactor(); + if (DF <= 1) + return this; + + unsigned BD = getBaseDiscriminator(); + unsigned CI = getCopyIdentifier() << (DF > 0x1f ? 14 : 7); + unsigned D = CI | (getPrefixEncodingFromUnsigned(DF) << 1); + + if (BD == 0) + D = (D << 1) | 1; + else + D = (D << (BD > 0x1f ? 14 : 7)) | (getPrefixEncodingFromUnsigned(BD) << 1); + + return cloneWithDiscriminator(D); +} + class DINamespace : public DIScope { friend class LLVMContextImpl; friend class MDNode; @@ -1918,7 +2063,7 @@ protected: DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Line, ArrayRef<Metadata *> Ops, uint32_t AlignInBits = 0) : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), - AlignInBits(AlignInBits) {} + AlignInBits(AlignInBits) {} ~DIVariable() = default; public: @@ -2108,7 +2253,7 @@ public: /// Retrieve the details of this fragment expression. static Optional<FragmentInfo> getFragmentInfo(expr_op_iterator Start, - expr_op_iterator End); + expr_op_iterator End); /// Retrieve the details of this fragment expression. Optional<FragmentInfo> getFragmentInfo() const { diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index a93c180df1b5..458c3cf29b0d 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -69,6 +69,11 @@ enum DiagnosticKind { DK_OptimizationFailure, DK_FirstRemark = DK_OptimizationRemark, DK_LastRemark = DK_OptimizationFailure, + DK_MachineOptimizationRemark, + DK_MachineOptimizationRemarkMissed, + DK_MachineOptimizationRemarkAnalysis, + DK_FirstMachineRemark = DK_MachineOptimizationRemark, + DK_LastMachineRemark = DK_MachineOptimizationRemarkAnalysis, DK_MIRParser, DK_PGOProfile, DK_Unsupported, @@ -342,19 +347,34 @@ private: const Twine &Msg; }; -/// Common features for diagnostics with an associated DebugLoc -class DiagnosticInfoWithDebugLocBase : public DiagnosticInfo { +class DiagnosticLocation { + StringRef Filename; + unsigned Line = 0; + unsigned Column = 0; public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + DiagnosticLocation() {} + DiagnosticLocation(const DebugLoc &DL); + DiagnosticLocation(const DISubprogram *SP); + + bool isValid() const { return !Filename.empty(); } + StringRef getFilename() const { return Filename; } + unsigned getLine() const { return Line; } + unsigned getColumn() const { return Column; } +}; + +/// Common features for diagnostics with an associated location. +class DiagnosticInfoWithLocationBase : public DiagnosticInfo { +public: + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. - DiagnosticInfoWithDebugLocBase(enum DiagnosticKind Kind, + DiagnosticInfoWithLocationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const Function &Fn, - const DebugLoc &DLoc) - : DiagnosticInfo(Kind, Severity), Fn(Fn), DLoc(DLoc) {} + const DiagnosticLocation &Loc) + : DiagnosticInfo(Kind, Severity), Fn(Fn), Loc(Loc) {} /// Return true if location information is available for this diagnostic. - bool isLocationAvailable() const; + bool isLocationAvailable() const { return Loc.isValid(); } /// Return a string with the location information for this diagnostic /// in the format "file:line:col". If location information is not available, @@ -366,18 +386,19 @@ public: void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const; const Function &getFunction() const { return Fn; } - const DebugLoc &getDebugLoc() const { return DLoc; } + DiagnosticLocation getLocation() const { return Loc; } private: /// Function where this diagnostic is triggered. const Function &Fn; /// Debug location where this diagnostic is triggered. - DebugLoc DLoc; + DiagnosticLocation Loc; }; -/// Common features for diagnostics dealing with optimization remarks. -class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithDebugLocBase { +/// \brief Common features for diagnostics dealing with optimization remarks +/// that are used by both IR and MIR passes. +class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithLocationBase { public: /// \brief Used to set IsVerbose via the stream interface. struct setIsVerbose {}; @@ -394,66 +415,29 @@ public: StringRef Key; std::string Val; // If set, the debug location corresponding to the value. - DebugLoc DLoc; + DiagnosticLocation Loc; explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {} - Argument(StringRef Key, Value *V); - Argument(StringRef Key, Type *T); + Argument(StringRef Key, const Value *V); + Argument(StringRef Key, const Type *T); Argument(StringRef Key, int N); Argument(StringRef Key, unsigned N); Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {} }; /// \p PassName is the name of the pass emitting this diagnostic. \p - /// RemarkName is a textual identifier for the remark. \p Fn is the function - /// where the diagnostic is being emitted. \p DLoc is the location information - /// to use in the diagnostic. If line table information is available, the - /// diagnostic will include the source code location. \p CodeRegion is IR - /// value (currently basic block) that the optimization operates on. This is - /// currently used to provide run-time hotness information with PGO. - DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, - enum DiagnosticSeverity Severity, - const char *PassName, StringRef RemarkName, - const Function &Fn, const DebugLoc &DLoc, - Value *CodeRegion = nullptr) - : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc), - PassName(PassName), RemarkName(RemarkName), CodeRegion(CodeRegion) {} - - /// \brief This is ctor variant allows a pass to build an optimization remark - /// from an existing remark. - /// - /// This is useful when a transformation pass (e.g LV) wants to emit a remark - /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis - /// remark. The string \p Prepend will be emitted before the original - /// message. - DiagnosticInfoOptimizationBase(const char *PassName, StringRef Prepend, - const DiagnosticInfoOptimizationBase &Orig) - : DiagnosticInfoWithDebugLocBase((DiagnosticKind)Orig.getKind(), - Orig.getSeverity(), Orig.getFunction(), - Orig.getDebugLoc()), - PassName(PassName), RemarkName(Orig.RemarkName), - CodeRegion(Orig.getCodeRegion()) { - *this << Prepend; - std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); - } - - /// Legacy interface. - /// \p PassName is the name of the pass emitting this diagnostic. - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is - /// the location information to use in the diagnostic. If line table + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Fn is the function where the diagnostic is being emitted. + /// \p Loc is the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code - /// location. \p Msg is the message to show. Note that this class does not - /// copy this message, so this reference must be valid for the whole life time - /// of the diagnostic. + /// location. DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, - const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc), - PassName(PassName), Hotness(Hotness) { - Args.push_back(Argument(Msg.str())); - } + const char *PassName, StringRef RemarkName, + const Function &Fn, + const DiagnosticLocation &Loc) + : DiagnosticInfoWithLocationBase(Kind, Severity, Fn, Loc), + PassName(PassName), RemarkName(RemarkName) {} DiagnosticInfoOptimizationBase &operator<<(StringRef S); DiagnosticInfoOptimizationBase &operator<<(Argument A); @@ -475,33 +459,45 @@ public: Optional<uint64_t> getHotness() const { return Hotness; } void setHotness(Optional<uint64_t> H) { Hotness = H; } - Value *getCodeRegion() const { return CodeRegion; } - bool isVerbose() const { return IsVerbose; } static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() >= DK_FirstRemark && - DI->getKind() <= DK_LastRemark; + return (DI->getKind() >= DK_FirstRemark && + DI->getKind() <= DK_LastRemark) || + (DI->getKind() >= DK_FirstMachineRemark && + DI->getKind() <= DK_LastMachineRemark); } -private: + bool isPassed() const { + return (getKind() == DK_OptimizationRemark || + getKind() == DK_MachineOptimizationRemark); + } + + bool isMissed() const { + return (getKind() == DK_OptimizationRemarkMissed || + getKind() == DK_MachineOptimizationRemarkMissed); + } + + bool isAnalysis() const { + return (getKind() == DK_OptimizationRemarkAnalysis || + getKind() == DK_MachineOptimizationRemarkAnalysis); + } + +protected: /// Name of the pass that triggers this report. If this matches the /// regular expression given in -Rpass=regexp, then the remark will /// be emitted. const char *PassName; - /// Textual identifier for the remark. Can be used by external tools reading - /// the YAML output file for optimization remarks to identify the remark. + /// Textual identifier for the remark (single-word, camel-case). Can be used + /// by external tools reading the YAML output file for optimization remarks to + /// identify the remark. StringRef RemarkName; /// If profile information is available, this is the number of times the /// corresponding code was executed in a profile instrumentation run. Optional<uint64_t> Hotness; - /// The IR value (currently basic block) that the optimization operates on. - /// This is currently used to provide run-time hotness information with PGO. - Value *CodeRegion; - /// Arguments collected via the streaming interface. SmallVector<Argument, 4> Args; @@ -516,106 +512,186 @@ private: friend struct yaml::MappingTraits<DiagnosticInfoOptimizationBase *>; }; -/// Diagnostic information for applied optimization remarks. -class OptimizationRemark : public DiagnosticInfoOptimizationBase { +/// \brief Common features for diagnostics dealing with optimization remarks +/// that are used by IR passes. +class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase { public: - /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass=, then the - /// diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the - /// diagnostic. If line table information is available, the diagnostic - /// will include the source code location. \p Msg is the message to show. - /// Note that this class does not copy this message, so this reference - /// must be valid for the whole life time of the diagnostic. - OptimizationRemark(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemark, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} + /// \p PassName is the name of the pass emitting this diagnostic. \p + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Fn is the function where the diagnostic is being emitted. + /// \p Loc is the location information to use in the diagnostic. If line table + /// information is available, the diagnostic will include the source code + /// location. \p CodeRegion is IR value (currently basic block) that the + /// optimization operates on. This is currently used to provide run-time + /// hotness information with PGO. + DiagnosticInfoIROptimization(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const char *PassName, StringRef RemarkName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Value *CodeRegion = nullptr) + : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, RemarkName, Fn, + Loc), + CodeRegion(CodeRegion) {} + /// \brief This is ctor variant allows a pass to build an optimization remark + /// from an existing remark. + /// + /// This is useful when a transformation pass (e.g LV) wants to emit a remark + /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis + /// remark. The string \p Prepend will be emitted before the original + /// message. + DiagnosticInfoIROptimization(const char *PassName, StringRef Prepend, + const DiagnosticInfoIROptimization &Orig) + : DiagnosticInfoOptimizationBase( + (DiagnosticKind)Orig.getKind(), Orig.getSeverity(), PassName, + Orig.RemarkName, Orig.getFunction(), Orig.getLocation()), + CodeRegion(Orig.getCodeRegion()) { + *this << Prepend; + std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); + } + + /// Legacy interface. + /// \p PassName is the name of the pass emitting this diagnostic. + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is + /// the location information to use in the diagnostic. If line table + /// information is available, the diagnostic will include the source code + /// location. \p Msg is the message to show. Note that this class does not + /// copy this message, so this reference must be valid for the whole life time + /// of the diagnostic. + DiagnosticInfoIROptimization(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, "", Fn, Loc) { + *this << Msg.str(); + } + + const Value *getCodeRegion() const { return CodeRegion; } + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark; + } + +private: + /// The IR value (currently basic block) that the optimization operates on. + /// This is currently used to provide run-time hotness information with PGO. + const Value *CodeRegion; +}; + +/// Diagnostic information for applied optimization remarks. +class OptimizationRemark : public DiagnosticInfoIROptimization { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass=, then the diagnostic will - /// be emitted. \p RemarkName is a textual identifier for the remark. \p - /// DLoc is the debug location and \p CodeRegion is the region that the - /// optimization operates on (currently on block is supported). + /// be emitted. \p RemarkName is a textual identifier for the remark (single- + /// word, camel-case). \p Loc is the debug location and \p CodeRegion is the + /// region that the optimization operates on (currently only block is + /// supported). OptimizationRemark(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, const Value *CodeRegion); - /// Same as above but the debug location and code region is derived from \p + /// Same as above, but the debug location and code region are derived from \p /// Instr. OptimizationRemark(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); + + /// Same as above, but the debug location and code region are derived from \p + /// Func. + OptimizationRemark(const char *PassName, StringRef RemarkName, + const Function *Func); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemark; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; -}; + bool isEnabled() const override { return isEnabled(getPassName()); } -/// Diagnostic information for missed-optimization remarks. -class OptimizationRemarkMissed : public DiagnosticInfoOptimizationBase { -public: +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass-missed=, then the + /// this name matches the regular expression given in -Rpass=, then the /// diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic /// will include the source code location. \p Msg is the message to show. /// Note that this class does not copy this message, so this reference /// must be valid for the whole life time of the diagnostic. - OptimizationRemarkMissed(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} + OptimizationRemark(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, + Fn, Loc, Msg) {} + + friend void emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); +}; +/// Diagnostic information for missed-optimization remarks. +class OptimizationRemarkMissed : public DiagnosticInfoIROptimization { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-missed=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, + const Value *CodeRegion); /// \brief Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkMissed; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; + bool isEnabled() const override { return isEnabled(getPassName()); } + +private: + /// This is deprecated now and only used by the function API below. + /// \p PassName is the name of the pass emitting this diagnostic. If + /// this name matches the regular expression given in -Rpass-missed=, then the + /// diagnostic will be emitted. \p Fn is the function where the diagnostic + /// is being emitted. \p Loc is the location information to use in the + /// diagnostic. If line table information is available, the diagnostic + /// will include the source code location. \p Msg is the message to show. + /// Note that this class does not copy this message, so this reference + /// must be valid for the whole life time of the diagnostic. + OptimizationRemarkMissed(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark, + PassName, Fn, Loc, Msg) {} + + friend void emitOptimizationRemarkMissed(LLVMContext &Ctx, + const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); }; /// Diagnostic information for optimization analysis remarks. -class OptimizationRemarkAnalysis : public DiagnosticInfoOptimizationBase { +class OptimizationRemarkAnalysis : public DiagnosticInfoIROptimization { public: - /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass-analysis=, then - /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the - /// diagnostic. If line table information is available, the diagnostic will - /// include the source code location. \p Msg is the message to show. Note that - /// this class does not copy this message, so this reference must be valid for - /// the whole life time of the diagnostic. - OptimizationRemarkAnalysis(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkAnalysis, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} - /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, + const Value *CodeRegion); /// \brief This is ctor variant allows a pass to build an optimization remark /// from an existing remark. @@ -626,19 +702,23 @@ public: /// message. OptimizationRemarkAnalysis(const char *PassName, StringRef Prepend, const OptimizationRemarkAnalysis &Orig) - : DiagnosticInfoOptimizationBase(PassName, Prepend, Orig) {} + : DiagnosticInfoIROptimization(PassName, Prepend, Orig) {} /// \brief Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysis; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; + bool isEnabled() const override { + return shouldAlwaysPrint() || isEnabled(getPassName()); + } static const char *AlwaysPrint; @@ -646,24 +726,65 @@ public: protected: OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, - const Twine &Msg, Optional<uint64_t> Hotness) - : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, Fn, DLoc, Msg, - Hotness) {} + const Function &Fn, const DiagnosticLocation &Loc, + const Twine &Msg) + : DiagnosticInfoIROptimization(Kind, DS_Remark, PassName, Fn, Loc, Msg) {} OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, - StringRef RemarkName, const DebugLoc &DLoc, - Value *CodeRegion); + StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion); + +private: + /// This is deprecated now and only used by the function API below. + /// \p PassName is the name of the pass emitting this diagnostic. If + /// this name matches the regular expression given in -Rpass-analysis=, then + /// the diagnostic will be emitted. \p Fn is the function where the diagnostic + /// is being emitted. \p Loc is the location information to use in the + /// diagnostic. If line table information is available, the diagnostic will + /// include the source code location. \p Msg is the message to show. Note that + /// this class does not copy this message, so this reference must be valid for + /// the whole life time of the diagnostic. + OptimizationRemarkAnalysis(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark, + PassName, Fn, Loc, Msg) {} + + friend void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, + const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); }; /// Diagnostic information for optimization analysis remarks related to /// floating-point non-commutativity. class OptimizationRemarkAnalysisFPCommute : public OptimizationRemarkAnalysis { public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass-analysis=, then the + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). The front-end will append its own message related to + /// options that address floating-point non-commutativity. + OptimizationRemarkAnalysisFPCommute(const char *PassName, + StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion) + : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, + PassName, RemarkName, Loc, CodeRegion) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_OptimizationRemarkAnalysisFPCommute; + } + +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass-analysis=, then /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address @@ -671,37 +792,42 @@ public: /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisFPCommute(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) + const DiagnosticLocation &Loc, + const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, - PassName, Fn, DLoc, Msg, Hotness) {} + PassName, Fn, Loc, Msg) {} + friend void emitOptimizationRemarkAnalysisFPCommute( + LLVMContext &Ctx, const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); +}; +/// Diagnostic information for optimization analysis remarks related to +/// pointer aliasing. +class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). The - /// front-end will append its own message related to options that address - /// floating-point non-commutativity. - OptimizationRemarkAnalysisFPCommute(const char *PassName, - StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion) - : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, - PassName, RemarkName, DLoc, CodeRegion) {} + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). The front-end will append its own message related to + /// options that address pointer aliasing legality. + OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion) + : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, + PassName, RemarkName, Loc, CodeRegion) {} static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() == DK_OptimizationRemarkAnalysisFPCommute; + return DI->getKind() == DK_OptimizationRemarkAnalysisAliasing; } -}; -/// Diagnostic information for optimization analysis remarks related to -/// pointer aliasing. -class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis { -public: +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass-analysis=, then /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address @@ -709,26 +835,14 @@ public: /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisAliasing(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, - PassName, Fn, DLoc, Msg, Hotness) {} - - /// \p PassName is the name of the pass emitting this diagnostic. If this name - /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). The - /// front-end will append its own message related to options that address - /// pointer aliasing legality. - OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion) + const DiagnosticLocation &Loc, + const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, - PassName, RemarkName, DLoc, CodeRegion) {} + PassName, Fn, Loc, Msg) {} - static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() == DK_OptimizationRemarkAnalysisAliasing; - } + friend void emitOptimizationRemarkAnalysisAliasing( + LLVMContext &Ctx, const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); }; /// Diagnostic information for machine IR parser. @@ -771,73 +885,97 @@ public: // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef) -/// Emit an optimization-applied message. \p PassName is the name of the pass -/// emitting the message. If -Rpass= is given and \p PassName matches the -/// regular expression in -Rpass, then the remark will be emitted. \p Fn is -/// the function triggering the remark, \p DLoc is the debug location where -/// the diagnostic is generated. \p Msg is the message string to use. +/// \brief Legacy interface to emit an optimization-applied message. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If -Rpass= is +/// given and \p PassName matches the regular expression in -Rpass, then the +/// remark will be emitted. \p Fn is the function triggering the remark, \p Loc +/// is the debug location where the diagnostic is generated. \p Msg is the +/// message string to use. void emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization-missed message. \p PassName is the name of the -/// pass emitting the message. If -Rpass-missed= is given and \p PassName -/// matches the regular expression in -Rpass, then the remark will be -/// emitted. \p Fn is the function triggering the remark, \p DLoc is the -/// debug location where the diagnostic is generated. \p Msg is the +/// \brief Legacy interface to emit an optimization-missed message. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If -Rpass-missed= +/// is given and \p PassName matches the regular expression in -Rpass, then the +/// remark will be emitted. \p Fn is the function triggering the remark, \p Loc +/// is the debug location where the diagnostic is generated. \p Msg is the /// message string to use. void emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark message. \p PassName is the name of -/// the pass emitting the message. If -Rpass-analysis= is given and \p -/// PassName matches the regular expression in -Rpass, then the remark will be -/// emitted. \p Fn is the function triggering the remark, \p DLoc is the debug -/// location where the diagnostic is generated. \p Msg is the message string -/// to use. +/// \brief Legacy interface to emit an optimization analysis remark message. +/// Use (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If +/// -Rpass-analysis= is given and \p PassName matches the regular expression in +/// -Rpass, then the remark will be emitted. \p Fn is the function triggering +/// the remark, \p Loc is the debug location where the diagnostic is +/// generated. \p Msg is the message string to use. void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark related to messages about -/// floating-point non-commutativity. \p PassName is the name of the pass -/// emitting the message. If -Rpass-analysis= is given and \p PassName matches -/// the regular expression in -Rpass, then the remark will be emitted. \p Fn is -/// the function triggering the remark, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. +/// \brief Legacy interface to emit an optimization analysis remark related to +/// messages about floating-point non-commutativity. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If +/// -Rpass-analysis= is given and \p PassName matches the regular expression in +/// -Rpass, then the remark will be emitted. \p Fn is the function triggering +/// the remark, \p Loc is the debug location where the diagnostic is +/// generated. \p Msg is the message string to use. void emitOptimizationRemarkAnalysisFPCommute(LLVMContext &Ctx, const char *PassName, const Function &Fn, - const DebugLoc &DLoc, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark related to messages about -/// pointer aliasing. \p PassName is the name of the pass emitting the message. +/// \brief Legacy interface to emit an optimization analysis remark related to +/// messages about pointer aliasing. Use (Machine)OptimizationRemarkEmitter +/// instead. +/// +/// \p PassName is the name of the pass emitting the message. /// If -Rpass-analysis= is given and \p PassName matches the regular expression /// in -Rpass, then the remark will be emitted. \p Fn is the function triggering -/// the remark, \p DLoc is the debug location where the diagnostic is generated. +/// the remark, \p Loc is the debug location where the diagnostic is generated. /// \p Msg is the message string to use. void emitOptimizationRemarkAnalysisAliasing(LLVMContext &Ctx, const char *PassName, const Function &Fn, - const DebugLoc &DLoc, + const DiagnosticLocation &Loc, const Twine &Msg); /// Diagnostic information for optimization failures. -class DiagnosticInfoOptimizationFailure - : public DiagnosticInfoOptimizationBase { +class DiagnosticInfoOptimizationFailure : public DiagnosticInfoIROptimization { public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. - DiagnosticInfoOptimizationFailure(const Function &Fn, const DebugLoc &DLoc, + DiagnosticInfoOptimizationFailure(const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) - : DiagnosticInfoOptimizationBase(DK_OptimizationFailure, DS_Warning, - nullptr, Fn, DLoc, Msg) {} + : DiagnosticInfoIROptimization(DK_OptimizationFailure, DS_Warning, + nullptr, Fn, Loc, Msg) {} + + /// \p PassName is the name of the pass emitting this diagnostic. \p + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Loc is the debug location and \p CodeRegion is the + /// region that the optimization operates on (currently basic block is + /// supported). + DiagnosticInfoOptimizationFailure(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationFailure; @@ -848,22 +986,22 @@ public: }; /// Diagnostic information for unsupported feature in backend. -class DiagnosticInfoUnsupported - : public DiagnosticInfoWithDebugLocBase { +class DiagnosticInfoUnsupported : public DiagnosticInfoWithLocationBase { private: Twine Msg; public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. - DiagnosticInfoUnsupported(const Function &Fn, const Twine &Msg, - DebugLoc DLoc = DebugLoc(), - DiagnosticSeverity Severity = DS_Error) - : DiagnosticInfoWithDebugLocBase(DK_Unsupported, Severity, Fn, DLoc), + DiagnosticInfoUnsupported( + const Function &Fn, const Twine &Msg, + const DiagnosticLocation &Loc = DiagnosticLocation(), + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfoWithLocationBase(DK_Unsupported, Severity, Fn, Loc), Msg(Msg) {} static bool classof(const DiagnosticInfo *DI) { @@ -874,19 +1012,6 @@ public: void print(DiagnosticPrinter &DP) const override; }; - -/// Emit a warning when loop vectorization is specified but fails. \p Fn is the -/// function triggering the warning, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. -void emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg); - -/// Emit a warning when loop interleaving is specified but fails. \p Fn is the -/// function triggering the warning, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. -void emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg); - } // end namespace llvm #endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/include/llvm/IR/Dominators.h b/include/llvm/IR/Dominators.h index 7c733bac8da0..cae03d33a7ee 100644 --- a/include/llvm/IR/Dominators.h +++ b/include/llvm/IR/Dominators.h @@ -16,17 +16,21 @@ #define LLVM_IR_DOMINATORS_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/GenericDomTree.h" +#include <utility> namespace llvm { class Function; -class BasicBlock; +class Instruction; +class Module; class raw_ostream; extern template class DomTreeNodeBase<BasicBlock>; @@ -43,24 +47,37 @@ typedef DomTreeNodeBase<BasicBlock> DomTreeNode; class BasicBlockEdge { const BasicBlock *Start; const BasicBlock *End; + public: BasicBlockEdge(const BasicBlock *Start_, const BasicBlock *End_) : - Start(Start_), End(End_) { } + Start(Start_), End(End_) {} + + BasicBlockEdge(const std::pair<BasicBlock *, BasicBlock *> &Pair) + : Start(Pair.first), End(Pair.second) {} + + BasicBlockEdge(const std::pair<const BasicBlock *, const BasicBlock *> &Pair) + : Start(Pair.first), End(Pair.second) {} + const BasicBlock *getStart() const { return Start; } + const BasicBlock *getEnd() const { return End; } + bool isSingleEdge() const; }; template <> struct DenseMapInfo<BasicBlockEdge> { - static unsigned getHashValue(const BasicBlockEdge *V); typedef DenseMapInfo<const BasicBlock *> BBInfo; + + static unsigned getHashValue(const BasicBlockEdge *V); + static inline BasicBlockEdge getEmptyKey() { return BasicBlockEdge(BBInfo::getEmptyKey(), BBInfo::getEmptyKey()); } + static inline BasicBlockEdge getTombstoneKey() { return BasicBlockEdge(BBInfo::getTombstoneKey(), BBInfo::getTombstoneKey()); } @@ -69,6 +86,7 @@ template <> struct DenseMapInfo<BasicBlockEdge> { return hash_combine(BBInfo::getHashValue(Edge.getStart()), BBInfo::getHashValue(Edge.getEnd())); } + static bool isEqual(const BasicBlockEdge &LHS, const BasicBlockEdge &RHS) { return BBInfo::isEqual(LHS.getStart(), RHS.getStart()) && BBInfo::isEqual(LHS.getEnd(), RHS.getEnd()); @@ -102,19 +120,17 @@ public: recalculate(F); } + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); + /// \brief Returns *false* if the other dominator tree matches this dominator /// tree. inline bool compare(const DominatorTree &Other) const { const DomTreeNode *R = getRootNode(); const DomTreeNode *OtherR = Other.getRootNode(); - - if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) - return true; - - if (Base::compare(Other)) - return true; - - return false; + return !R || !OtherR || R->getBlock() != OtherR->getBlock() || + Base::compare(Other); } // Ensure base-class overloads are visible. @@ -205,6 +221,7 @@ class DominatorTreePrinterPass public: explicit DominatorTreePrinterPass(raw_ostream &OS); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; @@ -240,6 +257,6 @@ public: void print(raw_ostream &OS, const Module *M = nullptr) const override; }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_DOMINATORS_H diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 1854d413c627..a3762a44ccb6 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -18,6 +18,7 @@ #ifndef LLVM_IR_FUNCTION_H #define LLVM_IR_FUNCTION_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringRef.h" @@ -47,23 +48,23 @@ class DISubprogram; class Function : public GlobalObject, public ilist_node<Function> { public: - typedef SymbolTableList<Argument> ArgumentListType; typedef SymbolTableList<BasicBlock> BasicBlockListType; // BasicBlock iterators... typedef BasicBlockListType::iterator iterator; typedef BasicBlockListType::const_iterator const_iterator; - typedef ArgumentListType::iterator arg_iterator; - typedef ArgumentListType::const_iterator const_arg_iterator; + typedef Argument *arg_iterator; + typedef const Argument *const_arg_iterator; private: // Important things that make up a function! BasicBlockListType BasicBlocks; ///< The basic blocks - mutable ArgumentListType ArgumentList; ///< The formal arguments + mutable Argument *Arguments; ///< The formal arguments + size_t NumArgs; std::unique_ptr<ValueSymbolTable> SymTab; ///< Symbol table of args/instructions - AttributeSet AttributeSets; ///< Parameter attributes + AttributeList AttributeSets; ///< Parameter attributes /* * Value::SubclassData @@ -102,6 +103,8 @@ private: void BuildLazyArguments() const; + void clearArguments(); + /// Function ctor - If the (optional) Module argument is specified, the /// function is automatically inserted into the end of the function list for /// the module. @@ -121,10 +124,12 @@ public: // Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// Returns the type of the ret val. - Type *getReturnType() const; /// Returns the FunctionType for me. - FunctionType *getFunctionType() const; + FunctionType *getFunctionType() const { + return cast<FunctionType>(getValueType()); + } + /// Returns the type of the ret val. + Type *getReturnType() const { return getFunctionType()->getReturnType(); } /// getContext - Return a reference to the LLVMContext associated with this /// function. @@ -132,10 +137,16 @@ public: /// isVarArg - Return true if this function takes a variable number of /// arguments. - bool isVarArg() const; + bool isVarArg() const { return getFunctionType()->isVarArg(); } - bool isMaterializable() const; - void setIsMaterializable(bool V); + bool isMaterializable() const { + return getGlobalObjectSubClassData() & (1 << IsMaterializableBit); + } + void setIsMaterializable(bool V) { + unsigned Mask = 1 << IsMaterializableBit; + setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | + (V ? Mask : 0u)); + } /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an @@ -173,42 +184,45 @@ public: } /// @brief Return the attribute list for this Function. - AttributeSet getAttributes() const { return AttributeSets; } + AttributeList getAttributes() const { return AttributeSets; } /// @brief Set the attribute list for this Function. - void setAttributes(AttributeSet Attrs) { AttributeSets = Attrs; } + void setAttributes(AttributeList Attrs) { AttributeSets = Attrs; } /// @brief Add function attributes to this function. void addFnAttr(Attribute::AttrKind Kind) { - addAttribute(AttributeSet::FunctionIndex, Kind); + addAttribute(AttributeList::FunctionIndex, Kind); } /// @brief Add function attributes to this function. void addFnAttr(StringRef Kind, StringRef Val = StringRef()) { - addAttribute(AttributeSet::FunctionIndex, + addAttribute(AttributeList::FunctionIndex, Attribute::get(getContext(), Kind, Val)); } void addFnAttr(Attribute Attr) { - addAttribute(AttributeSet::FunctionIndex, Attr); + addAttribute(AttributeList::FunctionIndex, Attr); } /// @brief Remove function attributes from this function. void removeFnAttr(Attribute::AttrKind Kind) { - removeAttribute(AttributeSet::FunctionIndex, Kind); + removeAttribute(AttributeList::FunctionIndex, Kind); } /// @brief Remove function attribute from this function. void removeFnAttr(StringRef Kind) { setAttributes(AttributeSets.removeAttribute( - getContext(), AttributeSet::FunctionIndex, Kind)); + getContext(), AttributeList::FunctionIndex, Kind)); } /// \brief Set the entry count for this function. /// /// Entry count is the number of times this function was executed based on - /// pgo data. - void setEntryCount(uint64_t Count); + /// pgo data. \p Imports points to a set of GUIDs that needs to be imported + /// by the function for sample PGO, to enable the same inlines as the + /// profiled optimized binary. + void setEntryCount(uint64_t Count, + const DenseSet<GlobalValue::GUID> *Imports = nullptr); /// \brief Get the entry count for this function. /// @@ -216,6 +230,10 @@ public: /// pgo data. Optional<uint64_t> getEntryCount() const; + /// Returns the set of GUIDs that needs to be imported to the function for + /// sample PGO, to enable the same inlines as the profiled optimized binary. + DenseSet<GlobalValue::GUID> getImportGUIDs() const; + /// Set the section prefix for this function. void setSectionPrefix(StringRef Prefix); @@ -232,17 +250,17 @@ public: /// @brief Return the attribute for the given attribute kind. Attribute getFnAttribute(Attribute::AttrKind Kind) const { - return getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeList::FunctionIndex, Kind); } Attribute getFnAttribute(StringRef Kind) const { - return getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeList::FunctionIndex, Kind); } /// \brief Return the stack alignment for the function. unsigned getFnStackAlignment() const { if (!hasFnAttribute(Attribute::StackAlignment)) return 0; - return AttributeSets.getStackAlignment(AttributeSet::FunctionIndex); + return AttributeSets.getStackAlignment(AttributeList::FunctionIndex); } /// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm @@ -261,7 +279,7 @@ public: void addAttribute(unsigned i, Attribute Attr); /// @brief adds the attributes to the list of attributes. - void addAttributes(unsigned i, AttributeSet Attrs); + void addAttributes(unsigned i, AttributeList Attrs); /// @brief removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute::AttrKind Kind); @@ -270,13 +288,18 @@ public: void removeAttribute(unsigned i, StringRef Kind); /// @brief removes the attributes from the list of attributes. - void removeAttributes(unsigned i, AttributeSet Attrs); + void removeAttributes(unsigned i, AttributeList Attrs); /// @brief check if an attributes is in the list of attributes. bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const { return getAttributes().hasAttribute(i, Kind); } + /// @brief check if an attributes is in the list of attributes. + bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const { + return getAttributes().hasParamAttribute(ArgNo, Kind); + } + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { return AttributeSets.getAttribute(i, Kind); } @@ -496,19 +519,6 @@ public: /// Get the underlying elements of the Function... the basic block list is /// empty for external functions. /// - const ArgumentListType &getArgumentList() const { - CheckLazyArguments(); - return ArgumentList; - } - ArgumentListType &getArgumentList() { - CheckLazyArguments(); - return ArgumentList; - } - - static ArgumentListType Function::*getSublistAccess(Argument*) { - return &Function::ArgumentList; - } - const BasicBlockListType &getBasicBlockList() const { return BasicBlocks; } BasicBlockListType &getBasicBlockList() { return BasicBlocks; } @@ -549,20 +559,20 @@ public: arg_iterator arg_begin() { CheckLazyArguments(); - return ArgumentList.begin(); + return Arguments; } const_arg_iterator arg_begin() const { CheckLazyArguments(); - return ArgumentList.begin(); + return Arguments; } arg_iterator arg_end() { CheckLazyArguments(); - return ArgumentList.end(); + return Arguments + NumArgs; } const_arg_iterator arg_end() const { CheckLazyArguments(); - return ArgumentList.end(); + return Arguments + NumArgs; } iterator_range<arg_iterator> args() { @@ -574,8 +584,8 @@ public: /// @} - size_t arg_size() const; - bool arg_empty() const; + size_t arg_size() const { return NumArgs; } + bool arg_empty() const { return arg_size() == 0; } /// \brief Check whether this function has a personality function. bool hasPersonalityFn() const { @@ -671,6 +681,9 @@ public: /// to \a DISubprogram. DISubprogram *getSubprogram() const; + /// Returns true if we should emit debug info for profiling. + bool isDebugInfoForProfiling() const; + private: void allocHungoffUselist(); template<int Idx> void setHungoffOperand(Constant *C); diff --git a/include/llvm/IR/GlobalIndirectSymbol.h b/include/llvm/IR/GlobalIndirectSymbol.h index 671309e85d19..212703af7101 100644 --- a/include/llvm/IR/GlobalIndirectSymbol.h +++ b/include/llvm/IR/GlobalIndirectSymbol.h @@ -48,27 +48,31 @@ public: setOperand(0, Symbol); } const Constant *getIndirectSymbol() const { - return const_cast<GlobalIndirectSymbol *>(this)->getIndirectSymbol(); + return getOperand(0); } Constant *getIndirectSymbol() { - return getOperand(0); + return const_cast<Constant *>( + static_cast<const GlobalIndirectSymbol *>(this)->getIndirectSymbol()); } const GlobalObject *getBaseObject() const { - return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(); + return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets()); } GlobalObject *getBaseObject() { - return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets()); + return const_cast<GlobalObject *>( + static_cast<const GlobalIndirectSymbol *>(this)->getBaseObject()); } const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const { - return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(DL, Offset); - } - GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { return dyn_cast<GlobalObject>( getIndirectSymbol()->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); } + GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { + return const_cast<GlobalObject *>( + static_cast<const GlobalIndirectSymbol *>(this) + ->getBaseObject(DL, Offset)); + } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { diff --git a/include/llvm/IR/GlobalObject.h b/include/llvm/IR/GlobalObject.h index 1057f564aab3..f3789bafefe3 100644 --- a/include/llvm/IR/GlobalObject.h +++ b/include/llvm/IR/GlobalObject.h @@ -63,8 +63,17 @@ public: } void setAlignment(unsigned Align); - unsigned getGlobalObjectSubClassData() const; - void setGlobalObjectSubClassData(unsigned Val); + unsigned getGlobalObjectSubClassData() const { + unsigned ValueData = getGlobalValueSubClassData(); + return ValueData >> GlobalObjectBits; + } + + void setGlobalObjectSubClassData(unsigned Val) { + unsigned OldData = getGlobalValueSubClassData(); + setGlobalValueSubClassData((OldData & GlobalObjectMask) | + (Val << GlobalObjectBits)); + assert(getGlobalObjectSubClassData() == Val && "representation error"); + } /// Check if this global has a custom object file section. /// diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index c6398aaa4847..bb30fa8be867 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -211,9 +211,10 @@ public: } bool hasComdat() const { return getComdat() != nullptr; } - Comdat *getComdat(); - const Comdat *getComdat() const { - return const_cast<GlobalValue *>(this)->getComdat(); + const Comdat *getComdat() const; + Comdat *getComdat() { + return const_cast<Comdat *>( + static_cast<const GlobalValue *>(this)->getComdat()); } VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } @@ -514,10 +515,11 @@ public: // increased. bool canIncreaseAlignment() const; - const GlobalObject *getBaseObject() const { - return const_cast<GlobalValue *>(this)->getBaseObject(); + const GlobalObject *getBaseObject() const; + GlobalObject *getBaseObject() { + return const_cast<GlobalObject *>( + static_cast<const GlobalValue *>(this)->getBaseObject()); } - GlobalObject *getBaseObject(); /// Returns whether this is a reference to an absolute symbol. bool isAbsoluteSymbolRef() const; diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 1d9c16989de9..bc689f3b01d7 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -33,6 +33,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -75,7 +76,7 @@ class IRBuilderCallbackInserter : IRBuilderDefaultInserter { public: IRBuilderCallbackInserter(std::function<void(Instruction *)> Callback) - : Callback(Callback) {} + : Callback(std::move(Callback)) {} protected: void InsertHelper(Instruction *I, const Twine &Name, @@ -560,6 +561,22 @@ public: Type *ResultType, const Twine &Name = ""); + /// Create a call to intrinsic \p ID with 2 operands which is mangled on the + /// first type. + CallInst *CreateBinaryIntrinsic(Intrinsic::ID ID, + Value *LHS, Value *RHS, + const Twine &Name = ""); + + /// Create call to the minnum intrinsic. + CallInst *CreateMinNum(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, Name); + } + + /// Create call to the maxnum intrinsic. + CallInst *CreateMaxNum(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, Name); + } + private: /// \brief Create a call to a masked intrinsic with given Id. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef<Value *> Ops, @@ -1073,9 +1090,15 @@ public: // Instruction creation methods: Memory Instructions //===--------------------------------------------------------------------===// + AllocaInst *CreateAlloca(Type *Ty, unsigned AddrSpace, + Value *ArraySize = nullptr, const Twine &Name = "") { + return Insert(new AllocaInst(Ty, AddrSpace, ArraySize), Name); + } + AllocaInst *CreateAlloca(Type *Ty, Value *ArraySize = nullptr, const Twine &Name = "") { - return Insert(new AllocaInst(Ty, ArraySize), Name); + const DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + return Insert(new AllocaInst(Ty, DL.getAllocaAddrSpace(), ArraySize), Name); } // \brief Provided to resolve 'CreateLoad(Ptr, "...")' correctly, instead of // converting the string to 'bool' for the isVolatile parameter. @@ -1790,24 +1813,16 @@ public: return V; } - /// \brief Create an assume intrinsic call that represents an alignment - /// assumption on the provided pointer. - /// - /// An optional offset can be provided, and if it is provided, the offset - /// must be subtracted from the provided pointer to get the pointer with the - /// specified alignment. - CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, - unsigned Alignment, - Value *OffsetValue = nullptr) { - assert(isa<PointerType>(PtrValue->getType()) && - "trying to create an alignment assumption on a non-pointer?"); - - PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); - Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); +private: + /// \brief Helper function that creates an assume intrinsic call that + /// represents an alignment assumption on the provided Ptr, Mask, Type + /// and Offset. + CallInst *CreateAlignmentAssumptionHelper(const DataLayout &DL, + Value *PtrValue, Value *Mask, + Type *IntPtrTy, + Value *OffsetValue) { Value *PtrIntValue = CreatePtrToInt(PtrValue, IntPtrTy, "ptrint"); - Value *Mask = ConstantInt::get(IntPtrTy, - Alignment > 0 ? Alignment - 1 : 0); if (OffsetValue) { bool IsOffsetZero = false; if (ConstantInt *CI = dyn_cast<ConstantInt>(OffsetValue)) @@ -1824,9 +1839,60 @@ public: Value *Zero = ConstantInt::get(IntPtrTy, 0); Value *MaskedPtr = CreateAnd(PtrIntValue, Mask, "maskedptr"); Value *InvCond = CreateICmpEQ(MaskedPtr, Zero, "maskcond"); - return CreateAssumption(InvCond); } + +public: + /// \brief Create an assume intrinsic call that represents an alignment + /// assumption on the provided pointer. + /// + /// An optional offset can be provided, and if it is provided, the offset + /// must be subtracted from the provided pointer to get the pointer with the + /// specified alignment. + CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, + unsigned Alignment, + Value *OffsetValue = nullptr) { + assert(isa<PointerType>(PtrValue->getType()) && + "trying to create an alignment assumption on a non-pointer?"); + PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); + Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); + + Value *Mask = ConstantInt::get(IntPtrTy, Alignment > 0 ? Alignment - 1 : 0); + return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy, + OffsetValue); + } + // + /// \brief Create an assume intrinsic call that represents an alignment + /// assumption on the provided pointer. + /// + /// An optional offset can be provided, and if it is provided, the offset + /// must be subtracted from the provided pointer to get the pointer with the + /// specified alignment. + /// + /// This overload handles the condition where the Alignment is dependent + /// on an existing value rather than a static value. + CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, + Value *Alignment, + Value *OffsetValue = nullptr) { + assert(isa<PointerType>(PtrValue->getType()) && + "trying to create an alignment assumption on a non-pointer?"); + PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); + Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); + + if (Alignment->getType() != IntPtrTy) + Alignment = CreateIntCast(Alignment, IntPtrTy, /*isSigned*/ true, + "alignmentcast"); + Value *IsPositive = + CreateICmp(CmpInst::ICMP_SGT, Alignment, + ConstantInt::get(Alignment->getType(), 0), "ispositive"); + Value *PositiveMask = + CreateSub(Alignment, ConstantInt::get(IntPtrTy, 1), "positivemask"); + Value *Mask = CreateSelect(IsPositive, PositiveMask, + ConstantInt::get(IntPtrTy, 0), "mask"); + + return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy, + OffsetValue); + } }; // Create wrappers for C Binding types (see CBindingWrapping.h). diff --git a/include/llvm/IR/InlineAsm.h b/include/llvm/IR/InlineAsm.h index f95509b9b09a..5d2f72d211ff 100644 --- a/include/llvm/IR/InlineAsm.h +++ b/include/llvm/IR/InlineAsm.h @@ -1,4 +1,4 @@ -//===-- llvm/InlineAsm.h - Class to represent inline asm strings-*- C++ -*-===// +//===- llvm/InlineAsm.h - Class to represent inline asm strings -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -102,12 +102,14 @@ public: /// input constraint is required to match it (e.g. "0"). The value is the /// constraint number that matches this one (for example, if this is /// constraint #0 and constraint #4 has the value "0", this will be 4). - signed char MatchingInput; + signed char MatchingInput = -1; + /// Code - The constraint code, either the register name (in braces) or the /// constraint letter/number. ConstraintCodeVector Codes; + /// Default constructor. - SubConstraintInfo() : MatchingInput(-1) {} + SubConstraintInfo() = default; }; typedef std::vector<SubConstraintInfo> SubConstraintInfoVector; @@ -117,17 +119,17 @@ public: struct ConstraintInfo { /// Type - The basic type of the constraint: input/output/clobber /// - ConstraintPrefix Type; + ConstraintPrefix Type = isInput; /// isEarlyClobber - "&": output operand writes result before inputs are all /// read. This is only ever set for an output operand. - bool isEarlyClobber; + bool isEarlyClobber = false; /// MatchingInput - If this is not -1, this is an output constraint where an /// input constraint is required to match it (e.g. "0"). The value is the /// constraint number that matches this one (for example, if this is /// constraint #0 and constraint #4 has the value "0", this will be 4). - signed char MatchingInput; + signed char MatchingInput = -1; /// hasMatchingInput - Return true if this is an output constraint that has /// a matching input constraint. @@ -135,30 +137,30 @@ public: /// isCommutative - This is set to true for a constraint that is commutative /// with the next operand. - bool isCommutative; + bool isCommutative = false; /// isIndirect - True if this operand is an indirect operand. This means /// that the address of the source or destination is present in the call /// instruction, instead of it being returned or passed in explicitly. This /// is represented with a '*' in the asm string. - bool isIndirect; + bool isIndirect = false; /// Code - The constraint code, either the register name (in braces) or the /// constraint letter/number. ConstraintCodeVector Codes; /// isMultipleAlternative - '|': has multiple-alternative constraints. - bool isMultipleAlternative; + bool isMultipleAlternative = false; /// multipleAlternatives - If there are multiple alternative constraints, /// this array will contain them. Otherwise it will be empty. SubConstraintInfoVector multipleAlternatives; /// The currently selected alternative constraint index. - unsigned currentAlternativeIndex; + unsigned currentAlternativeIndex = 0; /// Default constructor. - ConstraintInfo(); + ConstraintInfo() = default; /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, diff --git a/include/llvm/IR/InstVisitor.h b/include/llvm/IR/InstVisitor.h index 088d3e0fbfa5..55579819fd34 100644 --- a/include/llvm/IR/InstVisitor.h +++ b/include/llvm/IR/InstVisitor.h @@ -116,6 +116,9 @@ public: // visit - Finally, code to visit an instruction... // RetTy visit(Instruction &I) { + static_assert(std::is_base_of<InstVisitor, SubClass>::value, + "Must pass the derived type to this template!"); + switch (I.getOpcode()) { default: llvm_unreachable("Unknown instruction type encountered!"); // Build the switch statement using the Instruction.def file... diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index f2abbec64fe6..518094735d72 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -1061,13 +1061,13 @@ public: /// @brief Determine if Pred1 implies Pred2 is true when two compares have /// matching operands. - bool isImpliedTrueByMatchingCmp(Predicate Pred2) { + bool isImpliedTrueByMatchingCmp(Predicate Pred2) const { return isImpliedTrueByMatchingCmp(getPredicate(), Pred2); } /// @brief Determine if Pred1 implies Pred2 is false when two compares have /// matching operands. - bool isImpliedFalseByMatchingCmp(Predicate Pred2) { + bool isImpliedFalseByMatchingCmp(Predicate Pred2) const { return isImpliedFalseByMatchingCmp(getPredicate(), Pred2); } diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index fd7c54d69b63..90c3175122fd 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -68,14 +68,20 @@ public: /// Note: this is undefined behavior if the instruction does not have a /// parent, or the parent basic block does not have a parent function. const Module *getModule() const; - Module *getModule(); + Module *getModule() { + return const_cast<Module *>( + static_cast<const Instruction *>(this)->getModule()); + } /// Return the function this instruction belongs to. /// /// Note: it is undefined behavior to call this on an instruction not /// currently inserted into a function. const Function *getFunction() const; - Function *getFunction(); + Function *getFunction() { + return const_cast<Function *>( + static_cast<const Instruction *>(this)->getFunction()); + } /// This method unlinks 'this' from the containing basic block, but does not /// delete it. @@ -252,6 +258,12 @@ public: /// Returns false if no metadata was found. bool extractProfTotalWeight(uint64_t &TotalVal) const; + /// Updates branch_weights metadata by scaling it by \p S / \p T. + void updateProfWeight(uint64_t S, uint64_t T); + + /// Sets the branch_weights metadata to \p W for CallInst. + void setProfWeight(uint64_t W); + /// Set the debug location information for this instruction. void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); } @@ -276,6 +288,10 @@ public: /// Determine whether the no signed wrap flag is set. bool hasNoSignedWrap() const; + /// Drops flags that may cause this instruction to evaluate to poison despite + /// having non-poison inputs. + void dropPoisonGeneratingFlags(); + /// Determine whether the exact flag is set. bool isExact() const; @@ -329,6 +345,9 @@ public: /// Determine whether the allow-reciprocal flag is set. bool hasAllowReciprocal() const; + /// Determine whether the allow-contract flag is set. + bool hasAllowContract() const; + /// 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. @@ -372,18 +391,30 @@ public: /// /// In LLVM, the Add, Mul, And, Or, and Xor operators are associative. /// - bool isAssociative() const; - static bool isAssociative(unsigned op); + bool isAssociative() const LLVM_READONLY; + static bool isAssociative(unsigned Opcode) { + return Opcode == And || Opcode == Or || Opcode == Xor || + Opcode == Add || Opcode == Mul; + } /// Return true if the instruction is commutative: /// /// Commutative operators satisfy: (x op y) === (y op x) /// - /// In LLVM, these are the associative operators, plus SetEQ and SetNE, when + /// In LLVM, these are the commutative operators, plus SetEQ and SetNE, when /// applied to any type. /// bool isCommutative() const { return isCommutative(getOpcode()); } - static bool isCommutative(unsigned op); + static bool isCommutative(unsigned Opcode) { + switch (Opcode) { + case Add: case FAdd: + case Mul: case FMul: + case And: case Or: case Xor: + return true; + default: + return false; + } + } /// Return true if the instruction is idempotent: /// @@ -392,7 +423,9 @@ public: /// In LLVM, the And and Or operators are idempotent. /// bool isIdempotent() const { return isIdempotent(getOpcode()); } - static bool isIdempotent(unsigned op); + static bool isIdempotent(unsigned Opcode) { + return Opcode == And || Opcode == Or; + } /// Return true if the instruction is nilpotent: /// @@ -404,7 +437,9 @@ public: /// In LLVM, the Xor operator is nilpotent. /// bool isNilpotent() const { return isNilpotent(getOpcode()); } - static bool isNilpotent(unsigned op); + static bool isNilpotent(unsigned Opcode) { + return Opcode == Xor; + } /// Return true if this instruction may modify memory. bool mayWriteToMemory() const; diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index a5d78a08171a..34dafebe0fc5 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -67,18 +67,21 @@ protected: AllocaInst *cloneImpl() const; public: - explicit AllocaInst(Type *Ty, Value *ArraySize = nullptr, + explicit AllocaInst(Type *Ty, unsigned AddrSpace, + Value *ArraySize = nullptr, const Twine &Name = "", Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, Value *ArraySize, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, const Twine &Name, BasicBlock *InsertAtEnd); - AllocaInst(Type *Ty, const Twine &Name, Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd); + AllocaInst(Type *Ty, unsigned AddrSpace, + const Twine &Name, Instruction *InsertBefore = nullptr); + AllocaInst(Type *Ty, unsigned AddrSpace, + const Twine &Name, BasicBlock *InsertAtEnd); - AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align, const Twine &Name = "", Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align, const Twine &Name, BasicBlock *InsertAtEnd); // Out of line virtual method, so the vtable, etc. has a home. @@ -958,6 +961,14 @@ public: inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return op_end(); } + inline iterator_range<op_iterator> indices() { + return make_range(idx_begin(), idx_end()); + } + + inline iterator_range<const_op_iterator> indices() const { + return make_range(idx_begin(), idx_end()); + } + Value *getPointerOperand() { return getOperand(0); } @@ -1354,7 +1365,7 @@ class CallInst : public Instruction, public OperandBundleUser<CallInst, User::op_iterator> { friend class OperandBundleUser<CallInst, User::op_iterator>; - AttributeSet AttributeList; ///< parameter attributes for call + AttributeList Attrs; ///< parameter attributes for call FunctionType *FTy; CallInst(const CallInst &CI); @@ -1633,11 +1644,11 @@ public: /// Return the parameter attributes for this call. /// - AttributeSet getAttributes() const { return AttributeList; } + AttributeList getAttributes() const { return Attrs; } /// Set the parameter attributes for this call. /// - void setAttributes(AttributeSet Attrs) { AttributeList = Attrs; } + void setAttributes(AttributeList A) { Attrs = A; } /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind Kind); @@ -1670,8 +1681,11 @@ public: return hasFnAttrImpl(Kind); } - /// Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + /// Determine whether the return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const; + + /// Determine whether the argument or parameter has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const; /// Get the attribute of a given kind at a position. Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -1700,26 +1714,26 @@ public: /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { - return AttributeList.getParamAlignment(i); + return Attrs.getParamAlignment(i); } /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { - return AttributeList.getDereferenceableBytes(i); + return Attrs.getDereferenceableBytes(i); } /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { - return AttributeList.getDereferenceableOrNullBytes(i); + return Attrs.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { - return AttributeList.hasAttribute(n, Attribute::NoAlias); + return Attrs.hasAttribute(n, Attribute::NoAlias); } /// Return true if the call should not be treated as a call to a @@ -1732,7 +1746,7 @@ public: /// Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); + addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); } /// Return true if the call can return twice @@ -1740,7 +1754,7 @@ public: return hasFnAttr(Attribute::ReturnsTwice); } void setCanReturnTwice() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReturnsTwice); + addAttribute(AttributeList::FunctionIndex, Attribute::ReturnsTwice); } /// Determine if the call does not access memory. @@ -1748,7 +1762,7 @@ public: return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone); } /// Determine if the call does not access or only reads memory. @@ -1756,7 +1770,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly); } /// Determine if the call does not access or only writes memory. @@ -1764,7 +1778,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); } void setDoesNotReadMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::WriteOnly); } /// @brief Determine if the call can access memmory only using pointers based @@ -1773,34 +1787,34 @@ public: return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ArgMemOnly); } /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); + addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); + addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind); } /// Determine if the call cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); + addAttribute(AttributeList::FunctionIndex, Attribute::NoDuplicate); } /// Determine if the call is convergent bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } void setConvergent() { - addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + addAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } void setNotConvergent() { - removeAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + removeAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } /// Determine if the call returns a structure through first @@ -1810,12 +1824,12 @@ public: return false; // Be friendly and also check the callee. - return paramHasAttr(1, Attribute::StructRet); + return paramHasAttr(0, Attribute::StructRet); } /// Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { - return AttributeList.hasAttrSomewhere(Attribute::ByVal); + return Attrs.hasAttrSomewhere(Attribute::ByVal); } /// Return the function called, or null if this is an @@ -1858,7 +1872,7 @@ public: private: template <typename AttrKind> bool hasFnAttrImpl(AttrKind Kind) const { - if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, Kind)) + if (Attrs.hasAttribute(AttributeList::FunctionIndex, Kind)) return true; // Operand bundles override attributes on the called function, but don't @@ -1867,7 +1881,8 @@ private: return false; if (const Function *F = getCalledFunction()) - return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Kind); + return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, + Kind); return false; } @@ -3084,42 +3099,41 @@ public: // -2 static const unsigned DefaultPseudoIndex = static_cast<unsigned>(~0L-1); - template <class SwitchInstTy, class ConstantIntTy, class BasicBlockTy> - class CaseIteratorT { - protected: - SwitchInstTy *SI; - unsigned Index; + template <typename CaseHandleT> class CaseIteratorImpl; - public: - typedef CaseIteratorT<SwitchInstTy, ConstantIntTy, BasicBlockTy> Self; + /// A handle to a particular switch case. It exposes a convenient interface + /// to both the case value and the successor block. + /// + /// We define this as a template and instantiate it to form both a const and + /// non-const handle. + template <typename SwitchInstT, typename ConstantIntT, typename BasicBlockT> + class CaseHandleImpl { + // Directly befriend both const and non-const iterators. + friend class SwitchInst::CaseIteratorImpl< + CaseHandleImpl<SwitchInstT, ConstantIntT, BasicBlockT>>; - /// Initializes case iterator for given SwitchInst and for given - /// case number. - CaseIteratorT(SwitchInstTy *SI, unsigned CaseNum) { - this->SI = SI; - Index = CaseNum; - } + protected: + // Expose the switch type we're parameterized with to the iterator. + typedef SwitchInstT SwitchInstType; - /// Initializes case iterator for given SwitchInst and for given - /// TerminatorInst's successor index. - static Self fromSuccessorIndex(SwitchInstTy *SI, unsigned SuccessorIndex) { - assert(SuccessorIndex < SI->getNumSuccessors() && - "Successor index # out of range!"); - return SuccessorIndex != 0 ? - Self(SI, SuccessorIndex - 1) : - Self(SI, DefaultPseudoIndex); - } + SwitchInstT *SI; + ptrdiff_t Index; + + CaseHandleImpl() = default; + CaseHandleImpl(SwitchInstT *SI, ptrdiff_t Index) : SI(SI), Index(Index) {} + public: /// Resolves case value for current case. - ConstantIntTy *getCaseValue() { - assert(Index < SI->getNumCases() && "Index out the number of cases."); - return reinterpret_cast<ConstantIntTy*>(SI->getOperand(2 + Index*2)); + ConstantIntT *getCaseValue() const { + assert((unsigned)Index < SI->getNumCases() && + "Index out the number of cases."); + return reinterpret_cast<ConstantIntT *>(SI->getOperand(2 + Index * 2)); } /// Resolves successor for current case. - BasicBlockTy *getCaseSuccessor() { - assert((Index < SI->getNumCases() || - Index == DefaultPseudoIndex) && + BasicBlockT *getCaseSuccessor() const { + assert(((unsigned)Index < SI->getNumCases() || + (unsigned)Index == DefaultPseudoIndex) && "Index out the number of cases."); return SI->getSuccessor(getSuccessorIndex()); } @@ -3129,63 +3143,32 @@ public: /// Returns TerminatorInst's successor index for current case successor. unsigned getSuccessorIndex() const { - assert((Index == DefaultPseudoIndex || Index < SI->getNumCases()) && + assert(((unsigned)Index == DefaultPseudoIndex || + (unsigned)Index < SI->getNumCases()) && "Index out the number of cases."); - return Index != DefaultPseudoIndex ? Index + 1 : 0; + return (unsigned)Index != DefaultPseudoIndex ? Index + 1 : 0; } - Self operator++() { - // Check index correctness after increment. - // Note: Index == getNumCases() means end(). - assert(Index+1 <= SI->getNumCases() && "Index out the number of cases."); - ++Index; - return *this; - } - Self operator++(int) { - Self tmp = *this; - ++(*this); - return tmp; - } - Self operator--() { - // Check index correctness after decrement. - // Note: Index == getNumCases() means end(). - // Also allow "-1" iterator here. That will became valid after ++. - assert((Index == 0 || Index-1 <= SI->getNumCases()) && - "Index out the number of cases."); - --Index; - return *this; - } - Self operator--(int) { - Self tmp = *this; - --(*this); - return tmp; - } - bool operator==(const Self& RHS) const { - assert(RHS.SI == SI && "Incompatible operators."); - return RHS.Index == Index; - } - bool operator!=(const Self& RHS) const { - assert(RHS.SI == SI && "Incompatible operators."); - return RHS.Index != Index; - } - Self &operator*() { - return *this; + bool operator==(const CaseHandleImpl &RHS) const { + assert(SI == RHS.SI && "Incompatible operators."); + return Index == RHS.Index; } }; - typedef CaseIteratorT<const SwitchInst, const ConstantInt, const BasicBlock> - ConstCaseIt; + typedef CaseHandleImpl<const SwitchInst, const ConstantInt, const BasicBlock> + ConstCaseHandle; - class CaseIt : public CaseIteratorT<SwitchInst, ConstantInt, BasicBlock> { - typedef CaseIteratorT<SwitchInst, ConstantInt, BasicBlock> ParentTy; + class CaseHandle + : public CaseHandleImpl<SwitchInst, ConstantInt, BasicBlock> { + friend class SwitchInst::CaseIteratorImpl<CaseHandle>; public: - CaseIt(const ParentTy &Src) : ParentTy(Src) {} - CaseIt(SwitchInst *SI, unsigned CaseNum) : ParentTy(SI, CaseNum) {} + CaseHandle(SwitchInst *SI, ptrdiff_t Index) : CaseHandleImpl(SI, Index) {} /// Sets the new value for current case. void setValue(ConstantInt *V) { - assert(Index < SI->getNumCases() && "Index out the number of cases."); + assert((unsigned)Index < SI->getNumCases() && + "Index out the number of cases."); SI->setOperand(2 + Index*2, reinterpret_cast<Value*>(V)); } @@ -3195,6 +3178,76 @@ public: } }; + template <typename CaseHandleT> + class CaseIteratorImpl + : public iterator_facade_base<CaseIteratorImpl<CaseHandleT>, + std::random_access_iterator_tag, + CaseHandleT> { + typedef typename CaseHandleT::SwitchInstType SwitchInstT; + + CaseHandleT Case; + + public: + /// Default constructed iterator is in an invalid state until assigned to + /// a case for a particular switch. + CaseIteratorImpl() = default; + + /// Initializes case iterator for given SwitchInst and for given + /// case number. + CaseIteratorImpl(SwitchInstT *SI, unsigned CaseNum) : Case(SI, CaseNum) {} + + /// Initializes case iterator for given SwitchInst and for given + /// TerminatorInst's successor index. + static CaseIteratorImpl fromSuccessorIndex(SwitchInstT *SI, + unsigned SuccessorIndex) { + assert(SuccessorIndex < SI->getNumSuccessors() && + "Successor index # out of range!"); + return SuccessorIndex != 0 ? CaseIteratorImpl(SI, SuccessorIndex - 1) + : CaseIteratorImpl(SI, DefaultPseudoIndex); + } + + /// Support converting to the const variant. This will be a no-op for const + /// variant. + operator CaseIteratorImpl<ConstCaseHandle>() const { + return CaseIteratorImpl<ConstCaseHandle>(Case.SI, Case.Index); + } + + CaseIteratorImpl &operator+=(ptrdiff_t N) { + // Check index correctness after addition. + // Note: Index == getNumCases() means end(). + assert(Case.Index + N >= 0 && + (unsigned)(Case.Index + N) <= Case.SI->getNumCases() && + "Case.Index out the number of cases."); + Case.Index += N; + return *this; + } + CaseIteratorImpl &operator-=(ptrdiff_t N) { + // Check index correctness after subtraction. + // Note: Case.Index == getNumCases() means end(). + assert(Case.Index - N >= 0 && + (unsigned)(Case.Index - N) <= Case.SI->getNumCases() && + "Case.Index out the number of cases."); + Case.Index -= N; + return *this; + } + ptrdiff_t operator-(const CaseIteratorImpl &RHS) const { + assert(Case.SI == RHS.Case.SI && "Incompatible operators."); + return Case.Index - RHS.Case.Index; + } + bool operator==(const CaseIteratorImpl &RHS) const { + return Case == RHS.Case; + } + bool operator<(const CaseIteratorImpl &RHS) const { + assert(Case.SI == RHS.Case.SI && "Incompatible operators."); + return Case.Index < RHS.Case.Index; + } + CaseHandleT &operator*() { return Case; } + const CaseHandleT &operator*() const { return Case; } + }; + + typedef CaseIteratorImpl<CaseHandle> CaseIt; + typedef CaseIteratorImpl<ConstCaseHandle> ConstCaseIt; + static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore = nullptr) { @@ -3278,30 +3331,40 @@ public: /// default case iterator to indicate that it is handled by the default /// handler. CaseIt findCaseValue(const ConstantInt *C) { - for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValue() == C) - return i; + CaseIt I = llvm::find_if( + cases(), [C](CaseHandle &Case) { return Case.getCaseValue() == C; }); + if (I != case_end()) + return I; + return case_default(); } ConstCaseIt findCaseValue(const ConstantInt *C) const { - for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValue() == C) - return i; + ConstCaseIt I = llvm::find_if(cases(), [C](ConstCaseHandle &Case) { + return Case.getCaseValue() == C; + }); + if (I != case_end()) + return I; + return case_default(); } /// Finds the unique case value for a given successor. Returns null if the /// successor is not found, not unique, or is the default case. ConstantInt *findCaseDest(BasicBlock *BB) { - if (BB == getDefaultDest()) return nullptr; + if (BB == getDefaultDest()) + return nullptr; ConstantInt *CI = nullptr; - for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) { - if (i.getCaseSuccessor() == BB) { - if (CI) return nullptr; // Multiple cases lead to BB. - else CI = i.getCaseValue(); - } + for (auto Case : cases()) { + if (Case.getCaseSuccessor() != BB) + continue; + + if (CI) + return nullptr; // Multiple cases lead to BB. + + CI = Case.getCaseValue(); } + return CI; } @@ -3316,8 +3379,9 @@ public: /// index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, - /// including the case_end() iterator. - void removeCase(CaseIt i); + /// including the case_end() iterator. It returns an iterator for the next + /// case. + CaseIt removeCase(CaseIt I); unsigned getNumSuccessors() const { return getNumOperands()/2; } BasicBlock *getSuccessor(unsigned idx) const { @@ -3465,7 +3529,7 @@ class InvokeInst : public TerminatorInst, public OperandBundleUser<InvokeInst, User::op_iterator> { friend class OperandBundleUser<InvokeInst, User::op_iterator>; - AttributeSet AttributeList; + AttributeList Attrs; FunctionType *FTy; InvokeInst(const InvokeInst &BI); @@ -3669,11 +3733,11 @@ public: /// Return the parameter attributes for this invoke. /// - AttributeSet getAttributes() const { return AttributeList; } + AttributeList getAttributes() const { return Attrs; } /// Set the parameter attributes for this invoke. /// - void setAttributes(AttributeSet Attrs) { AttributeList = Attrs; } + void setAttributes(AttributeList A) { Attrs = A; } /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind Kind); @@ -3706,8 +3770,11 @@ public: return hasFnAttrImpl(Kind); } - /// Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + /// Determine whether the return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const; + + /// Determine whether the argument or parameter has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const; /// Get the attribute of a given kind at a position. Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -3737,26 +3804,26 @@ public: /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { - return AttributeList.getParamAlignment(i); + return Attrs.getParamAlignment(i); } /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { - return AttributeList.getDereferenceableBytes(i); + return Attrs.getDereferenceableBytes(i); } /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { - return AttributeList.getDereferenceableOrNullBytes(i); + return Attrs.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { - return AttributeList.hasAttribute(n, Attribute::NoAlias); + return Attrs.hasAttribute(n, Attribute::NoAlias); } /// Return true if the call should not be treated as a call to a @@ -3771,7 +3838,7 @@ public: /// Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); + addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); } /// Determine if the call does not access memory. @@ -3779,7 +3846,7 @@ public: return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone); } /// Determine if the call does not access or only reads memory. @@ -3787,7 +3854,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly); } /// Determine if the call does not access or only writes memory. @@ -3795,7 +3862,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); } void setDoesNotReadMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::WriteOnly); } /// @brief Determine if the call access memmory only using it's pointer @@ -3804,34 +3871,34 @@ public: return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ArgMemOnly); } /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); + addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); + addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind); } /// Determine if the invoke cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); + addAttribute(AttributeList::FunctionIndex, Attribute::NoDuplicate); } /// Determine if the invoke is convergent bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } void setConvergent() { - addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + addAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } void setNotConvergent() { - removeAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + removeAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } /// Determine if the call returns a structure through first @@ -3841,12 +3908,12 @@ public: return false; // Be friendly and also check the callee. - return paramHasAttr(1, Attribute::StructRet); + return paramHasAttr(0, Attribute::StructRet); } /// Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { - return AttributeList.hasAttrSomewhere(Attribute::ByVal); + return Attrs.hasAttrSomewhere(Attribute::ByVal); } /// Return the function called, or null if this is an @@ -3918,7 +3985,7 @@ private: void setSuccessorV(unsigned idx, BasicBlock *B) override; template <typename AttrKind> bool hasFnAttrImpl(AttrKind Kind) const { - if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, Kind)) + if (Attrs.hasAttribute(AttributeList::FunctionIndex, Kind)) return true; // Operand bundles override attributes on the called function, but don't @@ -3927,7 +3994,8 @@ private: return false; if (const Function *F = getCalledFunction()) - return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Kind); + return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, + Kind); return false; } diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index b14a54503e52..f69b5bfc0be2 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -152,6 +152,71 @@ namespace llvm { } }; + /// This is the common base class for constrained floating point intrinsics. + class ConstrainedFPIntrinsic : public IntrinsicInst { + public: + enum RoundingMode { + rmInvalid, + rmDynamic, + rmToNearest, + rmDownward, + rmUpward, + rmTowardZero + }; + + enum ExceptionBehavior { + ebInvalid, + ebIgnore, + ebMayTrap, + ebStrict + }; + + RoundingMode getRoundingMode() const; + ExceptionBehavior getExceptionBehavior() const; + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::experimental_constrained_fadd: + case Intrinsic::experimental_constrained_fsub: + case Intrinsic::experimental_constrained_fmul: + case Intrinsic::experimental_constrained_fdiv: + case Intrinsic::experimental_constrained_frem: + return true; + default: return false; + } + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } + }; + + /// This class represents atomic memcpy intrinsic + /// TODO: Integrate this class into MemIntrinsic hierarchy. + class ElementAtomicMemCpyInst : public IntrinsicInst { + public: + Value *getRawDest() const { return getArgOperand(0); } + Value *getRawSource() const { return getArgOperand(1); } + + Value *getNumElements() const { return getArgOperand(2); } + void setNumElements(Value *V) { setArgOperand(2, V); } + + uint64_t getSrcAlignment() const { return getParamAlignment(1); } + uint64_t getDstAlignment() const { return getParamAlignment(2); } + + uint64_t getElementSizeInBytes() const { + Value *Arg = getArgOperand(3); + return cast<ConstantInt>(Arg)->getZExtValue(); + } + + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::memcpy_element_atomic; + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } + }; + /// This is the common base class for memset/memcpy/memmove. class MemIntrinsic : public IntrinsicInst { public: diff --git a/include/llvm/IR/Intrinsics.h b/include/llvm/IR/Intrinsics.h index d07358445dab..2f6bdf8ecf19 100644 --- a/include/llvm/IR/Intrinsics.h +++ b/include/llvm/IR/Intrinsics.h @@ -28,7 +28,7 @@ class FunctionType; class Function; class LLVMContext; class Module; -class AttributeSet; +class AttributeList; /// This namespace contains an enum with a value for every intrinsic/builtin /// function known by LLVM. The enum values are returned by @@ -69,7 +69,7 @@ namespace Intrinsic { bool isLeaf(ID id); /// Return the attributes for an intrinsic. - AttributeSet getAttributes(LLVMContext &C, ID id); + AttributeList getAttributes(LLVMContext &C, ID id); /// Create or insert an LLVM Function declaration for an intrinsic, and return /// it. diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 89ae94270888..309b21489224 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -331,13 +331,13 @@ def int_get_dynamic_area_offset : Intrinsic<[llvm_anyint_ty]>; def int_thread_pointer : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>, GCCBuiltin<"__builtin_thread_pointer">; -// IntrArgMemOnly is more pessimistic than strictly necessary for prefetch, -// however it does conveniently prevent the prefetch from being reordered -// with respect to nearby accesses to the same memory. -def int_prefetch : Intrinsic<[], - [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty], - [IntrArgMemOnly, NoCapture<0>]>; +// IntrInaccessibleMemOrArgMemOnly is a little more pessimistic than strictly +// necessary for prefetch, however it does conveniently prevent the prefetch +// from being reordered overly much with respect to nearby access to the same +// memory while not impeding optimization. +def int_prefetch + : Intrinsic<[], [ llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], + [ IntrInaccessibleMemOrArgMemOnly, ReadOnly<0>, NoCapture<0> ]>; def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; @@ -389,6 +389,9 @@ def int_memset : Intrinsic<[], llvm_i32_ty, llvm_i1_ty], [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>; +// FIXME: Add version of these floating point intrinsics which allow non-default +// rounding modes and FP exception handling. + let IntrProperties = [IntrNoMem] in { def int_fma : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, @@ -438,10 +441,44 @@ def int_sigsetjmp : Intrinsic<[llvm_i32_ty] , [llvm_ptr_ty, llvm_i32_ty]>; def int_siglongjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>; // Internal interface for object size checking -def int_objectsize : Intrinsic<[llvm_anyint_ty], [llvm_anyptr_ty, llvm_i1_ty], +def int_objectsize : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, llvm_i1_ty, llvm_i1_ty], [IntrNoMem]>, GCCBuiltin<"__builtin_object_size">; +//===--------------- Constrained Floating Point Intrinsics ----------------===// +// + +let IntrProperties = [IntrInaccessibleMemOnly] in { + def int_experimental_constrained_fadd : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fsub : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fmul : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fdiv : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_frem : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; +} +// FIXME: Add intrinsic for fcmp, fptrunc, fpext, fptoui and fptosi. + + //===------------------------- Expect Intrinsics --------------------------===// // def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, @@ -565,10 +602,10 @@ def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], //===------------------------- Memory Use Markers -------------------------===// // def int_lifetime_start : Intrinsic<[], - [llvm_i64_ty, llvm_ptr_ty], + [llvm_i64_ty, llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_lifetime_end : Intrinsic<[], - [llvm_i64_ty, llvm_ptr_ty], + [llvm_i64_ty, llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_anyptr_ty], @@ -578,9 +615,16 @@ def int_invariant_end : Intrinsic<[], llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<2>]>; +// invariant.group.barrier can't be marked with 'readnone' (IntrNoMem), +// because it would cause CSE of two barriers with the same argument. +// Readonly and argmemonly says that barrier only reads its argument and +// it can be CSE only if memory didn't change between 2 barriers call, +// which is valid. +// The argument also can't be marked with 'returned' attribute, because +// it would remove barrier. def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], - [IntrNoMem]>; + [IntrReadMem, IntrArgMemOnly]>; //===------------------------ Stackmap Intrinsics -------------------------===// // @@ -619,18 +663,18 @@ def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty], // Coroutine Structure Intrinsics. -def int_coro_id : Intrinsic<[llvm_token_ty], [llvm_i32_ty, llvm_ptr_ty, - llvm_ptr_ty, llvm_ptr_ty], - [IntrArgMemOnly, IntrReadMem, +def int_coro_id : Intrinsic<[llvm_token_ty], [llvm_i32_ty, llvm_ptr_ty, + llvm_ptr_ty, llvm_ptr_ty], + [IntrArgMemOnly, IntrReadMem, ReadNone<1>, ReadOnly<2>, NoCapture<2>]>; def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], []>; def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], [WriteOnly<1>]>; -def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], - [IntrReadMem, IntrArgMemOnly, ReadOnly<1>, +def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], + [IntrReadMem, IntrArgMemOnly, ReadOnly<1>, NoCapture<1>]>; -def int_coro_end : Intrinsic<[], [llvm_ptr_ty, llvm_i1_ty], []>; +def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []>; def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>; @@ -745,6 +789,10 @@ def int_memcpy_element_atomic : Intrinsic<[], [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, WriteOnly<0>, ReadOnly<1>]>; +//===----- Intrinsics that are used to provide predicate information -----===// + +def int_ssa_copy : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], + [IntrNoMem, Returned<0>]>; //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// diff --git a/include/llvm/IR/IntrinsicsAMDGPU.td b/include/llvm/IR/IntrinsicsAMDGPU.td index dcec3860f2ca..5415c6b0d151 100644 --- a/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/include/llvm/IR/IntrinsicsAMDGPU.td @@ -64,6 +64,10 @@ def int_r600_recipsqrt_clamped : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_r600_cube : Intrinsic< + [llvm_v4f32_ty], [llvm_v4f32_ty], [IntrNoMem] +>; + } // End TargetPrefix = "r600" let TargetPrefix = "amdgcn" in { @@ -121,7 +125,8 @@ def int_amdgcn_s_barrier : GCCBuiltin<"__builtin_amdgcn_s_barrier">, def int_amdgcn_wave_barrier : GCCBuiltin<"__builtin_amdgcn_wave_barrier">, Intrinsic<[], [], [IntrConvergent]>; -def int_amdgcn_s_waitcnt : Intrinsic<[], [llvm_i32_ty], []>; +def int_amdgcn_s_waitcnt : GCCBuiltin<"__builtin_amdgcn_s_waitcnt">, + Intrinsic<[], [llvm_i32_ty], []>; def int_amdgcn_div_scale : Intrinsic< // 1st parameter: Numerator @@ -202,10 +207,19 @@ def int_amdgcn_fract : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_amdgcn_cvt_pkrtz : Intrinsic< + [llvm_v2f16_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; + def int_amdgcn_class : Intrinsic< [llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem] >; +def int_amdgcn_fmed3 : GCCBuiltin<"__builtin_amdgcn_fmed3">, + Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem] +>; + def int_amdgcn_cubeid : GCCBuiltin<"__builtin_amdgcn_cubeid">, Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] @@ -231,17 +245,20 @@ def int_amdgcn_cubetc : GCCBuiltin<"__builtin_amdgcn_cubetc">, def int_amdgcn_sffbh : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], [IntrNoMem]>; -// TODO: Do we want an ordering for these? -def int_amdgcn_atomic_inc : Intrinsic<[llvm_anyint_ty], - [llvm_anyptr_ty, LLVMMatchType<0>], - [IntrArgMemOnly, NoCapture<0>] ->; -def int_amdgcn_atomic_dec : Intrinsic<[llvm_anyint_ty], - [llvm_anyptr_ty, LLVMMatchType<0>], +// Fields should mirror atomicrmw +class AMDGPUAtomicIncIntrin : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, + LLVMMatchType<0>, + llvm_i32_ty, // ordering + llvm_i32_ty, // scope + llvm_i1_ty], // isVolatile [IntrArgMemOnly, NoCapture<0>] >; +def int_amdgcn_atomic_inc : AMDGPUAtomicIncIntrin; +def int_amdgcn_atomic_dec : AMDGPUAtomicIncIntrin; + class AMDGPUImageLoad : Intrinsic < [llvm_anyfloat_ty], // vdata(VGPR) [llvm_anyint_ty, // vaddr(VGPR) @@ -451,6 +468,32 @@ def int_amdgcn_buffer_atomic_cmpswap : Intrinsic< llvm_i1_ty], // slc(imm) []>; +// Uses that do not set the done bit should set IntrWriteMem on the +// call site. +def int_amdgcn_exp : Intrinsic <[], [ + llvm_i32_ty, // tgt, + llvm_i32_ty, // en + llvm_any_ty, // src0 (f32 or i32) + LLVMMatchType<0>, // src1 + LLVMMatchType<0>, // src2 + LLVMMatchType<0>, // src3 + llvm_i1_ty, // done + llvm_i1_ty // vm + ], + [] +>; + +// exp with compr bit set. +def int_amdgcn_exp_compr : Intrinsic <[], [ + llvm_i32_ty, // tgt, + llvm_i32_ty, // en + llvm_anyvector_ty, // src0 (v2f16 or v2i16) + LLVMMatchType<0>, // src1 + llvm_i1_ty, // done + llvm_i1_ty], // vm + [] +>; + def int_amdgcn_buffer_wbinvl1_sc : GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1_sc">, Intrinsic<[], [], []>; @@ -530,7 +573,14 @@ def int_amdgcn_ds_swizzle : GCCBuiltin<"__builtin_amdgcn_ds_swizzle">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; -// llvm.amdgcn.lerp +def int_amdgcn_ubfe : Intrinsic<[llvm_anyint_ty], + [LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], [IntrNoMem] +>; + +def int_amdgcn_sbfe : Intrinsic<[llvm_anyint_ty], + [LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], [IntrNoMem] +>; + def int_amdgcn_lerp : GCCBuiltin<"__builtin_amdgcn_lerp">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; @@ -619,10 +669,51 @@ def int_amdgcn_s_memrealtime : // llvm.amdgcn.ds.permute <index> <src> def int_amdgcn_ds_permute : + GCCBuiltin<"__builtin_amdgcn_ds_permute">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; // llvm.amdgcn.ds.bpermute <index> <src> def int_amdgcn_ds_bpermute : + GCCBuiltin<"__builtin_amdgcn_ds_bpermute">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; + +//===----------------------------------------------------------------------===// +// Special Intrinsics for backend internal use only. No frontend +// should emit calls to these. +// ===----------------------------------------------------------------------===// +def int_amdgcn_if : Intrinsic<[llvm_i1_ty, llvm_i64_ty], + [llvm_i1_ty], [IntrConvergent] +>; + +def int_amdgcn_else : Intrinsic<[llvm_i1_ty, llvm_i64_ty], + [llvm_i64_ty], [IntrConvergent] +>; + +def int_amdgcn_break : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_if_break : Intrinsic<[llvm_i64_ty], + [llvm_i1_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_else_break : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_loop : Intrinsic<[llvm_i1_ty], + [llvm_i64_ty], [IntrConvergent] +>; + +def int_amdgcn_end_cf : Intrinsic<[], [llvm_i64_ty], [IntrConvergent]>; + +// Represent unreachable in a divergent region. +def int_amdgcn_unreachable : Intrinsic<[], [], [IntrConvergent]>; + +// Emit 2.5 ulp, no denormal division. Should only be inserted by +// pass based on !fpmath metadata. +def int_amdgcn_fdiv_fast : Intrinsic< + [llvm_float_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; } diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index 24239689a62e..18ed24be56d4 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -67,7 +67,7 @@ def int_arm_isb : GCCBuiltin<"__builtin_arm_isb">, MSBuiltin<"__isb">, // VFP def int_arm_get_fpscr : GCCBuiltin<"__builtin_arm_get_fpscr">, - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; + Intrinsic<[llvm_i32_ty], [], []>; def int_arm_set_fpscr : GCCBuiltin<"__builtin_arm_set_fpscr">, Intrinsic<[], [llvm_i32_ty], []>; def int_arm_vcvtr : Intrinsic<[llvm_float_ty], [llvm_anyfloat_ty], diff --git a/include/llvm/IR/IntrinsicsHexagon.td b/include/llvm/IR/IntrinsicsHexagon.td index 6519f051deeb..8ac56e03be6a 100644 --- a/include/llvm/IR/IntrinsicsHexagon.td +++ b/include/llvm/IR/IntrinsicsHexagon.td @@ -5659,20 +5659,20 @@ class Hexagon_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> [IntrNoMem]>; // -// Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> -// tag : M6_vabsdiffb -class Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> +// Hexagon_vv64ivmemv512_Intrinsic<string GCCIntSuffix> +// tag: V6_vS32b_qpred_ai +class Hexagon_vv64ivmemv512_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, - [llvm_i64_ty], [llvm_i64_ty,llvm_i64_ty], - [IntrNoMem]>; + [], [llvm_v512i1_ty,llvm_ptr_ty,llvm_v16i32_ty], + [IntrArgMemOnly]>; // -// Hexagon_LLii_Intrinsic<string GCCIntSuffix> -// tag : S6_vsplatrbp -class Hexagon_LLii_Intrinsic<string GCCIntSuffix> +// Hexagon_vv128ivmemv1024_Intrinsic<string GCCIntSuffix> +// tag: V6_vS32b_qpred_ai_128B +class Hexagon_vv128ivmemv1024_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, - [llvm_i64_ty], [llvm_i32_ty], - [IntrNoMem]>; + [], [llvm_v1024i1_ty,llvm_ptr_ty,llvm_v32i32_ty], + [IntrArgMemOnly]>; // // BUILTIN_INFO(HEXAGON.S6_rol_i_r,SI_ftype_SISI,2) @@ -9343,6 +9343,303 @@ def int_hexagon_V6_vlutvwh_oracc_128B : Hexagon_v2048v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_oracc_128B">; // +// Masked vector stores +// +def int_hexagon_V6_vmaskedstoreq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstoreq">; + +def int_hexagon_V6_vmaskedstorenq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorenq">; + +def int_hexagon_V6_vmaskedstorentq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorentq">; + +def int_hexagon_V6_vmaskedstorentnq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorentnq">; + +def int_hexagon_V6_vmaskedstoreq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstoreq_128B">; + +def int_hexagon_V6_vmaskedstorenq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorenq_128B">; + +def int_hexagon_V6_vmaskedstorentq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorentq_128B">; + +def int_hexagon_V6_vmaskedstorentnq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorentnq_128B">; + + +/// +/// HexagonV62 intrinsics +/// + +// +// Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> +// tag : M6_vabsdiffb +class Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_i64_ty], [llvm_i64_ty,llvm_i64_ty], + [IntrNoMem]>; + +// +// Hexagon_LLii_Intrinsic<string GCCIntSuffix> +// tag : S6_vsplatrbp +class Hexagon_LLii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_i64_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlsrb +class Hexagon_V62_v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlsrb_128B +class Hexagon_V62_v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vasrwuhrndsat +class Hexagon_V62_v512v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vasrwuhrndsat_128B +class Hexagon_V62_v1024v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vrounduwuh +class Hexagon_V62_v512v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vrounduwuh_128B +class Hexagon_V62_v1024v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v2048_Intrinsic<string GCCIntSuffix> +// tag : V6_vadduwsat_dv_128B +class Hexagon_V62_v2048v2048v2048_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v64i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vaddhw_acc +class Hexagon_V62_v1024v1024v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vaddhw_acc_128B +class Hexagon_V62_v2048v2048v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpyewuh_64 +class Hexagon_V62_v1024v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpyewuh_64_128B +class Hexagon_V62_v2048v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048i_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpauhb_128B +class Hexagon_V62_v2048v2048i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v2048i_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpauhb_acc_128B +class Hexagon_V62_v2048v2048v2048i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v64i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt +class Hexagon_V62_v512v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v512i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_128B +class Hexagon_V62_v1024v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v1024i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_acc +class Hexagon_V62_v512v512v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v512i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_acc_128B +class Hexagon_V62_v1024v1024v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v1024i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v64iv512_Intrinsic<string GCCIntSuffix> +// tag : V6_vandvqv +class Hexagon_V62_v512v64iv512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v512i1_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v128iv1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vandvqv_128B +class Hexagon_V62_v1024v128iv1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v1024i1_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_pred_scalar2v2 +class Hexagon_V62_v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v512i1_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_pred_scalar2v2_128B +class Hexagon_V62_v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v1024i1_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v64iv64iv64i_Intrinsic<string GCCIntSuffix> +// tag : V6_shuffeqw +class Hexagon_V62_v64iv64iv64i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v512i1_ty], [llvm_v512i1_ty,llvm_v512i1_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v128iv128iv128i_Intrinsic<string GCCIntSuffix> +// tag : V6_shuffeqw_128B +class Hexagon_V62_v128iv128iv128i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v1024i1_ty], [llvm_v1024i1_ty,llvm_v1024i1_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_lvsplath +class Hexagon_V62_v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_lvsplath_128B +class Hexagon_V62_v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvvb_oracci +class Hexagon_V62_v512v512v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvvb_oracci_128B +class Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwhi +class Hexagon_V62_v1024v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwhi_128B +class Hexagon_V62_v2048v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwh_oracci +class Hexagon_V62_v1024v1024v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwh_oracci_128B +class Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + + +// // BUILTIN_INFO(HEXAGON.M6_vabsdiffb,DI_ftype_DIDI,2) // tag : M6_vabsdiffb def int_hexagon_M6_vabsdiffb : @@ -9355,12 +9652,6 @@ def int_hexagon_M6_vabsdiffub : Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_M6_vabsdiffub">; // -// BUILTIN_INFO(HEXAGON.S6_vsplatrbp,DI_ftype_SI,1) -// tag : S6_vsplatrbp -def int_hexagon_S6_vsplatrbp : -Hexagon_LLii_Intrinsic<"HEXAGON_S6_vsplatrbp">; - -// // BUILTIN_INFO(HEXAGON.S6_vtrunehb_ppp,DI_ftype_DIDI,2) // tag : S6_vtrunehb_ppp def int_hexagon_S6_vtrunehb_ppp : @@ -9371,3 +9662,550 @@ Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_S6_vtrunehb_ppp">; // tag : S6_vtrunohb_ppp def int_hexagon_S6_vtrunohb_ppp : Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_S6_vtrunohb_ppp">; + +// +// BUILTIN_INFO(HEXAGON.S6_vsplatrbp,DI_ftype_SI,1) +// tag : S6_vsplatrbp +def int_hexagon_S6_vsplatrbp : +Hexagon_LLii_Intrinsic<"HEXAGON_S6_vsplatrbp">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlsrb,VI_ftype_VISI,2) +// tag : V6_vlsrb +def int_hexagon_V6_vlsrb : +Hexagon_V62_v512v512i_Intrinsic<"HEXAGON_V6_vlsrb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlsrb_128B,VI_ftype_VISI,2) +// tag : V6_vlsrb_128B +def int_hexagon_V6_vlsrb_128B : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vlsrb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrwuhrndsat,VI_ftype_VIVISI,3) +// tag : V6_vasrwuhrndsat +def int_hexagon_V6_vasrwuhrndsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasrwuhrndsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrwuhrndsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasrwuhrndsat_128B +def int_hexagon_V6_vasrwuhrndsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasrwuhrndsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasruwuhrndsat,VI_ftype_VIVISI,3) +// tag : V6_vasruwuhrndsat +def int_hexagon_V6_vasruwuhrndsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasruwuhrndsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasruwuhrndsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasruwuhrndsat_128B +def int_hexagon_V6_vasruwuhrndsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasruwuhrndsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrhbsat,VI_ftype_VIVISI,3) +// tag : V6_vasrhbsat +def int_hexagon_V6_vasrhbsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasrhbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrhbsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasrhbsat_128B +def int_hexagon_V6_vasrhbsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasrhbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduwuh,VI_ftype_VIVI,2) +// tag : V6_vrounduwuh +def int_hexagon_V6_vrounduwuh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vrounduwuh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduwuh_128B,VI_ftype_VIVI,2) +// tag : V6_vrounduwuh_128B +def int_hexagon_V6_vrounduwuh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vrounduwuh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduhub,VI_ftype_VIVI,2) +// tag : V6_vrounduhub +def int_hexagon_V6_vrounduhub : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vrounduhub">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduhub_128B,VI_ftype_VIVI,2) +// tag : V6_vrounduhub_128B +def int_hexagon_V6_vrounduhub_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vrounduhub_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat,VI_ftype_VIVI,2) +// tag : V6_vadduwsat +def int_hexagon_V6_vadduwsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vadduwsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_128B,VI_ftype_VIVI,2) +// tag : V6_vadduwsat_128B +def int_hexagon_V6_vadduwsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vadduwsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_dv,VD_ftype_VDVD,2) +// tag : V6_vadduwsat_dv +def int_hexagon_V6_vadduwsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vadduwsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vadduwsat_dv_128B +def int_hexagon_V6_vadduwsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vadduwsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat,VI_ftype_VIVI,2) +// tag : V6_vsubuwsat +def int_hexagon_V6_vsubuwsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubuwsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubuwsat_128B +def int_hexagon_V6_vsubuwsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubuwsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_dv,VD_ftype_VDVD,2) +// tag : V6_vsubuwsat_dv +def int_hexagon_V6_vsubuwsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubuwsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vsubuwsat_dv_128B +def int_hexagon_V6_vsubuwsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vsubuwsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat,VI_ftype_VIVI,2) +// tag : V6_vaddbsat +def int_hexagon_V6_vaddbsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_128B,VI_ftype_VIVI,2) +// tag : V6_vaddbsat_128B +def int_hexagon_V6_vaddbsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_dv,VD_ftype_VDVD,2) +// tag : V6_vaddbsat_dv +def int_hexagon_V6_vaddbsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddbsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vaddbsat_dv_128B +def int_hexagon_V6_vaddbsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vaddbsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat,VI_ftype_VIVI,2) +// tag : V6_vsubbsat +def int_hexagon_V6_vsubbsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubbsat_128B +def int_hexagon_V6_vsubbsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_dv,VD_ftype_VDVD,2) +// tag : V6_vsubbsat_dv +def int_hexagon_V6_vsubbsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubbsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vsubbsat_dv_128B +def int_hexagon_V6_vsubbsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vsubbsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddububb_sat,VI_ftype_VIVI,2) +// tag : V6_vaddububb_sat +def int_hexagon_V6_vaddububb_sat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddububb_sat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddububb_sat_128B,VI_ftype_VIVI,2) +// tag : V6_vaddububb_sat_128B +def int_hexagon_V6_vaddububb_sat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddububb_sat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubububb_sat,VI_ftype_VIVI,2) +// tag : V6_vsubububb_sat +def int_hexagon_V6_vsubububb_sat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubububb_sat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubububb_sat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubububb_sat_128B +def int_hexagon_V6_vsubububb_sat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubububb_sat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddhw_acc,VD_ftype_VDVIVI,3) +// tag : V6_vaddhw_acc +def int_hexagon_V6_vaddhw_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vaddhw_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddhw_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vaddhw_acc_128B +def int_hexagon_V6_vaddhw_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vaddhw_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduhw_acc,VD_ftype_VDVIVI,3) +// tag : V6_vadduhw_acc +def int_hexagon_V6_vadduhw_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vadduhw_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduhw_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vadduhw_acc_128B +def int_hexagon_V6_vadduhw_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vadduhw_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddubh_acc,VD_ftype_VDVIVI,3) +// tag : V6_vaddubh_acc +def int_hexagon_V6_vaddubh_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vaddubh_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddubh_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vaddubh_acc_128B +def int_hexagon_V6_vaddubh_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vaddubh_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyewuh_64,VD_ftype_VIVI,2) +// tag : V6_vmpyewuh_64 +def int_hexagon_V6_vmpyewuh_64 : +Hexagon_V62_v1024v512v512_Intrinsic<"HEXAGON_V6_vmpyewuh_64">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyewuh_64_128B,VD_ftype_VIVI,2) +// tag : V6_vmpyewuh_64_128B +def int_hexagon_V6_vmpyewuh_64_128B : +Hexagon_V62_v2048v1024v1024_Intrinsic<"HEXAGON_V6_vmpyewuh_64_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyowh_64_acc,VD_ftype_VDVIVI,3) +// tag : V6_vmpyowh_64_acc +def int_hexagon_V6_vmpyowh_64_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vmpyowh_64_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyowh_64_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vmpyowh_64_acc_128B +def int_hexagon_V6_vmpyowh_64_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vmpyowh_64_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb,VD_ftype_VDSI,2) +// tag : V6_vmpauhb +def int_hexagon_V6_vmpauhb : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vmpauhb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_128B,VD_ftype_VDSI,2) +// tag : V6_vmpauhb_128B +def int_hexagon_V6_vmpauhb_128B : +Hexagon_V62_v2048v2048i_Intrinsic<"HEXAGON_V6_vmpauhb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_acc,VD_ftype_VDVDSI,3) +// tag : V6_vmpauhb_acc +def int_hexagon_V6_vmpauhb_acc : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vmpauhb_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_acc_128B,VD_ftype_VDVDSI,3) +// tag : V6_vmpauhb_acc_128B +def int_hexagon_V6_vmpauhb_acc_128B : +Hexagon_V62_v2048v2048v2048i_Intrinsic<"HEXAGON_V6_vmpauhb_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub,VI_ftype_VISI,2) +// tag : V6_vmpyiwub +def int_hexagon_V6_vmpyiwub : +Hexagon_V62_v512v512i_Intrinsic<"HEXAGON_V6_vmpyiwub">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_128B,VI_ftype_VISI,2) +// tag : V6_vmpyiwub_128B +def int_hexagon_V6_vmpyiwub_128B : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vmpyiwub_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_acc,VI_ftype_VIVISI,3) +// tag : V6_vmpyiwub_acc +def int_hexagon_V6_vmpyiwub_acc : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vmpyiwub_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_acc_128B,VI_ftype_VIVISI,3) +// tag : V6_vmpyiwub_acc_128B +def int_hexagon_V6_vmpyiwub_acc_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vmpyiwub_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt,VI_ftype_QVSI,2) +// tag : V6_vandnqrt +def int_hexagon_V6_vandnqrt : +Hexagon_V62_v512v64ii_Intrinsic<"HEXAGON_V6_vandnqrt">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_128B,VI_ftype_QVSI,2) +// tag : V6_vandnqrt_128B +def int_hexagon_V6_vandnqrt_128B : +Hexagon_V62_v1024v128ii_Intrinsic<"HEXAGON_V6_vandnqrt_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_acc,VI_ftype_VIQVSI,3) +// tag : V6_vandnqrt_acc +def int_hexagon_V6_vandnqrt_acc : +Hexagon_V62_v512v512v64ii_Intrinsic<"HEXAGON_V6_vandnqrt_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_acc_128B,VI_ftype_VIQVSI,3) +// tag : V6_vandnqrt_acc_128B +def int_hexagon_V6_vandnqrt_acc_128B : +Hexagon_V62_v1024v1024v128ii_Intrinsic<"HEXAGON_V6_vandnqrt_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvqv,VI_ftype_QVVI,2) +// tag : V6_vandvqv +def int_hexagon_V6_vandvqv : +Hexagon_V62_v512v64iv512_Intrinsic<"HEXAGON_V6_vandvqv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvqv_128B,VI_ftype_QVVI,2) +// tag : V6_vandvqv_128B +def int_hexagon_V6_vandvqv_128B : +Hexagon_V62_v1024v128iv1024_Intrinsic<"HEXAGON_V6_vandvqv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvnqv,VI_ftype_QVVI,2) +// tag : V6_vandvnqv +def int_hexagon_V6_vandvnqv : +Hexagon_V62_v512v64iv512_Intrinsic<"HEXAGON_V6_vandvnqv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvnqv_128B,VI_ftype_QVVI,2) +// tag : V6_vandvnqv_128B +def int_hexagon_V6_vandvnqv_128B : +Hexagon_V62_v1024v128iv1024_Intrinsic<"HEXAGON_V6_vandvnqv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_pred_scalar2v2,QV_ftype_SI,1) +// tag : V6_pred_scalar2v2 +def int_hexagon_V6_pred_scalar2v2 : +Hexagon_V62_v64ii_Intrinsic<"HEXAGON_V6_pred_scalar2v2">; + +// +// BUILTIN_INFO(HEXAGON.V6_pred_scalar2v2_128B,QV_ftype_SI,1) +// tag : V6_pred_scalar2v2_128B +def int_hexagon_V6_pred_scalar2v2_128B : +Hexagon_V62_v128ii_Intrinsic<"HEXAGON_V6_pred_scalar2v2_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqw,QV_ftype_QVQV,2) +// tag : V6_shuffeqw +def int_hexagon_V6_shuffeqw : +Hexagon_V62_v64iv64iv64i_Intrinsic<"HEXAGON_V6_shuffeqw">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqw_128B,QV_ftype_QVQV,2) +// tag : V6_shuffeqw_128B +def int_hexagon_V6_shuffeqw_128B : +Hexagon_V62_v128iv128iv128i_Intrinsic<"HEXAGON_V6_shuffeqw_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqh,QV_ftype_QVQV,2) +// tag : V6_shuffeqh +def int_hexagon_V6_shuffeqh : +Hexagon_V62_v64iv64iv64i_Intrinsic<"HEXAGON_V6_shuffeqh">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqh_128B,QV_ftype_QVQV,2) +// tag : V6_shuffeqh_128B +def int_hexagon_V6_shuffeqh_128B : +Hexagon_V62_v128iv128iv128i_Intrinsic<"HEXAGON_V6_shuffeqh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmaxb,VI_ftype_VIVI,2) +// tag : V6_vmaxb +def int_hexagon_V6_vmaxb : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vmaxb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmaxb_128B,VI_ftype_VIVI,2) +// tag : V6_vmaxb_128B +def int_hexagon_V6_vmaxb_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vmaxb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vminb,VI_ftype_VIVI,2) +// tag : V6_vminb +def int_hexagon_V6_vminb : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vminb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vminb_128B,VI_ftype_VIVI,2) +// tag : V6_vminb_128B +def int_hexagon_V6_vminb_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vminb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsatuwuh,VI_ftype_VIVI,2) +// tag : V6_vsatuwuh +def int_hexagon_V6_vsatuwuh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsatuwuh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsatuwuh_128B,VI_ftype_VIVI,2) +// tag : V6_vsatuwuh_128B +def int_hexagon_V6_vsatuwuh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsatuwuh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplath,VI_ftype_SI,1) +// tag : V6_lvsplath +def int_hexagon_V6_lvsplath : +Hexagon_V62_v512i_Intrinsic<"HEXAGON_V6_lvsplath">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplath_128B,VI_ftype_SI,1) +// tag : V6_lvsplath_128B +def int_hexagon_V6_lvsplath_128B : +Hexagon_V62_v1024i_Intrinsic<"HEXAGON_V6_lvsplath_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplatb,VI_ftype_SI,1) +// tag : V6_lvsplatb +def int_hexagon_V6_lvsplatb : +Hexagon_V62_v512i_Intrinsic<"HEXAGON_V6_lvsplatb">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplatb_128B,VI_ftype_SI,1) +// tag : V6_lvsplatb_128B +def int_hexagon_V6_lvsplatb_128B : +Hexagon_V62_v1024i_Intrinsic<"HEXAGON_V6_lvsplatb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbw,VI_ftype_VIVI,2) +// tag : V6_vaddclbw +def int_hexagon_V6_vaddclbw : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddclbw">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbw_128B,VI_ftype_VIVI,2) +// tag : V6_vaddclbw_128B +def int_hexagon_V6_vaddclbw_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddclbw_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbh,VI_ftype_VIVI,2) +// tag : V6_vaddclbh +def int_hexagon_V6_vaddclbh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddclbh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbh_128B,VI_ftype_VIVI,2) +// tag : V6_vaddclbh_128B +def int_hexagon_V6_vaddclbh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddclbh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvbi,VI_ftype_VIVISI,3) +// tag : V6_vlutvvbi +def int_hexagon_V6_vlutvvbi : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvbi">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvbi_128B,VI_ftype_VIVISI,3) +// tag : V6_vlutvvbi_128B +def int_hexagon_V6_vlutvvbi_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvbi_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_oracci,VI_ftype_VIVIVISI,4) +// tag : V6_vlutvvb_oracci +def int_hexagon_V6_vlutvvb_oracci : +Hexagon_V62_v512v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvb_oracci">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_oracci_128B,VI_ftype_VIVIVISI,4) +// tag : V6_vlutvvb_oracci_128B +def int_hexagon_V6_vlutvvb_oracci_128B : +Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvb_oracci_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwhi,VD_ftype_VIVISI,3) +// tag : V6_vlutvwhi +def int_hexagon_V6_vlutvwhi : +Hexagon_V62_v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwhi">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwhi_128B,VD_ftype_VIVISI,3) +// tag : V6_vlutvwhi_128B +def int_hexagon_V6_vlutvwhi_128B : +Hexagon_V62_v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwhi_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_oracci,VD_ftype_VDVIVISI,4) +// tag : V6_vlutvwh_oracci +def int_hexagon_V6_vlutvwh_oracci : +Hexagon_V62_v1024v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwh_oracci">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_oracci_128B,VD_ftype_VDVIVISI,4) +// tag : V6_vlutvwh_oracci_128B +def int_hexagon_V6_vlutvwh_oracci_128B : +Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_oracci_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_nm,VI_ftype_VIVISI,3) +// tag : V6_vlutvvb_nm +def int_hexagon_V6_vlutvvb_nm : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvb_nm">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_nm_128B,VI_ftype_VIVISI,3) +// tag : V6_vlutvvb_nm_128B +def int_hexagon_V6_vlutvvb_nm_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvb_nm_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_nm,VD_ftype_VIVISI,3) +// tag : V6_vlutvwh_nm +def int_hexagon_V6_vlutvwh_nm : +Hexagon_V62_v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwh_nm">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_nm_128B,VD_ftype_VIVISI,3) +// tag : V6_vlutvwh_nm_128B +def int_hexagon_V6_vlutvwh_nm_128B : +Hexagon_V62_v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_nm_128B">; + diff --git a/include/llvm/IR/IntrinsicsNVVM.td b/include/llvm/IR/IntrinsicsNVVM.td index f035ac3c90ee..68f123df0430 100644 --- a/include/llvm/IR/IntrinsicsNVVM.td +++ b/include/llvm/IR/IntrinsicsNVVM.td @@ -11,6 +11,27 @@ // //===----------------------------------------------------------------------===// +// The following intrinsics were once defined here, but are now auto-upgraded +// to target-generic LLVM intrinsics. +// +// * llvm.nvvm.brev32 --> llvm.bitreverse.i32 +// * llvm.nvvm.brev64 --> llvm.bitreverse.i64 +// * llvm.nvvm.clz.i --> llvm.ctlz.i32 +// * llvm.nvvm.clz.ll --> trunc i64 llvm.ctlz.i64(x) to i32 +// * llvm.nvvm.popc.i --> llvm.ctpop.i32 +// * llvm.nvvm.popc.ll --> trunc i64 llvm.ctpop.i64 to i32 +// * llvm.nvvm.abs.i --> select(x >= -x, x, -x) +// * llvm.nvvm.abs.ll --> ibid. +// * llvm.nvvm.max.i --> select(x sge y, x, y) +// * llvm.nvvm.max.ll --> ibid. +// * llvm.nvvm.max.ui --> select(x uge y, x, y) +// * llvm.nvvm.max.ull --> ibid. +// * llvm.nvvm.max.i --> select(x sle y, x, y) +// * llvm.nvvm.max.ll --> ibid. +// * llvm.nvvm.max.ui --> select(x ule y, x, y) +// * llvm.nvvm.max.ull --> ibid. +// * llvm.nvvm.h2f --> llvm.convert.to.fp16.f32 + def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // @@ -18,16 +39,6 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // let TargetPrefix = "nvvm" in { - def int_nvvm_clz_i : GCCBuiltin<"__nvvm_clz_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_clz_ll : GCCBuiltin<"__nvvm_clz_ll">, - Intrinsic<[llvm_i32_ty], [llvm_i64_ty], [IntrNoMem]>; - - def int_nvvm_popc_i : GCCBuiltin<"__nvvm_popc_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_popc_ll : GCCBuiltin<"__nvvm_popc_ll">, - Intrinsic<[llvm_i32_ty], [llvm_i64_ty], [IntrNoMem]>; - def int_nvvm_prmt : GCCBuiltin<"__nvvm_prmt">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem, Commutative]>; @@ -36,34 +47,6 @@ let TargetPrefix = "nvvm" in { // Min Max // - def int_nvvm_min_i : GCCBuiltin<"__nvvm_min_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_min_ui : GCCBuiltin<"__nvvm_min_ui">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_min_ll : GCCBuiltin<"__nvvm_min_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_min_ull : GCCBuiltin<"__nvvm_min_ull">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_max_i : GCCBuiltin<"__nvvm_max_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_max_ui : GCCBuiltin<"__nvvm_max_ui">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_max_ll : GCCBuiltin<"__nvvm_max_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_max_ull : GCCBuiltin<"__nvvm_max_ull">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_fmin_f : GCCBuiltin<"__nvvm_fmin_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem, Commutative]>; @@ -201,15 +184,6 @@ let TargetPrefix = "nvvm" in { [IntrNoMem, Commutative]>; // -// Brev -// - - def int_nvvm_brev32 : GCCBuiltin<"__nvvm_brev32">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_brev64 : GCCBuiltin<"__nvvm_brev64">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty], [IntrNoMem]>; - -// // Sad // @@ -242,16 +216,10 @@ let TargetPrefix = "nvvm" in { // Abs // - def int_nvvm_abs_i : GCCBuiltin<"__nvvm_abs_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_abs_ll : GCCBuiltin<"__nvvm_abs_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty], [IntrNoMem]>; - def int_nvvm_fabs_ftz_f : GCCBuiltin<"__nvvm_fabs_ftz_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty], [IntrNoMem]>; def int_nvvm_fabs_f : GCCBuiltin<"__nvvm_fabs_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty], [IntrNoMem]>; - def int_nvvm_fabs_d : GCCBuiltin<"__nvvm_fabs_d">, Intrinsic<[llvm_double_ty], [llvm_double_ty], [IntrNoMem]>; @@ -700,9 +668,6 @@ let TargetPrefix = "nvvm" in { def int_nvvm_f2h_rn : GCCBuiltin<"__nvvm_f2h_rn">, Intrinsic<[llvm_i16_ty], [llvm_float_ty], [IntrNoMem]>; - def int_nvvm_h2f : GCCBuiltin<"__nvvm_h2f">, - Intrinsic<[llvm_float_ty], [llvm_i16_ty], [IntrNoMem]>; - // // Bitcast // @@ -768,6 +733,13 @@ let TargetPrefix = "nvvm" in { // intrinsics in this file, this one is a user-facing API. def int_nvvm_barrier0 : GCCBuiltin<"__syncthreads">, Intrinsic<[], [], [IntrConvergent]>; + // Synchronize all threads in the CTA at barrier 'n'. + def int_nvvm_barrier_n : GCCBuiltin<"__nvvm_bar_n">, + Intrinsic<[], [llvm_i32_ty], [IntrConvergent]>; + // Synchronize 'm', a multiple of warp size, (arg 2) threads in + // the CTA at barrier 'n' (arg 1). + def int_nvvm_barrier : GCCBuiltin<"__nvvm_bar">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_popc : GCCBuiltin<"__nvvm_bar0_popc">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_and : GCCBuiltin<"__nvvm_bar0_and">, diff --git a/include/llvm/IR/IntrinsicsPowerPC.td b/include/llvm/IR/IntrinsicsPowerPC.td index 12e23b681ca4..64240a929782 100644 --- a/include/llvm/IR/IntrinsicsPowerPC.td +++ b/include/llvm/IR/IntrinsicsPowerPC.td @@ -203,19 +203,19 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // source address with a single pointer. def int_ppc_altivec_stvx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvxl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvebx : Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvehx : Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvewx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; // Comparisons setting a vector. def int_ppc_altivec_vcmpbfp : GCCBuiltin<"__builtin_altivec_vcmpbfp">, @@ -749,20 +749,20 @@ def int_ppc_vsx_lxvll : IntrArgMemOnly]>; def int_ppc_vsx_stxvl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i64_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_vsx_stxvll : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i64_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; // Vector store. -def int_ppc_vsx_stxvw4x : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvd2x : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvw4x_be : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvd2x_be : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; +def int_ppc_vsx_stxvw4x : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvd2x : Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvw4x_be : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvd2x_be : Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; // Vector and scalar maximum. def int_ppc_vsx_xvmaxdp : PowerPC_VSX_Vec_DDD_Intrinsic<"xvmaxdp">; def int_ppc_vsx_xvmaxsp : PowerPC_VSX_Vec_FFF_Intrinsic<"xvmaxsp">; @@ -953,7 +953,7 @@ class PowerPC_QPX_LoadPerm_Intrinsic<string GCCIntSuffix> class PowerPC_QPX_Store_Intrinsic<string GCCIntSuffix> : PowerPC_QPX_Intrinsic<GCCIntSuffix, [], [llvm_v4f64_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // PowerPC QPX Intrinsic Definitions. diff --git a/include/llvm/IR/IntrinsicsWebAssembly.td b/include/llvm/IR/IntrinsicsWebAssembly.td index 4234c466d973..3a0957dfa39b 100644 --- a/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/include/llvm/IR/IntrinsicsWebAssembly.td @@ -17,6 +17,6 @@ let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.". // Note that current_memory is not IntrNoMem because it must be sequenced with // respect to grow_memory calls. def int_wasm_current_memory : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; -def int_wasm_grow_memory : Intrinsic<[], [llvm_anyint_ty], []>; +def int_wasm_grow_memory : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], []>; } diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index 85966af9c820..97c756cf4b60 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -785,12 +785,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem, Commutative]>; } -// Cacheability support ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_movntdqa : GCCBuiltin<"__builtin_ia32_movntdqa">, - Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty], [IntrReadMem]>; -} - // Test instruction with bitwise comparison. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_ptestz : GCCBuiltin<"__builtin_ia32_ptestz128">, @@ -2346,8 +2340,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_mpsadbw : GCCBuiltin<"__builtin_ia32_mpsadbw256">, Intrinsic<[llvm_v16i16_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_movntdqa : GCCBuiltin<"__builtin_ia32_movntdqa256">, - Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty], [IntrReadMem]>; } //===----------------------------------------------------------------------===// @@ -3033,17 +3025,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xop_vfrcz_ps_256 : GCCBuiltin<"__builtin_ia32_vfrczps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty], [IntrNoMem]>; - def int_x86_xop_vpcmov : - GCCBuiltin<"__builtin_ia32_vpcmov">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty], - [IntrNoMem]>; - def int_x86_xop_vpcmov_256 : - GCCBuiltin<"__builtin_ia32_vpcmov_256">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty], - [IntrNoMem]>; - def int_x86_xop_vpcomb : GCCBuiltin<"__builtin_ia32_vpcomb">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i8_ty], [IntrNoMem]>; @@ -3881,74 +3862,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_cvtq2mask_512 : GCCBuiltin<"__builtin_ia32_cvtq2mask512">, Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_128 : GCCBuiltin<"__builtin_ia32_cvtmask2b128">, - Intrinsic<[llvm_v16i8_ty], [llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_256 : GCCBuiltin<"__builtin_ia32_cvtmask2b256">, - Intrinsic<[llvm_v32i8_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_512 : GCCBuiltin<"__builtin_ia32_cvtmask2b512">, - Intrinsic<[llvm_v64i8_ty], [llvm_i64_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2w_128 : GCCBuiltin<"__builtin_ia32_cvtmask2w128">, - Intrinsic<[llvm_v8i16_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2w_256 : GCCBuiltin<"__builtin_ia32_cvtmask2w256">, - Intrinsic<[llvm_v16i16_ty], [llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2w_512 : GCCBuiltin<"__builtin_ia32_cvtmask2w512">, - Intrinsic<[llvm_v32i16_ty], [llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2d_128 : GCCBuiltin<"__builtin_ia32_cvtmask2d128">, - Intrinsic<[llvm_v4i32_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2d_256 : GCCBuiltin<"__builtin_ia32_cvtmask2d256">, - Intrinsic<[llvm_v8i32_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2d_512 : GCCBuiltin<"__builtin_ia32_cvtmask2d512">, - Intrinsic<[llvm_v16i32_ty], [llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2q_128 : GCCBuiltin<"__builtin_ia32_cvtmask2q128">, - Intrinsic<[llvm_v2i64_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2q_256 : GCCBuiltin<"__builtin_ia32_cvtmask2q256">, - Intrinsic<[llvm_v4i64_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2q_512 : GCCBuiltin<"__builtin_ia32_cvtmask2q512">, - Intrinsic<[llvm_v8i64_ty], [llvm_i8_ty], [IntrNoMem]>; - } // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_packsswb_128 : GCCBuiltin<"__builtin_ia32_packsswb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, - llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packsswb_256 : GCCBuiltin<"__builtin_ia32_packsswb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v16i16_ty,llvm_v16i16_ty, - llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packsswb_512 : GCCBuiltin<"__builtin_ia32_packsswb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty, - llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_128 : GCCBuiltin<"__builtin_ia32_packssdw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_256 : GCCBuiltin<"__builtin_ia32_packssdw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_512 : GCCBuiltin<"__builtin_ia32_packssdw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_128 : GCCBuiltin<"__builtin_ia32_packuswb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, - llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_256 : GCCBuiltin<"__builtin_ia32_packuswb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v16i16_ty,llvm_v16i16_ty, - llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_512 : GCCBuiltin<"__builtin_ia32_packuswb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty, - llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_128 : GCCBuiltin<"__builtin_ia32_packusdw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_256 : GCCBuiltin<"__builtin_ia32_packusdw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_512 : GCCBuiltin<"__builtin_ia32_packusdw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_packsswb_512 : GCCBuiltin<"__builtin_ia32_packsswb512">, + Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty], + [IntrNoMem]>; + def int_x86_avx512_packssdw_512 : GCCBuiltin<"__builtin_ia32_packssdw512">, + Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty], + [IntrNoMem]>; + def int_x86_avx512_packuswb_512 : GCCBuiltin<"__builtin_ia32_packuswb512">, + Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty], + [IntrNoMem]>; + def int_x86_avx512_packusdw_512 : GCCBuiltin<"__builtin_ia32_packusdw512">, + Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty], + [IntrNoMem]>; } // Vector convert @@ -4595,39 +4524,15 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_div_pd_512 : GCCBuiltin<"__builtin_ia32_divpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_ps_128 : GCCBuiltin<"__builtin_ia32_maxps_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_ps_256 : GCCBuiltin<"__builtin_ia32_maxps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_max_ps_512 : GCCBuiltin<"__builtin_ia32_maxps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_pd_128 : GCCBuiltin<"__builtin_ia32_maxpd_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_pd_256 : GCCBuiltin<"__builtin_ia32_maxpd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_max_pd_512 : GCCBuiltin<"__builtin_ia32_maxpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_ps_128 : GCCBuiltin<"__builtin_ia32_minps_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_ps_256 : GCCBuiltin<"__builtin_ia32_minps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_min_ps_512 : GCCBuiltin<"__builtin_ia32_minps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_pd_128 : GCCBuiltin<"__builtin_ia32_minpd_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_pd_256 : GCCBuiltin<"__builtin_ia32_minpd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_min_pd_512 : GCCBuiltin<"__builtin_ia32_minpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -5481,32 +5386,6 @@ let TargetPrefix = "x86" in { Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_lzcnt_d_128 : - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_d_256 : - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_d_512 : - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_lzcnt_q_128 : - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_q_256 : - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_q_512 : - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; } // Compares @@ -6458,10 +6337,6 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_cmpsd_mask">, Intrinsic<[llvm_i8_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_movntdqa : - GCCBuiltin<"__builtin_ia32_movntdqa512">, - Intrinsic<[llvm_v8i64_ty], [llvm_ptr_ty], [IntrReadMem]>; } //===----------------------------------------------------------------------===// @@ -6495,3 +6370,10 @@ let TargetPrefix = "x86" in { : GCCBuiltin<"__builtin_ia32_mwaitx">, Intrinsic<[], [ llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], []>; } + +//===----------------------------------------------------------------------===// +// Cache-line zero +let TargetPrefix = "x86" in { + def int_x86_clzero : GCCBuiltin<"__builtin_ia32_clzero">, + Intrinsic<[], [llvm_ptr_ty], []>; +} diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 7f43d5df3c3f..d13d5ddaeb3c 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -78,6 +78,7 @@ public: MD_type = 19, // "type" MD_section_prefix = 20, // "section_prefix" MD_absolute_symbol = 21, // "absolute_symbol" + MD_associated = 22, // "associated" }; /// Known operand bundle tag IDs, which always have the same value. All diff --git a/include/llvm/IR/MDBuilder.h b/include/llvm/IR/MDBuilder.h index bab8728ed49f..899976a87bc7 100644 --- a/include/llvm/IR/MDBuilder.h +++ b/include/llvm/IR/MDBuilder.h @@ -15,7 +15,9 @@ #ifndef LLVM_IR_MDBUILDER_H #define LLVM_IR_MDBUILDER_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/Support/DataTypes.h" #include <utility> @@ -63,8 +65,11 @@ public: /// Return metadata specifying that a branch or switch is unpredictable. MDNode *createUnpredictable(); - /// Return metadata containing the entry count for a function. - MDNode *createFunctionEntryCount(uint64_t Count); + /// Return metadata containing the entry \p Count for a function, and the + /// GUIDs stored in \p Imports that need to be imported for sample PGO, to + /// enable the same inlines as the profiled optimized binary + MDNode *createFunctionEntryCount(uint64_t Count, + const DenseSet<GlobalValue::GUID> *Imports); /// Return metadata containing the section prefix for a function. MDNode *createFunctionSectionPrefix(StringRef Prefix); diff --git a/include/llvm/IR/Mangler.h b/include/llvm/IR/Mangler.h index 0eb91a3b0600..56ee21392ccd 100644 --- a/include/llvm/IR/Mangler.h +++ b/include/llvm/IR/Mangler.h @@ -21,6 +21,7 @@ namespace llvm { class DataLayout; template <typename T> class SmallVectorImpl; +class Triple; class Twine; class raw_ostream; @@ -46,6 +47,9 @@ public: const Twine &GVName, const DataLayout &DL); }; +void emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, + const Triple &TT, Mangler &Mangler); + } // End llvm namespace #endif diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 46c785a1c05d..fd79355bff1a 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -78,7 +78,7 @@ public: protected: Metadata(unsigned ID, StorageType Storage) : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) { - static_assert(sizeof(*this) == 8, "Metdata fields poorly packed"); + static_assert(sizeof(*this) == 8, "Metadata fields poorly packed"); } ~Metadata() = default; @@ -269,12 +269,11 @@ public: private: LLVMContext &Context; - uint64_t NextIndex; + uint64_t NextIndex = 0; SmallDenseMap<void *, std::pair<OwnerTy, uint64_t>, 4> UseMap; public: - ReplaceableMetadataImpl(LLVMContext &Context) - : Context(Context), NextIndex(0) {} + ReplaceableMetadataImpl(LLVMContext &Context) : Context(Context) {} ~ReplaceableMetadataImpl() { assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata"); @@ -586,8 +585,9 @@ dyn_extract_or_null(Y &&MD) { class MDString : public Metadata { friend class StringMapEntry<MDString>; - StringMapEntry<MDString> *Entry; - MDString() : Metadata(MDStringKind, Uniqued), Entry(nullptr) {} + StringMapEntry<MDString> *Entry = nullptr; + + MDString() : Metadata(MDStringKind, Uniqued) {} public: MDString(const MDString &) = delete; @@ -1062,7 +1062,6 @@ public: static MDNode *getMostGenericRange(MDNode *A, MDNode *B); static MDNode *getMostGenericAliasScope(MDNode *A, MDNode *B); static MDNode *getMostGenericAlignmentOrDereferenceable(MDNode *A, MDNode *B); - }; /// \brief Tuple of metadata. @@ -1284,7 +1283,7 @@ class NamedMDNode : public ilist_node<NamedMDNode> { friend class Module; std::string Name; - Module *Parent; + Module *Parent = nullptr; void *Operands; // SmallVector<TrackingMDRef, 4> void setParent(Module *M) { Parent = M; } diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 79870b9455a6..70c57cf90add 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -311,7 +311,7 @@ public: /// 4. Finally, the function exists but has the wrong prototype: return the /// function with a constantexpr cast to the right prototype. Constant *getOrInsertFunction(StringRef Name, FunctionType *T, - AttributeSet AttributeList); + AttributeList AttributeList); Constant *getOrInsertFunction(StringRef Name, FunctionType *T); @@ -321,13 +321,22 @@ public: /// or a ConstantExpr BitCast of that type if the named function has a /// different type. This version of the method takes a null terminated list of /// function arguments, which makes it easier for clients to use. + template<typename... ArgsTy> Constant *getOrInsertFunction(StringRef Name, - AttributeSet AttributeList, - Type *RetTy, ...) LLVM_END_WITH_NULL; + AttributeList AttributeList, + Type *RetTy, ArgsTy... Args) + { + SmallVector<Type*, sizeof...(ArgsTy)> ArgTys{Args...}; + return getOrInsertFunction(Name, + FunctionType::get(RetTy, ArgTys, false), + AttributeList); + } /// Same as above, but without the attributes. - Constant *getOrInsertFunction(StringRef Name, Type *RetTy, ...) - LLVM_END_WITH_NULL; + template<typename... ArgsTy> + Constant *getOrInsertFunction(StringRef Name, Type *RetTy, ArgsTy... Args) { + return getOrInsertFunction(Name, AttributeList{}, RetTy, Args...); + } /// Look up the specified function in the module symbol table. If it does not /// exist, return null. @@ -345,20 +354,23 @@ public: return getGlobalVariable(Name, false); } - GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal) const { - return const_cast<Module *>(this)->getGlobalVariable(Name, AllowInternal); - } + GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal) const; - GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal = false); + GlobalVariable *getGlobalVariable(StringRef Name, + bool AllowInternal = false) { + return static_cast<const Module *>(this)->getGlobalVariable(Name, + AllowInternal); + } /// Return the global variable in the module with the specified name, of /// arbitrary type. This method returns null if a global with the specified /// name is not found. - GlobalVariable *getNamedGlobal(StringRef Name) { + const GlobalVariable *getNamedGlobal(StringRef Name) const { return getGlobalVariable(Name, true); } - const GlobalVariable *getNamedGlobal(StringRef Name) const { - return const_cast<Module *>(this)->getNamedGlobal(Name); + GlobalVariable *getNamedGlobal(StringRef Name) { + return const_cast<GlobalVariable *>( + static_cast<const Module *>(this)->getNamedGlobal(Name)); } /// Look up the specified global in the module symbol table. @@ -615,6 +627,32 @@ public: return global_objects().end(); } + typedef concat_iterator<GlobalValue, iterator, global_iterator, + alias_iterator, ifunc_iterator> + global_value_iterator; + typedef concat_iterator<const GlobalValue, const_iterator, + const_global_iterator, const_alias_iterator, + const_ifunc_iterator> + const_global_value_iterator; + + iterator_range<global_value_iterator> global_values() { + return concat<GlobalValue>(functions(), globals(), aliases(), ifuncs()); + } + iterator_range<const_global_value_iterator> global_values() const { + return concat<const GlobalValue>(functions(), globals(), aliases(), + ifuncs()); + } + + global_value_iterator global_value_begin() { return global_values().begin(); } + global_value_iterator global_value_end() { return global_values().end(); } + + const_global_value_iterator global_value_begin() const { + return global_values().begin(); + } + const_global_value_iterator global_value_end() const { + return global_values().end(); + } + /// @} /// @name Named Metadata Iteration /// @{ @@ -726,6 +764,10 @@ public: /// @name Utility functions for querying Debug information. /// @{ + /// \brief Returns the Number of Register ParametersDwarf Version by checking + /// module flags. + unsigned getNumberRegisterParameters() const; + /// \brief Returns the Dwarf Version by checking module flags. unsigned getDwarfVersion() const; diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index 83c4ae011216..09f6c1897009 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -162,7 +162,7 @@ private: protected: /// GlobalValueSummary constructor. GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs) - : Kind(K), Flags(Flags), RefEdgeList(std::move(Refs)) {} + : Kind(K), Flags(Flags), OriginalName(0), RefEdgeList(std::move(Refs)) {} public: virtual ~GlobalValueSummary() = default; @@ -233,12 +233,13 @@ public: void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } const GlobalValueSummary &getAliasee() const { - return const_cast<AliasSummary *>(this)->getAliasee(); + assert(AliaseeSummary && "Unexpected missing aliasee summary"); + return *AliaseeSummary; } GlobalValueSummary &getAliasee() { - assert(AliaseeSummary && "Unexpected missing aliasee summary"); - return *AliaseeSummary; + return const_cast<GlobalValueSummary &>( + static_cast<const AliasSummary *>(this)->getAliasee()); } }; @@ -249,6 +250,23 @@ public: /// <CalleeValueInfo, CalleeInfo> call edge pair. typedef std::pair<ValueInfo, CalleeInfo> EdgeTy; + /// An "identifier" for a virtual function. This contains the type identifier + /// represented as a GUID and the offset from the address point to the virtual + /// function pointer, where "address point" is as defined in the Itanium ABI: + /// https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general + struct VFuncId { + GlobalValue::GUID GUID; + uint64_t Offset; + }; + + /// A specification for a virtual function call with all constant integer + /// arguments. This is used to perform virtual constant propagation on the + /// summary. + struct ConstVCall { + VFuncId VFunc; + std::vector<uint64_t> Args; + }; + private: /// Number of instructions (ignoring debug instructions, e.g.) computed /// during the initial compile step when the summary index is first built. @@ -257,17 +275,47 @@ private: /// List of <CalleeValueInfo, CalleeInfo> call edge pairs from this function. std::vector<EdgeTy> CallGraphEdgeList; - /// List of type identifiers used by this function, represented as GUIDs. - std::vector<GlobalValue::GUID> TypeIdList; + /// All type identifier related information. Because these fields are + /// relatively uncommon we only allocate space for them if necessary. + struct TypeIdInfo { + /// List of type identifiers used by this function in llvm.type.test + /// intrinsics other than by an llvm.assume intrinsic, represented as GUIDs. + std::vector<GlobalValue::GUID> TypeTests; + + /// List of virtual calls made by this function using (respectively) + /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics that do + /// not have all constant integer arguments. + std::vector<VFuncId> TypeTestAssumeVCalls, TypeCheckedLoadVCalls; + + /// List of virtual calls made by this function using (respectively) + /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics with + /// all constant integer arguments. + std::vector<ConstVCall> TypeTestAssumeConstVCalls, + TypeCheckedLoadConstVCalls; + }; + + std::unique_ptr<TypeIdInfo> TIdInfo; public: /// Summary constructors. FunctionSummary(GVFlags Flags, unsigned NumInsts, std::vector<ValueInfo> Refs, std::vector<EdgeTy> CGEdges, - std::vector<GlobalValue::GUID> TypeIds) + std::vector<GlobalValue::GUID> TypeTests, + std::vector<VFuncId> TypeTestAssumeVCalls, + std::vector<VFuncId> TypeCheckedLoadVCalls, + std::vector<ConstVCall> TypeTestAssumeConstVCalls, + std::vector<ConstVCall> TypeCheckedLoadConstVCalls) : GlobalValueSummary(FunctionKind, Flags, std::move(Refs)), - InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)), - TypeIdList(std::move(TypeIds)) {} + InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)) { + if (!TypeTests.empty() || !TypeTestAssumeVCalls.empty() || + !TypeCheckedLoadVCalls.empty() || !TypeTestAssumeConstVCalls.empty() || + !TypeCheckedLoadConstVCalls.empty()) + TIdInfo = llvm::make_unique<TypeIdInfo>(TypeIdInfo{ + std::move(TypeTests), std::move(TypeTestAssumeVCalls), + std::move(TypeCheckedLoadVCalls), + std::move(TypeTestAssumeConstVCalls), + std::move(TypeCheckedLoadConstVCalls)}); + } /// Check if this is a function summary. static bool classof(const GlobalValueSummary *GVS) { @@ -280,8 +328,85 @@ public: /// Return the list of <CalleeValueInfo, CalleeInfo> pairs. ArrayRef<EdgeTy> calls() const { return CallGraphEdgeList; } - /// Returns the list of type identifiers used by this function. - ArrayRef<GlobalValue::GUID> type_tests() const { return TypeIdList; } + /// Returns the list of type identifiers used by this function in + /// llvm.type.test intrinsics other than by an llvm.assume intrinsic, + /// represented as GUIDs. + ArrayRef<GlobalValue::GUID> type_tests() const { + if (TIdInfo) + return TIdInfo->TypeTests; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.assume(llvm.type.test) intrinsics that do not have all constant + /// integer arguments. + ArrayRef<VFuncId> type_test_assume_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeTestAssumeVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.type.checked.load intrinsics that do not have all constant integer + /// arguments. + ArrayRef<VFuncId> type_checked_load_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeCheckedLoadVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.assume(llvm.type.test) intrinsics with all constant integer + /// arguments. + ArrayRef<ConstVCall> type_test_assume_const_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeTestAssumeConstVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.type.checked.load intrinsics with all constant integer arguments. + ArrayRef<ConstVCall> type_checked_load_const_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeCheckedLoadConstVCalls; + return {}; + } + + /// Add a type test to the summary. This is used by WholeProgramDevirt if we + /// were unable to devirtualize a checked call. + void addTypeTest(GlobalValue::GUID Guid) { + if (!TIdInfo) + TIdInfo = llvm::make_unique<TypeIdInfo>(); + TIdInfo->TypeTests.push_back(Guid); + } +}; + +template <> struct DenseMapInfo<FunctionSummary::VFuncId> { + static FunctionSummary::VFuncId getEmptyKey() { return {0, uint64_t(-1)}; } + static FunctionSummary::VFuncId getTombstoneKey() { + return {0, uint64_t(-2)}; + } + static bool isEqual(FunctionSummary::VFuncId L, FunctionSummary::VFuncId R) { + return L.GUID == R.GUID && L.Offset == R.Offset; + } + static unsigned getHashValue(FunctionSummary::VFuncId I) { return I.GUID; } +}; + +template <> struct DenseMapInfo<FunctionSummary::ConstVCall> { + static FunctionSummary::ConstVCall getEmptyKey() { + return {{0, uint64_t(-1)}, {}}; + } + static FunctionSummary::ConstVCall getTombstoneKey() { + return {{0, uint64_t(-2)}, {}}; + } + static bool isEqual(FunctionSummary::ConstVCall L, + FunctionSummary::ConstVCall R) { + return DenseMapInfo<FunctionSummary::VFuncId>::isEqual(L.VFunc, R.VFunc) && + L.Args == R.Args; + } + static unsigned getHashValue(FunctionSummary::ConstVCall I) { + return I.VFunc.GUID; + } }; /// \brief Global variable summary information to aid decisions and @@ -323,8 +448,40 @@ struct TypeTestResolution { unsigned SizeM1BitWidth = 0; }; +struct WholeProgramDevirtResolution { + enum Kind { + Indir, ///< Just do a regular virtual call + SingleImpl, ///< Single implementation devirtualization + } TheKind = Indir; + + std::string SingleImplName; + + struct ByArg { + enum Kind { + Indir, ///< Just do a regular virtual call + UniformRetVal, ///< Uniform return value optimization + UniqueRetVal, ///< Unique return value optimization + VirtualConstProp, ///< Virtual constant propagation + } TheKind = Indir; + + /// Additional information for the resolution: + /// - UniformRetVal: the uniform return value. + /// - UniqueRetVal: the return value associated with the unique vtable (0 or + /// 1). + uint64_t Info = 0; + }; + + /// Resolutions for calls with all constant integer arguments (excluding the + /// first argument, "this"), where the key is the argument vector. + std::map<std::vector<uint64_t>, ByArg> ResByArg; +}; + struct TypeIdSummary { TypeTestResolution TTRes; + + /// Mapping from byte offset to whole-program devirt resolution for that + /// (typeid, byte offset) pair. + std::map<uint64_t, WholeProgramDevirtResolution> WPDRes; }; /// 160 bits SHA1 @@ -372,6 +529,10 @@ private: // FIXME: Add bitcode read/write support for this field. std::map<std::string, TypeIdSummary> TypeIdMap; + /// Mapping from original ID to GUID. If original ID can map to multiple + /// GUIDs, it will be mapped to 0. + std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap; + // YAML I/O support. friend yaml::MappingTraits<ModuleSummaryIndex>; @@ -399,9 +560,17 @@ public: return GlobalValueMap.find(ValueGUID); } + /// Return the GUID for \p OriginalId in the OidGuidMap. + GlobalValue::GUID getGUIDFromOriginalID(GlobalValue::GUID OriginalID) const { + const auto I = OidGuidMap.find(OriginalID); + return I == OidGuidMap.end() ? 0 : I->second; + } + /// Add a global value summary for a value of the given name. void addGlobalValueSummary(StringRef ValueName, std::unique_ptr<GlobalValueSummary> Summary) { + addOriginalName(GlobalValue::getGUID(ValueName), + Summary->getOriginalName()); GlobalValueMap[GlobalValue::getGUID(ValueName)].push_back( std::move(Summary)); } @@ -409,9 +578,21 @@ public: /// Add a global value summary for a value of the given GUID. void addGlobalValueSummary(GlobalValue::GUID ValueGUID, std::unique_ptr<GlobalValueSummary> Summary) { + addOriginalName(ValueGUID, Summary->getOriginalName()); GlobalValueMap[ValueGUID].push_back(std::move(Summary)); } + /// Add an original name for the value of the given GUID. + void addOriginalName(GlobalValue::GUID ValueGUID, + GlobalValue::GUID OrigGUID) { + if (OrigGUID == 0 || ValueGUID == OrigGUID) + return; + if (OidGuidMap.count(OrigGUID) && OidGuidMap[OrigGUID] != ValueGUID) + OidGuidMap[OrigGUID] = 0; + else + OidGuidMap[OrigGUID] = ValueGUID; + } + /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if /// not found. GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, @@ -507,6 +688,25 @@ public: return ModulePathStringTable.count(M.getModuleIdentifier()); } + const std::map<std::string, TypeIdSummary> &typeIds() const { + return TypeIdMap; + } + + /// This accessor should only be used when exporting because it can mutate the + /// map. + TypeIdSummary &getOrInsertTypeIdSummary(StringRef TypeId) { + return TypeIdMap[TypeId]; + } + + /// This returns either a pointer to the type id summary (if present in the + /// summary map) or null (if not present). This may be used when importing. + const TypeIdSummary *getTypeIdSummary(StringRef TypeId) const { + auto I = TypeIdMap.find(TypeId); + if (I == TypeIdMap.end()) + return nullptr; + return &I->second; + } + /// Remove entries in the GlobalValueMap that have empty summaries due to the /// eager nature of map entry creation during VST parsing. These would /// also be suppressed during combined index generation in mergeFrom(), diff --git a/include/llvm/IR/ModuleSummaryIndexYAML.h b/include/llvm/IR/ModuleSummaryIndexYAML.h index e2880ec6fec8..80719c696935 100644 --- a/include/llvm/IR/ModuleSummaryIndexYAML.h +++ b/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -33,20 +33,135 @@ template <> struct MappingTraits<TypeTestResolution> { } }; +template <> +struct ScalarEnumerationTraits<WholeProgramDevirtResolution::ByArg::Kind> { + static void enumeration(IO &io, + WholeProgramDevirtResolution::ByArg::Kind &value) { + io.enumCase(value, "Indir", WholeProgramDevirtResolution::ByArg::Indir); + io.enumCase(value, "UniformRetVal", + WholeProgramDevirtResolution::ByArg::UniformRetVal); + io.enumCase(value, "UniqueRetVal", + WholeProgramDevirtResolution::ByArg::UniqueRetVal); + io.enumCase(value, "VirtualConstProp", + WholeProgramDevirtResolution::ByArg::VirtualConstProp); + } +}; + +template <> struct MappingTraits<WholeProgramDevirtResolution::ByArg> { + static void mapping(IO &io, WholeProgramDevirtResolution::ByArg &res) { + io.mapOptional("Kind", res.TheKind); + io.mapOptional("Info", res.Info); + } +}; + +template <> +struct CustomMappingTraits< + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>> { + static void inputOne( + IO &io, StringRef Key, + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) { + std::vector<uint64_t> Args; + std::pair<StringRef, StringRef> P = {"", Key}; + while (!P.second.empty()) { + P = P.second.split(','); + uint64_t Arg; + if (P.first.getAsInteger(0, Arg)) { + io.setError("key not an integer"); + return; + } + Args.push_back(Arg); + } + io.mapRequired(Key.str().c_str(), V[Args]); + } + static void output( + IO &io, + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) { + for (auto &P : V) { + std::string Key; + for (uint64_t Arg : P.first) { + if (!Key.empty()) + Key += ','; + Key += llvm::utostr(Arg); + } + io.mapRequired(Key.c_str(), P.second); + } + } +}; + +template <> struct ScalarEnumerationTraits<WholeProgramDevirtResolution::Kind> { + static void enumeration(IO &io, WholeProgramDevirtResolution::Kind &value) { + io.enumCase(value, "Indir", WholeProgramDevirtResolution::Indir); + io.enumCase(value, "SingleImpl", WholeProgramDevirtResolution::SingleImpl); + } +}; + +template <> struct MappingTraits<WholeProgramDevirtResolution> { + static void mapping(IO &io, WholeProgramDevirtResolution &res) { + io.mapOptional("Kind", res.TheKind); + io.mapOptional("SingleImplName", res.SingleImplName); + io.mapOptional("ResByArg", res.ResByArg); + } +}; + +template <> +struct CustomMappingTraits<std::map<uint64_t, WholeProgramDevirtResolution>> { + static void inputOne(IO &io, StringRef Key, + std::map<uint64_t, WholeProgramDevirtResolution> &V) { + uint64_t KeyInt; + if (Key.getAsInteger(0, KeyInt)) { + io.setError("key not an integer"); + return; + } + io.mapRequired(Key.str().c_str(), V[KeyInt]); + } + static void output(IO &io, std::map<uint64_t, WholeProgramDevirtResolution> &V) { + for (auto &P : V) + io.mapRequired(llvm::utostr(P.first).c_str(), P.second); + } +}; + template <> struct MappingTraits<TypeIdSummary> { static void mapping(IO &io, TypeIdSummary& summary) { io.mapOptional("TTRes", summary.TTRes); + io.mapOptional("WPDRes", summary.WPDRes); } }; struct FunctionSummaryYaml { std::vector<uint64_t> TypeTests; + std::vector<FunctionSummary::VFuncId> TypeTestAssumeVCalls, + TypeCheckedLoadVCalls; + std::vector<FunctionSummary::ConstVCall> TypeTestAssumeConstVCalls, + TypeCheckedLoadConstVCalls; +}; + +} // End yaml namespace +} // End llvm namespace + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<FunctionSummary::VFuncId> { + static void mapping(IO &io, FunctionSummary::VFuncId& id) { + io.mapOptional("GUID", id.GUID); + io.mapOptional("Offset", id.Offset); + } +}; + +template <> struct MappingTraits<FunctionSummary::ConstVCall> { + static void mapping(IO &io, FunctionSummary::ConstVCall& id) { + io.mapOptional("VFunc", id.VFunc); + io.mapOptional("Args", id.Args); + } }; } // End yaml namespace } // End llvm namespace -LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::VFuncId) +LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::ConstVCall) namespace llvm { namespace yaml { @@ -54,6 +169,12 @@ namespace yaml { template <> struct MappingTraits<FunctionSummaryYaml> { static void mapping(IO &io, FunctionSummaryYaml& summary) { io.mapOptional("TypeTests", summary.TypeTests); + io.mapOptional("TypeTestAssumeVCalls", summary.TypeTestAssumeVCalls); + io.mapOptional("TypeCheckedLoadVCalls", summary.TypeCheckedLoadVCalls); + io.mapOptional("TypeTestAssumeConstVCalls", + summary.TypeTestAssumeConstVCalls); + io.mapOptional("TypeCheckedLoadConstVCalls", + summary.TypeCheckedLoadConstVCalls); } }; @@ -82,7 +203,11 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> { false); Elem.push_back(llvm::make_unique<FunctionSummary>( GVFlags, 0, ArrayRef<ValueInfo>{}, - ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests))); + ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests), + std::move(FSum.TypeTestAssumeVCalls), + std::move(FSum.TypeCheckedLoadVCalls), + std::move(FSum.TypeTestAssumeConstVCalls), + std::move(FSum.TypeCheckedLoadConstVCalls))); } } static void output(IO &io, GlobalValueSummaryMapTy &V) { @@ -90,7 +215,11 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> { std::vector<FunctionSummaryYaml> FSums; for (auto &Sum : P.second) { if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get())) - FSums.push_back(FunctionSummaryYaml{FSum->type_tests()}); + FSums.push_back(FunctionSummaryYaml{ + FSum->type_tests(), FSum->type_test_assume_vcalls(), + FSum->type_checked_load_vcalls(), + FSum->type_test_assume_const_vcalls(), + FSum->type_checked_load_const_vcalls()}); } if (!FSums.empty()) io.mapRequired(llvm::utostr(P.first).c_str(), FSums); diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 444ce93921f6..997a85340c25 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -18,8 +18,6 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -174,12 +172,15 @@ private: FastMathFlags(unsigned F) : Flags(F) { } public: + /// This is how the bits are used in Value::SubclassOptionalData so they + /// should fit there too. enum { UnsafeAlgebra = (1 << 0), NoNaNs = (1 << 1), NoInfs = (1 << 2), NoSignedZeros = (1 << 3), - AllowReciprocal = (1 << 4) + AllowReciprocal = (1 << 4), + AllowContract = (1 << 5) }; FastMathFlags() = default; @@ -195,6 +196,7 @@ public: bool noInfs() const { return 0 != (Flags & NoInfs); } bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } + bool allowContract() const { return 0 != (Flags & AllowContract); } bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); } /// Flag setters @@ -202,12 +204,16 @@ public: void setNoInfs() { Flags |= NoInfs; } void setNoSignedZeros() { Flags |= NoSignedZeros; } void setAllowReciprocal() { Flags |= AllowReciprocal; } + void setAllowContract(bool B) { + Flags = (Flags & ~AllowContract) | B * AllowContract; + } void setUnsafeAlgebra() { Flags |= UnsafeAlgebra; setNoNaNs(); setNoInfs(); setNoSignedZeros(); setAllowReciprocal(); + setAllowContract(true); } void operator&=(const FastMathFlags &OtherFlags) { @@ -259,6 +265,12 @@ private: (B * FastMathFlags::AllowReciprocal); } + void setHasAllowContract(bool B) { + SubclassOptionalData = + (SubclassOptionalData & ~FastMathFlags::AllowContract) | + (B * FastMathFlags::AllowContract); + } + /// Convenience function for setting multiple fast-math flags. /// FMF is a mask of the bits to set. void setFastMathFlags(FastMathFlags FMF) { @@ -302,6 +314,12 @@ public: return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0; } + /// Test whether this operation is permitted to + /// be floating-point contracted. + bool hasAllowContract() const { + return (SubclassOptionalData & FastMathFlags::AllowContract) != 0; + } + /// Convenience function for getting all the fast-math flags FastMathFlags getFastMathFlags() const { return FastMathFlags(SubclassOptionalData); diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h index 9eee65e93e52..185a5ac956f5 100644 --- a/include/llvm/IR/OptBisect.h +++ b/include/llvm/IR/OptBisect.h @@ -51,24 +51,6 @@ public: template <class UnitT> bool shouldRunPass(const Pass *P, const UnitT &U); - /// Checks the bisect limit to determine if the optimization described by the - /// /p Desc argument should run. - /// - /// This function will immediate return true if bisection is disabled. If the - /// bisect limit is set to -1, the function will print a message with the - /// bisect number assigned to the optimization along with the /p Desc - /// description and return true. Otherwise, the function will print a message - /// with the bisect number assigned to the optimization and indicating whether - /// or not the pass will be run and return true if the bisect limit has not - /// yet been exceded or false if it has. - /// - /// Passes may call this function to provide more fine grained control over - /// individual optimizations performed by the pass. Passes which cannot be - /// skipped entirely (such as non-optional code generation passes) may still - /// call this function to control whether or not individual optional - /// transformations are performed. - bool shouldRunCase(const Twine &Desc); - private: bool checkPass(const StringRef PassName, const StringRef TargetDesc); diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index b7811fdb7504..c845112baa45 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -73,6 +73,46 @@ struct alignas(8) AnalysisKey {}; /// if it is, the analysis knows that it itself is preserved. struct alignas(8) AnalysisSetKey {}; +/// This templated class represents "all analyses that operate over \<a +/// particular IR unit\>" (e.g. a Function or a Module) in instances of +/// PreservedAnalysis. +/// +/// This lets a transformation say e.g. "I preserved all function analyses". +/// +/// Note that you must provide an explicit instantiation declaration and +/// definition for this template in order to get the correct behavior on +/// Windows. Otherwise, the address of SetKey will not be stable. +template <typename IRUnitT> class AllAnalysesOn { +public: + static AnalysisSetKey *ID() { return &SetKey; } + +private: + static AnalysisSetKey SetKey; +}; + +template <typename IRUnitT> AnalysisSetKey AllAnalysesOn<IRUnitT>::SetKey; + +extern template class AllAnalysesOn<Module>; +extern template class AllAnalysesOn<Function>; + +/// Represents analyses that only rely on functions' control flow. +/// +/// This can be used with \c PreservedAnalyses to mark the CFG as preserved and +/// to query whether it has been preserved. +/// +/// The CFG of a function is defined as the set of basic blocks and the edges +/// between them. Changing the set of basic blocks in a function is enough to +/// mutate the CFG. Mutating the condition of a branch or argument of an +/// invoked function does not mutate the CFG, but changing the successor labels +/// of those instructions does. +class CFGAnalyses { +public: + static AnalysisSetKey *ID() { return &SetKey; } + +private: + static AnalysisSetKey SetKey; +}; + /// A set of analyses that are preserved following a run of a transformation /// pass. /// @@ -348,29 +388,6 @@ struct AnalysisInfoMixin : PassInfoMixin<DerivedT> { } }; -/// This templated class represents "all analyses that operate over \<a -/// particular IR unit\>" (e.g. a Function or a Module) in instances of -/// PreservedAnalysis. -/// -/// This lets a transformation say e.g. "I preserved all function analyses". -/// -/// Note that you must provide an explicit instantiation declaration and -/// definition for this template in order to get the correct behavior on -/// Windows. Otherwise, the address of SetKey will not be stable. -template <typename IRUnitT> -class AllAnalysesOn { -public: - static AnalysisSetKey *ID() { return &SetKey; } - -private: - static AnalysisSetKey SetKey; -}; - -template <typename IRUnitT> AnalysisSetKey AllAnalysesOn<IRUnitT>::SetKey; - -extern template class AllAnalysesOn<Module>; -extern template class AllAnalysesOn<Function>; - /// \brief Manages a sequence of passes over a particular unit of IR. /// /// A pass manager contains a sequence of passes to run over a particular unit @@ -780,7 +797,7 @@ public: if (DebugLogging) dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name() - << "\n"; + << " on " << IR.getName() << "\n"; I = ResultsList.erase(I); AnalysisResults.erase({ID, &IR}); @@ -821,7 +838,8 @@ private: if (Inserted) { auto &P = this->lookUpPass(ID); if (DebugLogging) - dbgs() << "Running analysis: " << P.name() << "\n"; + dbgs() << "Running analysis: " << P.name() << " on " << IR.getName() + << "\n"; AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; ResultList.emplace_back(ID, P.run(IR, *this, ExtraArgs...)); @@ -852,7 +870,7 @@ private: if (DebugLogging) dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name() - << "\n"; + << " on " << IR.getName() << "\n"; AnalysisResultLists[&IR].erase(RI->second); AnalysisResults.erase(RI); } diff --git a/include/llvm/IR/PassManagerInternal.h b/include/llvm/IR/PassManagerInternal.h index 02f21675fa9d..387dc4c65c43 100644 --- a/include/llvm/IR/PassManagerInternal.h +++ b/include/llvm/IR/PassManagerInternal.h @@ -291,7 +291,7 @@ struct AnalysisPassModel : AnalysisPassConcept<IRUnitT, PreservedAnalysesT, AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, ExtraArgTs... ExtraArgs) override { - return make_unique<ResultModelT>(Pass.run(IR, AM, ExtraArgs...)); + return llvm::make_unique<ResultModelT>(Pass.run(IR, AM, ExtraArgs...)); } /// \brief The model delegates to a static \c PassT::name method. diff --git a/include/llvm/IR/PatternMatch.h b/include/llvm/IR/PatternMatch.h index a30fc97e98ef..40f9c21f646b 100644 --- a/include/llvm/IR/PatternMatch.h +++ b/include/llvm/IR/PatternMatch.h @@ -157,6 +157,19 @@ inline match_combine_or<match_zero, match_neg_zero> m_AnyZero() { return m_CombineOr(m_Zero(), m_NegZero()); } +struct match_nan { + template <typename ITy> bool match(ITy *V) { + if (const auto *C = dyn_cast<ConstantFP>(V)) { + const APFloat &APF = C->getValueAPF(); + return APF.isNaN(); + } + return false; + } +}; + +/// Match an arbitrary NaN constant. This includes quiet and signalling nans. +inline match_nan m_NaN() { return match_nan(); } + struct apint_match { const APInt *&Res; apint_match(const APInt *&R) : Res(R) {} @@ -814,6 +827,13 @@ inline CastClass_match<OpTy, Instruction::ZExt> m_ZExt(const OpTy &Op) { return CastClass_match<OpTy, Instruction::ZExt>(Op); } +template <typename OpTy> +inline match_combine_or<CastClass_match<OpTy, Instruction::ZExt>, + CastClass_match<OpTy, Instruction::SExt>> +m_ZExtOrSExt(const OpTy &Op) { + return m_CombineOr(m_ZExt(Op), m_SExt(Op)); +} + /// \brief Matches UIToFP. template <typename OpTy> inline CastClass_match<OpTy, Instruction::UIToFP> m_UIToFP(const OpTy &Op) { @@ -826,6 +846,18 @@ inline CastClass_match<OpTy, Instruction::SIToFP> m_SIToFP(const OpTy &Op) { return CastClass_match<OpTy, Instruction::SIToFP>(Op); } +/// \brief Matches FPTrunc +template <typename OpTy> +inline CastClass_match<OpTy, Instruction::FPTrunc> m_FPTrunc(const OpTy &Op) { + return CastClass_match<OpTy, Instruction::FPTrunc>(Op); +} + +/// \brief Matches FPExt +template <typename OpTy> +inline CastClass_match<OpTy, Instruction::FPExt> m_FPExt(const OpTy &Op) { + return CastClass_match<OpTy, Instruction::FPExt>(Op); +} + //===----------------------------------------------------------------------===// // Matchers for unary operators // @@ -1316,6 +1348,14 @@ template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) { // Matchers for two-operands operators with the operators in either order // +/// \brief Matches a BinaryOperator with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<AnyBinaryOp_match<LHS, RHS>, + AnyBinaryOp_match<RHS, LHS>> +m_c_BinOp(const LHS &L, const RHS &R) { + return m_CombineOr(m_BinOp(L, R), m_BinOp(R, L)); +} + /// \brief Matches an ICmp with a predicate over LHS and RHS in either order. /// Does not swap the predicate. template<typename LHS, typename RHS> @@ -1325,6 +1365,22 @@ m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) { return m_CombineOr(m_ICmp(Pred, L, R), m_ICmp(Pred, R, L)); } +/// \brief Matches a Add with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Add>, + BinaryOp_match<RHS, LHS, Instruction::Add>> +m_c_Add(const LHS &L, const RHS &R) { + return m_CombineOr(m_Add(L, R), m_Add(R, L)); +} + +/// \brief Matches a Mul with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Mul>, + BinaryOp_match<RHS, LHS, Instruction::Mul>> +m_c_Mul(const LHS &L, const RHS &R) { + return m_CombineOr(m_Mul(L, R), m_Mul(R, L)); +} + /// \brief Matches an And with LHS and RHS in either order. template<typename LHS, typename RHS> inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::And>, diff --git a/include/llvm/IR/PredIteratorCache.h b/include/llvm/IR/PredIteratorCache.h index 118310aed1d0..81f535311431 100644 --- a/include/llvm/IR/PredIteratorCache.h +++ b/include/llvm/IR/PredIteratorCache.h @@ -27,8 +27,8 @@ namespace llvm { /// wants the predecessor list for the same blocks. class PredIteratorCache { /// BlockToPredsMap - Pointer to null-terminated list. - DenseMap<BasicBlock *, BasicBlock **> BlockToPredsMap; - DenseMap<BasicBlock *, unsigned> BlockToPredCountMap; + mutable DenseMap<BasicBlock *, BasicBlock **> BlockToPredsMap; + mutable DenseMap<BasicBlock *, unsigned> BlockToPredCountMap; /// Memory - This is the space that holds cached preds. BumpPtrAllocator Memory; @@ -55,13 +55,15 @@ private: return Entry; } - unsigned GetNumPreds(BasicBlock *BB) { - GetPreds(BB); - return BlockToPredCountMap[BB]; + unsigned GetNumPreds(BasicBlock *BB) const { + auto Result = BlockToPredCountMap.find(BB); + if (Result != BlockToPredCountMap.end()) + return Result->second; + return BlockToPredCountMap[BB] = std::distance(pred_begin(BB), pred_end(BB)); } public: - size_t size(BasicBlock *BB) { return GetNumPreds(BB); } + size_t size(BasicBlock *BB) const { return GetNumPreds(BB); } ArrayRef<BasicBlock *> get(BasicBlock *BB) { return makeArrayRef(GetPreds(BB), GetNumPreds(BB)); } diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h index 916faa4b327e..03151cd7c8f7 100644 --- a/include/llvm/IR/Statepoint.h +++ b/include/llvm/IR/Statepoint.h @@ -454,7 +454,7 @@ struct StatepointDirectives { /// Parse out statepoint directives from the function attributes present in \p /// AS. -StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeSet AS); +StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeList AS); /// Return \c true if the the \p Attr is an attribute that is a statepoint /// directive. diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index 5c6d58affd7a..49a5fb21297d 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -1,4 +1,4 @@ -//===-- llvm/SymbolTableListTraits.h - Traits for iplist --------*- C++ -*-===// +//===- llvm/SymbolTableListTraits.h - Traits for iplist ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -26,23 +26,27 @@ #define LLVM_IR_SYMBOLTABLELISTTRAITS_H #include "llvm/ADT/ilist.h" +#include "llvm/ADT/simple_ilist.h" +#include <cstddef> namespace llvm { -class ValueSymbolTable; -/// Template metafunction to get the parent type for a symbol table list. -/// -/// Implementations create a typedef called \c type so that we only need a -/// single template parameter for the list and traits. -template <typename NodeTy> struct SymbolTableListParentType {}; class Argument; class BasicBlock; class Function; -class Instruction; -class GlobalVariable; class GlobalAlias; class GlobalIFunc; +class GlobalVariable; +class Instruction; class Module; +class ValueSymbolTable; + +/// Template metafunction to get the parent type for a symbol table list. +/// +/// Implementations create a typedef called \c type so that we only need a +/// single template parameter for the list and traits. +template <typename NodeTy> struct SymbolTableListParentType {}; + #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \ template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; }; DEFINE_SYMBOL_TABLE_PARENT_TYPE(Instruction, BasicBlock) @@ -67,7 +71,7 @@ class SymbolTableListTraits : public ilist_alloc_traits<ValueSubClass> { typename SymbolTableListParentType<ValueSubClass>::type ItemParentClass; public: - SymbolTableListTraits() {} + SymbolTableListTraits() = default; private: /// getListOwner - Return the object that owns this list. If this is a list @@ -109,6 +113,6 @@ template <class T> class SymbolTableList : public iplist_impl<simple_ilist<T>, SymbolTableListTraits<T>> {}; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_SYMBOLTABLELISTTRAITS_H diff --git a/include/llvm/IR/TrackingMDRef.h b/include/llvm/IR/TrackingMDRef.h index fe513a8f9795..12b196432006 100644 --- a/include/llvm/IR/TrackingMDRef.h +++ b/include/llvm/IR/TrackingMDRef.h @@ -15,6 +15,8 @@ #define LLVM_IR_TRACKINGMDREF_H #include "llvm/IR/Metadata.h" +#include <algorithm> +#include <cassert> namespace llvm { @@ -22,14 +24,15 @@ namespace llvm { /// /// This class behaves like \a TrackingVH, but for metadata. class TrackingMDRef { - Metadata *MD; + Metadata *MD = nullptr; public: - TrackingMDRef() : MD(nullptr) {} + TrackingMDRef() = default; explicit TrackingMDRef(Metadata *MD) : MD(MD) { track(); } TrackingMDRef(TrackingMDRef &&X) : MD(X.MD) { retrack(X); } TrackingMDRef(const TrackingMDRef &X) : MD(X.MD) { track(); } + TrackingMDRef &operator=(TrackingMDRef &&X) { if (&X == this) return *this; @@ -39,6 +42,7 @@ public: retrack(X); return *this; } + TrackingMDRef &operator=(const TrackingMDRef &X) { if (&X == this) return *this; @@ -48,6 +52,7 @@ public: track(); return *this; } + ~TrackingMDRef() { untrack(); } Metadata *get() const { return MD; } @@ -80,10 +85,12 @@ private: if (MD) MetadataTracking::track(MD); } + void untrack() { if (MD) MetadataTracking::untrack(MD); } + void retrack(TrackingMDRef &X) { assert(MD == X.MD && "Expected values to match"); if (X.MD) { @@ -101,15 +108,17 @@ template <class T> class TypedTrackingMDRef { TrackingMDRef Ref; public: - TypedTrackingMDRef() {} + TypedTrackingMDRef() = default; explicit TypedTrackingMDRef(T *MD) : Ref(static_cast<Metadata *>(MD)) {} TypedTrackingMDRef(TypedTrackingMDRef &&X) : Ref(std::move(X.Ref)) {} TypedTrackingMDRef(const TypedTrackingMDRef &X) : Ref(X.Ref) {} + TypedTrackingMDRef &operator=(TypedTrackingMDRef &&X) { Ref = std::move(X.Ref); return *this; } + TypedTrackingMDRef &operator=(const TypedTrackingMDRef &X) { Ref = X.Ref; return *this; @@ -162,4 +171,4 @@ template <class T> struct simplify_type<const TypedTrackingMDRef<T>> { } // end namespace llvm -#endif +#endif // LLVM_IR_TRACKINGMDREF_H diff --git a/include/llvm/IR/Type.h b/include/llvm/IR/Type.h index 778ee06169f1..e6a0df937e9b 100644 --- a/include/llvm/IR/Type.h +++ b/include/llvm/IR/Type.h @@ -290,7 +290,11 @@ public: /// If this is a vector type, return the element type, otherwise return /// 'this'. - Type *getScalarType() const LLVM_READONLY; + Type *getScalarType() const { + if (isVectorTy()) + return getVectorElementType(); + return const_cast<Type*>(this); + } //===--------------------------------------------------------------------===// // Type Iteration support. @@ -423,7 +427,7 @@ private: }; // Printing of types. -static inline raw_ostream &operator<<(raw_ostream &OS, Type &T) { +static inline raw_ostream &operator<<(raw_ostream &OS, const Type &T) { T.print(OS); return OS; } diff --git a/include/llvm/IR/TypeFinder.h b/include/llvm/IR/TypeFinder.h index 046f85caec9d..48c4f1161aa1 100644 --- a/include/llvm/IR/TypeFinder.h +++ b/include/llvm/IR/TypeFinder.h @@ -1,4 +1,4 @@ -//===-- llvm/IR/TypeFinder.h - Class to find used struct types --*- C++ -*-===// +//===- llvm/IR/TypeFinder.h - Class to find used struct types ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,8 +15,7 @@ #define LLVM_IR_TYPEFINDER_H #include "llvm/ADT/DenseSet.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/Type.h" +#include <cstddef> #include <vector> namespace llvm { @@ -24,6 +23,7 @@ namespace llvm { class MDNode; class Module; class StructType; +class Type; class Value; /// TypeFinder - Walk over a module, identifying all of the types that are @@ -36,10 +36,10 @@ class TypeFinder { DenseSet<Type*> VisitedTypes; std::vector<StructType*> StructTypes; - bool OnlyNamed; + bool OnlyNamed = false; public: - TypeFinder() : OnlyNamed(false) {} + TypeFinder() = default; void run(const Module &M, bool onlyNamed); void clear(); @@ -77,6 +77,6 @@ private: void incorporateMDNode(const MDNode *V); }; -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_TYPEFINDER_H diff --git a/include/llvm/IR/Use.h b/include/llvm/IR/Use.h index ff6b2e1f1e22..05b68ccbb38e 100644 --- a/include/llvm/IR/Use.h +++ b/include/llvm/IR/Use.h @@ -85,7 +85,7 @@ public: /// /// For an instruction operand, for example, this will return the /// instruction. - User *getUser() const; + User *getUser() const LLVM_READONLY; inline void set(Value *Val); @@ -111,7 +111,7 @@ public: static void zap(Use *Start, const Use *Stop, bool del = false); private: - const Use *getImpliedUser() const; + const Use *getImpliedUser() const LLVM_READONLY; Value *Val; Use *Next; diff --git a/include/llvm/IR/UseListOrder.h b/include/llvm/IR/UseListOrder.h index efff208295b6..ebe99223facd 100644 --- a/include/llvm/IR/UseListOrder.h +++ b/include/llvm/IR/UseListOrder.h @@ -20,20 +20,19 @@ namespace llvm { -class Module; class Function; class Value; /// \brief Structure to hold a use-list order. struct UseListOrder { - const Value *V; - const Function *F; + const Value *V = nullptr; + const Function *F = nullptr; std::vector<unsigned> Shuffle; UseListOrder(const Value *V, const Function *F, size_t ShuffleSize) : V(V), F(F), Shuffle(ShuffleSize) {} - UseListOrder() : V(nullptr), F(nullptr) {} + UseListOrder() = default; UseListOrder(UseListOrder &&) = default; UseListOrder &operator=(UseListOrder &&) = default; }; diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index c907d6b670b5..54758a9b6d6a 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -122,8 +122,16 @@ protected: } private: + const Use *getHungOffOperands() const { + return *(reinterpret_cast<const Use *const *>(this) - 1); + } + Use *&getHungOffOperands() { return *(reinterpret_cast<Use **>(this) - 1); } + const Use *getIntrusiveOperands() const { + return reinterpret_cast<const Use *>(this) - NumUserOperands; + } + Use *getIntrusiveOperands() { return reinterpret_cast<Use *>(this) - NumUserOperands; } @@ -135,11 +143,11 @@ private: } public: - Use *getOperandList() { + const Use *getOperandList() const { return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands(); } - const Use *getOperandList() const { - return const_cast<User *>(this)->getOperandList(); + Use *getOperandList() { + return const_cast<Use *>(static_cast<const User *>(this)->getOperandList()); } Value *getOperand(unsigned i) const { diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index bdafbbf58cc4..a4b48d7f3539 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -294,7 +294,15 @@ public: // when using them since you might not get all uses. // The methods that don't start with materialized_ assert that modules is // fully materialized. - void assertModuleIsMaterialized() const; + void assertModuleIsMaterializedImpl() const; + // This indirection exists so we can keep assertModuleIsMaterializedImpl() + // around in release builds of Value.cpp to be linked with other code built + // in debug mode. But this avoids calling it in any of the release built code. + void assertModuleIsMaterialized() const { +#ifndef NDEBUG + assertModuleIsMaterializedImpl(); +#endif + } bool use_empty() const { assertModuleIsMaterialized(); @@ -468,27 +476,30 @@ public: /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCasts(); - const Value *stripPointerCasts() const { - return const_cast<Value*>(this)->stripPointerCasts(); + const Value *stripPointerCasts() const; + Value *stripPointerCasts() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripPointerCasts()); } /// \brief Strip off pointer casts and all-zero GEPs. /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCastsNoFollowAliases(); - const Value *stripPointerCastsNoFollowAliases() const { - return const_cast<Value*>(this)->stripPointerCastsNoFollowAliases(); + const Value *stripPointerCastsNoFollowAliases() const; + Value *stripPointerCastsNoFollowAliases() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripPointerCastsNoFollowAliases()); } /// \brief Strip off pointer casts and all-constant inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsConstantOffsets(); - const Value *stripInBoundsConstantOffsets() const { - return const_cast<Value*>(this)->stripInBoundsConstantOffsets(); + const Value *stripInBoundsConstantOffsets() const; + Value *stripInBoundsConstantOffsets() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripInBoundsConstantOffsets()); } /// \brief Accumulate offsets from \a stripInBoundsConstantOffsets(). @@ -498,21 +509,22 @@ public: /// correct bitwidth for an offset of this pointer type. /// /// If this is called on a non-pointer value, it returns 'this'. - Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset); const Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset) const { - return const_cast<Value *>(this) - ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + APInt &Offset) const; + Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, + APInt &Offset) { + return const_cast<Value *>(static_cast<const Value *>(this) + ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); } /// \brief Strip off pointer casts and inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsOffsets(); - const Value *stripInBoundsOffsets() const { - return const_cast<Value*>(this)->stripInBoundsOffsets(); + const Value *stripInBoundsOffsets() const; + Value *stripInBoundsOffsets() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripInBoundsOffsets()); } /// \brief Returns the number of bytes known to be dereferenceable for the @@ -535,11 +547,12 @@ public: /// the PHI node corresponding to PredBB. If not, return ourself. This is /// useful if you want to know the value something has in a predecessor /// block. - Value *DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB); - const Value *DoPHITranslation(const BasicBlock *CurBB, - const BasicBlock *PredBB) const{ - return const_cast<Value*>(this)->DoPHITranslation(CurBB, PredBB); + const BasicBlock *PredBB) const; + + Value *DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB) { + return const_cast<Value *>( + static_cast<const Value *>(this)->DoPHITranslation(CurBB, PredBB)); } /// \brief The maximum alignment for instructions. diff --git a/include/llvm/IR/ValueHandle.h b/include/llvm/IR/ValueHandle.h index a4d4893a9bc9..4838bac9e0f7 100644 --- a/include/llvm/IR/ValueHandle.h +++ b/include/llvm/IR/ValueHandle.h @@ -98,6 +98,15 @@ protected: V != DenseMapInfo<Value *>::getTombstoneKey(); } + /// \brief Remove this ValueHandle from its current use list. + void RemoveFromUseList(); + + /// \brief Clear the underlying pointer without clearing the use list. + /// + /// This should only be used if a derived class has manually removed the + /// handle from the use list. + void clearValPtr() { V = nullptr; } + public: // Callbacks made from Value. static void ValueIsDeleted(Value *V); @@ -120,8 +129,6 @@ private: /// \brief Add this ValueHandle to the use list for V. void AddToUseList(); - /// \brief Remove this ValueHandle from its current use list. - void RemoveFromUseList(); }; /// \brief Value handle that is nullable, but tries to track the Value. @@ -259,7 +266,6 @@ struct isPodLike<AssertingVH<T> > { #endif }; - /// \brief Value handle that tracks a Value across RAUW. /// /// TrackingVH is designed for situations where a client needs to hold a handle @@ -370,6 +376,130 @@ public: virtual void allUsesReplacedWith(Value *) {} }; +/// Value handle that poisons itself if the Value is deleted. +/// +/// This is a Value Handle that points to a value and poisons itself if the +/// value is destroyed while the handle is still live. This is very useful for +/// catching dangling pointer bugs where an \c AssertingVH cannot be used +/// because the dangling handle needs to outlive the value without ever being +/// used. +/// +/// One particularly useful place to use this is as the Key of a map. Dangling +/// pointer bugs often lead to really subtle bugs that only occur if another +/// object happens to get allocated to the same address as the old one. Using +/// a PoisoningVH ensures that an assert is triggered if looking up a new value +/// in the map finds a handle from the old value. +/// +/// Note that a PoisoningVH handle does *not* follow values across RAUW +/// operations. This means that RAUW's need to explicitly update the +/// PoisoningVH's as it moves. This is required because in non-assert mode this +/// class turns into a trivial wrapper around a pointer. +template <typename ValueTy> +class PoisoningVH +#ifndef NDEBUG + final : public CallbackVH +#endif +{ + friend struct DenseMapInfo<PoisoningVH<ValueTy>>; + + // Convert a ValueTy*, which may be const, to the raw Value*. + static Value *GetAsValue(Value *V) { return V; } + static Value *GetAsValue(const Value *V) { return const_cast<Value *>(V); } + +#ifndef NDEBUG + /// A flag tracking whether this value has been poisoned. + /// + /// On delete and RAUW, we leave the value pointer alone so that as a raw + /// pointer it produces the same value (and we fit into the same key of + /// a hash table, etc), but we poison the handle so that any top-level usage + /// will fail. + bool Poisoned = false; + + Value *getRawValPtr() const { return ValueHandleBase::getValPtr(); } + void setRawValPtr(Value *P) { ValueHandleBase::operator=(P); } + + /// Handle deletion by poisoning the handle. + void deleted() override { + assert(!Poisoned && "Tried to delete an already poisoned handle!"); + Poisoned = true; + RemoveFromUseList(); + } + + /// Handle RAUW by poisoning the handle. + void allUsesReplacedWith(Value *) override { + assert(!Poisoned && "Tried to RAUW an already poisoned handle!"); + Poisoned = true; + RemoveFromUseList(); + } +#else // NDEBUG + Value *ThePtr = nullptr; + + Value *getRawValPtr() const { return ThePtr; } + void setRawValPtr(Value *P) { ThePtr = P; } +#endif + + ValueTy *getValPtr() const { + assert(!Poisoned && "Accessed a poisoned value handle!"); + return static_cast<ValueTy *>(getRawValPtr()); + } + void setValPtr(ValueTy *P) { setRawValPtr(GetAsValue(P)); } + +public: + PoisoningVH() = default; +#ifndef NDEBUG + PoisoningVH(ValueTy *P) : CallbackVH(GetAsValue(P)) {} + PoisoningVH(const PoisoningVH &RHS) + : CallbackVH(RHS), Poisoned(RHS.Poisoned) {} + ~PoisoningVH() { + if (Poisoned) + clearValPtr(); + } + PoisoningVH &operator=(const PoisoningVH &RHS) { + if (Poisoned) + clearValPtr(); + CallbackVH::operator=(RHS); + Poisoned = RHS.Poisoned; + return *this; + } +#else + PoisoningVH(ValueTy *P) : ThePtr(GetAsValue(P)) {} +#endif + + operator ValueTy *() const { return getValPtr(); } + + ValueTy *operator->() const { return getValPtr(); } + ValueTy &operator*() const { return *getValPtr(); } +}; + +// Specialize DenseMapInfo to allow PoisoningVH to participate in DenseMap. +template <typename T> struct DenseMapInfo<PoisoningVH<T>> { + static inline PoisoningVH<T> getEmptyKey() { + PoisoningVH<T> Res; + Res.setRawValPtr(DenseMapInfo<Value *>::getEmptyKey()); + return Res; + } + static inline PoisoningVH<T> getTombstoneKey() { + PoisoningVH<T> Res; + Res.setRawValPtr(DenseMapInfo<Value *>::getTombstoneKey()); + return Res; + } + static unsigned getHashValue(const PoisoningVH<T> &Val) { + return DenseMapInfo<Value *>::getHashValue(Val.getRawValPtr()); + } + static bool isEqual(const PoisoningVH<T> &LHS, const PoisoningVH<T> &RHS) { + return DenseMapInfo<Value *>::isEqual(LHS.getRawValPtr(), + RHS.getRawValPtr()); + } +}; + +template <typename T> struct isPodLike<PoisoningVH<T>> { +#ifdef NDEBUG + static const bool value = true; +#else + static const bool value = false; +#endif +}; + } // End llvm namespace #endif diff --git a/include/llvm/IR/ValueSymbolTable.h b/include/llvm/IR/ValueSymbolTable.h index 61a12db403ea..9e86751dae6f 100644 --- a/include/llvm/IR/ValueSymbolTable.h +++ b/include/llvm/IR/ValueSymbolTable.h @@ -1,4 +1,4 @@ -//===-- llvm/ValueSymbolTable.h - Implement a Value Symtab ------*- C++ -*-===// +//===- llvm/ValueSymbolTable.h - Implement a Value Symtab -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,31 +15,36 @@ #define LLVM_IR_VALUESYMBOLTABLE_H #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Value.h" -#include "llvm/Support/DataTypes.h" +#include <cstdint> namespace llvm { - template <typename ValueSubClass> class SymbolTableListTraits; - template <unsigned InternalLen> class SmallString; - class BasicBlock; - class Function; - class NamedMDNode; - class Module; - class StringRef; + +class Argument; +class BasicBlock; +class Function; +class GlobalAlias; +class GlobalIFunc; +class GlobalVariable; +class Instruction; +template <unsigned InternalLen> class SmallString; +template <typename ValueSubClass> class SymbolTableListTraits; /// This class provides a symbol table of name/value pairs. It is essentially /// a std::map<std::string,Value*> but has a controlled interface provided by /// LLVM as well as ensuring uniqueness of names. /// class ValueSymbolTable { - friend class Value; friend class SymbolTableListTraits<Argument>; friend class SymbolTableListTraits<BasicBlock>; - friend class SymbolTableListTraits<Instruction>; friend class SymbolTableListTraits<Function>; - friend class SymbolTableListTraits<GlobalVariable>; friend class SymbolTableListTraits<GlobalAlias>; friend class SymbolTableListTraits<GlobalIFunc>; + friend class SymbolTableListTraits<GlobalVariable>; + friend class SymbolTableListTraits<Instruction>; + friend class Value; + /// @name Types /// @{ public: @@ -55,14 +60,14 @@ public: /// @} /// @name Constructors /// @{ -public: - ValueSymbolTable() : vmap(0), LastUnique(0) {} + + ValueSymbolTable() : vmap(0) {} ~ValueSymbolTable(); /// @} /// @name Accessors /// @{ -public: + /// This method finds the value with the given \p Name in the /// the symbol table. /// @returns the value associated with the \p Name @@ -84,7 +89,7 @@ public: /// @} /// @name Iteration /// @{ -public: + /// @brief Get an iterator that from the beginning of the symbol table. inline iterator begin() { return vmap.begin(); } @@ -122,13 +127,13 @@ private: /// @} /// @name Internal Data /// @{ -private: + ValueMap vmap; ///< The map that holds the symbol table. - mutable uint32_t LastUnique; ///< Counter for tracking unique names + mutable uint32_t LastUnique = 0; ///< Counter for tracking unique names /// @} }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_VALUESYMBOLTABLE_H |