diff options
Diffstat (limited to 'include/llvm')
689 files changed, 39142 insertions, 14833 deletions
diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 3fe04060fd59..3f6bd00a779c 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -25,6 +25,8 @@ struct fltSemantics; class APSInt; class StringRef; +template <typename T> class SmallVectorImpl; + /// Enum that represents what fraction of the LSB truncated bits of an fp number /// represent. /// @@ -511,19 +513,12 @@ public: /// 0 -> \c IEK_Zero /// Inf -> \c IEK_Inf /// - friend int ilogb(const APFloat &Arg) { - if (Arg.isNaN()) - return IEK_NaN; - if (Arg.isZero()) - return IEK_Zero; - if (Arg.isInfinity()) - return IEK_Inf; - - return Arg.exponent; - } + friend int ilogb(const APFloat &Arg); /// \brief Returns: X * 2^Exp for integral exponents. - friend APFloat scalbn(APFloat X, int Exp); + friend APFloat scalbn(APFloat X, int Exp, roundingMode); + + friend APFloat frexp(const APFloat &X, int &Exp, roundingMode); private: @@ -579,6 +574,7 @@ private: const APInt *fill); void makeInf(bool Neg = false); void makeZero(bool Neg = false); + void makeQuiet(); /// @} @@ -651,7 +647,14 @@ private: /// These additional declarations are required in order to compile LLVM with IBM /// xlC compiler. hash_code hash_value(const APFloat &Arg); -APFloat scalbn(APFloat X, int Exp); +int ilogb(const APFloat &Arg); +APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode); + +/// \brief Equivalent of C standard library function. +/// +/// While the C standard says Exp is an unspecified value for infinity and nan, +/// this returns INT_MAX for infinities, and INT_MIN for NaNs. +APFloat frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM); /// \brief Returns the absolute value of the argument. inline APFloat abs(APFloat X) { diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index e2a0cb5e69dc..d77d1c7ca93f 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -16,7 +16,6 @@ #ifndef LLVM_ADT_APINT_H #define LLVM_ADT_APINT_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include <cassert> @@ -31,6 +30,7 @@ class hash_code; class raw_ostream; template <typename T> class SmallVectorImpl; +template <typename T> class ArrayRef; // An unsigned host type used as a single part of a multi-part // bignum. @@ -177,11 +177,11 @@ class APInt { /// provides a more convenient form of divide for internal use since KnuthDiv /// has specific constraints on its inputs. If those constraints are not met /// then it provides a simpler form of divide. - static void divide(const APInt LHS, unsigned lhsWords, const APInt &RHS, + static void divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, unsigned rhsWords, APInt *Quotient, APInt *Remainder); /// out-of-line slow case for inline constructor - void initSlowCase(unsigned numBits, uint64_t val, bool isSigned); + void initSlowCase(uint64_t val, bool isSigned); /// shared code between two array constructors void initFromArray(ArrayRef<uint64_t> array); @@ -239,7 +239,7 @@ public: if (isSingleWord()) VAL = val; else - initSlowCase(numBits, val, isSigned); + initSlowCase(val, isSigned); clearUnusedBits(); } @@ -625,7 +625,12 @@ public: /// Negates *this using two's complement logic. /// /// \returns An APInt value representing the negation of *this. - APInt operator-() const { return APInt(BitWidth, 0) - (*this); } + APInt operator-() const { + APInt Result(*this); + Result.flipAllBits(); + ++Result; + return Result; + } /// \brief Logical negation operator. /// @@ -835,13 +840,13 @@ public: /// /// Adds RHS to this APInt and returns the result. APInt operator+(const APInt &RHS) const; - APInt operator+(uint64_t RHS) const { return (*this) + APInt(BitWidth, RHS); } + APInt operator+(uint64_t RHS) const; /// \brief Subtraction operator. /// /// Subtracts RHS from this APInt and returns the result. APInt operator-(const APInt &RHS) const; - APInt operator-(uint64_t RHS) const { return (*this) - APInt(BitWidth, RHS); } + APInt operator-(uint64_t RHS) const; /// \brief Left logical shift operator. /// @@ -1451,6 +1456,10 @@ public: /// \returns a byte-swapped representation of this APInt Value. APInt LLVM_ATTRIBUTE_UNUSED_RESULT byteSwap() const; + /// \returns the value with the bit representation reversed of this APInt + /// Value. + APInt LLVM_ATTRIBUTE_UNUSED_RESULT reverseBits() const; + /// \brief Converts this APInt to a double value. double roundToDouble(bool isSigned) const; @@ -1744,16 +1753,24 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) { namespace APIntOps { /// \brief Determine the smaller of two APInts considered to be signed. -inline APInt smin(const APInt &A, const APInt &B) { return A.slt(B) ? A : B; } +inline const APInt &smin(const APInt &A, const APInt &B) { + return A.slt(B) ? A : B; +} /// \brief Determine the larger of two APInts considered to be signed. -inline APInt smax(const APInt &A, const APInt &B) { return A.sgt(B) ? A : B; } +inline const APInt &smax(const APInt &A, const APInt &B) { + return A.sgt(B) ? A : B; +} /// \brief Determine the smaller of two APInts considered to be signed. -inline APInt umin(const APInt &A, const APInt &B) { return A.ult(B) ? A : B; } +inline const APInt &umin(const APInt &A, const APInt &B) { + return A.ult(B) ? A : B; +} /// \brief Determine the larger of two APInts considered to be unsigned. -inline APInt umax(const APInt &A, const APInt &B) { return A.ugt(B) ? A : B; } +inline const APInt &umax(const APInt &A, const APInt &B) { + return A.ugt(B) ? A : B; +} /// \brief Check if the specified APInt has a N-bits unsigned integer value. inline bool isIntN(unsigned N, const APInt &APIVal) { return APIVal.isIntN(N); } @@ -1770,6 +1787,13 @@ inline bool isMask(unsigned numBits, const APInt &APIVal) { APIVal == APInt::getLowBitsSet(APIVal.getBitWidth(), numBits); } +/// \returns true if the argument is a non-empty sequence of ones starting at +/// the least significant bit with the remainder zero (32 bit version). +/// Ex. isMask(0x0000FFFFU) == true. +inline bool isMask(const APInt &Value) { + return (Value != 0) && ((Value + 1) & Value) == 0; +} + /// \brief Return true if the argument APInt value contains a sequence of ones /// with the remainder zero. inline bool isShiftedMask(unsigned numBits, const APInt &APIVal) { diff --git a/include/llvm/ADT/ArrayRef.h b/include/llvm/ADT/ArrayRef.h index 517ba39849e1..95a1e62ef005 100644 --- a/include/llvm/ADT/ArrayRef.h +++ b/include/llvm/ADT/ArrayRef.h @@ -16,7 +16,6 @@ #include <vector> namespace llvm { - /// ArrayRef - Represent a constant reference to an array (0 or more elements /// consecutively in memory), i.e. a start pointer and a length. It allows /// various APIs to take consecutive elements easily and conveniently. @@ -92,19 +91,20 @@ namespace llvm { /// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to /// ensure that only ArrayRefs of pointers can be converted. template <typename U> - ArrayRef(const ArrayRef<U *> &A, - typename std::enable_if< - std::is_convertible<U *const *, T const *>::value>::type* = 0) + ArrayRef( + const ArrayRef<U *> &A, + typename std::enable_if< + std::is_convertible<U *const *, T const *>::value>::type * = nullptr) : Data(A.data()), Length(A.size()) {} /// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is /// templated in order to avoid instantiating SmallVectorTemplateCommon<T> /// whenever we copy-construct an ArrayRef. template<typename U, typename DummyT> - /*implicit*/ ArrayRef(const SmallVectorTemplateCommon<U*, DummyT> &Vec, - typename std::enable_if< - std::is_convertible<U *const *, - T const *>::value>::type* = 0) + /*implicit*/ ArrayRef( + const SmallVectorTemplateCommon<U *, DummyT> &Vec, + typename std::enable_if< + std::is_convertible<U *const *, T const *>::value>::type * = nullptr) : Data(Vec.data()), Length(Vec.size()) { } @@ -161,20 +161,26 @@ namespace llvm { } /// slice(n) - Chop off the first N elements of the array. - ArrayRef<T> slice(unsigned N) const { + ArrayRef<T> slice(size_t N) const { assert(N <= size() && "Invalid specifier"); return ArrayRef<T>(data()+N, size()-N); } /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. - ArrayRef<T> slice(unsigned N, unsigned M) const { + ArrayRef<T> slice(size_t N, size_t M) const { assert(N+M <= size() && "Invalid specifier"); return ArrayRef<T>(data()+N, M); } - // \brief Drop the last \p N elements of the array. - ArrayRef<T> drop_back(unsigned N = 1) const { + /// \brief Drop the first \p N elements of the array. + ArrayRef<T> drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(N, size() - N); + } + + /// \brief Drop the last \p N elements of the array. + ArrayRef<T> drop_back(size_t N = 1) const { assert(size() >= N && "Dropping more elements than exist"); return slice(0, size() - N); } @@ -273,19 +279,25 @@ namespace llvm { } /// slice(n) - Chop off the first N elements of the array. - MutableArrayRef<T> slice(unsigned N) const { + MutableArrayRef<T> slice(size_t N) const { assert(N <= this->size() && "Invalid specifier"); return MutableArrayRef<T>(data()+N, this->size()-N); } /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. - MutableArrayRef<T> slice(unsigned N, unsigned M) const { + MutableArrayRef<T> slice(size_t N, size_t M) const { assert(N+M <= this->size() && "Invalid specifier"); return MutableArrayRef<T>(data()+N, M); } - MutableArrayRef<T> drop_back(unsigned N) const { + /// \brief Drop the first \p N elements of the array. + MutableArrayRef<T> drop_front(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(N, this->size() - N); + } + + MutableArrayRef<T> drop_back(size_t N = 1) const { assert(this->size() >= N && "Dropping more elements than exist"); return slice(0, this->size() - N); } @@ -379,6 +391,6 @@ namespace llvm { template <typename T> hash_code hash_value(ArrayRef<T> S) { return hash_combine_range(S.begin(), S.end()); } -} +} // end namespace llvm -#endif +#endif // LLVM_ADT_ARRAYREF_H diff --git a/include/llvm/ADT/BitVector.h b/include/llvm/ADT/BitVector.h index ad00d51f99e9..661437126d48 100644 --- a/include/llvm/ADT/BitVector.h +++ b/include/llvm/ADT/BitVector.h @@ -14,13 +14,13 @@ #ifndef LLVM_ADT_BITVECTOR_H #define LLVM_ADT_BITVECTOR_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <algorithm> #include <cassert> #include <climits> +#include <cstdint> #include <cstdlib> +#include <cstring> namespace llvm { @@ -69,7 +69,7 @@ public: } operator bool() const { - return ((*WordRef) & (BitWord(1) << BitPos)) ? true : false; + return ((*WordRef) & (BitWord(1) << BitPos)) != 0; } }; @@ -105,6 +105,7 @@ public: BitVector(BitVector &&RHS) : Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) { RHS.Bits = nullptr; + RHS.Size = RHS.Capacity = 0; } ~BitVector() { @@ -244,7 +245,7 @@ public: BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE); Bits[I / BITWORD_SIZE] |= PrefixMask; - I = RoundUpToAlignment(I, BITWORD_SIZE); + I = alignTo(I, BITWORD_SIZE); for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE) Bits[I / BITWORD_SIZE] = ~0UL; @@ -283,7 +284,7 @@ public: BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE); Bits[I / BITWORD_SIZE] &= ~PrefixMask; - I = RoundUpToAlignment(I, BITWORD_SIZE); + I = alignTo(I, BITWORD_SIZE); for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE) Bits[I / BITWORD_SIZE] = 0UL; @@ -454,6 +455,7 @@ public: Capacity = RHS.Capacity; RHS.Bits = nullptr; + RHS.Size = RHS.Capacity = 0; return *this; } @@ -576,7 +578,7 @@ static inline size_t capacity_in_bytes(const BitVector &X) { return X.getMemorySize(); } -} // End llvm namespace +} // end namespace llvm namespace std { /// Implement std::swap in terms of BitVector swap. @@ -584,6 +586,6 @@ namespace std { swap(llvm::BitVector &LHS, llvm::BitVector &RHS) { LHS.swap(RHS); } -} +} // end namespace std -#endif +#endif // LLVM_ADT_BITVECTOR_H diff --git a/include/llvm/ADT/BitmaskEnum.h b/include/llvm/ADT/BitmaskEnum.h new file mode 100644 index 000000000000..18c6ba5a3eb8 --- /dev/null +++ b/include/llvm/ADT/BitmaskEnum.h @@ -0,0 +1,153 @@ +//===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BITMASKENUM_H +#define LLVM_ADT_BITMASKENUM_H + +#include <cassert> +#include <type_traits> +#include <utility> + +#include "llvm/Support/MathExtras.h" + +/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can +/// perform bitwise operations on it without putting static_cast everywhere. +/// +/// \code +/// enum MyEnum { +/// E1 = 1, E2 = 2, E3 = 4, E4 = 8, +/// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4) +/// }; +/// +/// void Foo() { +/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast! +/// } +/// \endcode +/// +/// Normally when you do a bitwise operation on an enum value, you get back an +/// instance of the underlying type (e.g. int). But using this macro, bitwise +/// ops on your enum will return you back instances of the enum. This is +/// particularly useful for enums which represent a combination of flags. +/// +/// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual +/// value in your enum. +/// +/// All of the enum's values must be non-negative. +#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \ + LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue + +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used +/// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. +/// +/// Suppose you have an enum foo::bar::MyEnum. Before using +/// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or +/// namespace foo::bar. This allows the relevant operator overloads to be found +/// by ADL. +/// +/// You don't need to use this macro in namespace llvm; it's done at the bottom +/// of this file. +#define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ + using ::llvm::BitmaskEnumDetail::operator~; \ + using ::llvm::BitmaskEnumDetail::operator|; \ + using ::llvm::BitmaskEnumDetail::operator&; \ + using ::llvm::BitmaskEnumDetail::operator^; \ + using ::llvm::BitmaskEnumDetail::operator|=; \ + using ::llvm::BitmaskEnumDetail::operator&=; \ + /* Force a semicolon at the end of this macro. */ \ + using ::llvm::BitmaskEnumDetail::operator^= + +namespace llvm { + +/// Traits class to determine whether an enum has a +/// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. +template <typename E, typename Enable = void> +struct is_bitmask_enum : std::false_type {}; + +template <typename E> +struct is_bitmask_enum< + E, typename std::enable_if<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= + 0>::type> : std::true_type {}; +namespace BitmaskEnumDetail { + +/// Get a bitmask with 1s in all places up to the high-order bit of E's largest +/// value. +template <typename E> typename std::underlying_type<E>::type Mask() { + // On overflow, NextPowerOf2 returns zero with the type uint64_t, so + // subtracting 1 gives us the mask with all bits set, like we want. + return NextPowerOf2(static_cast<typename std::underlying_type<E>::type>( + E::LLVM_BITMASK_LARGEST_ENUMERATOR)) - + 1; +} + +/// Check that Val is in range for E, and return Val cast to E's underlying +/// type. +template <typename E> typename std::underlying_type<E>::type Underlying(E Val) { + auto U = static_cast<typename std::underlying_type<E>::type>(Val); + assert(U >= 0 && "Negative enum values are not allowed."); + assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)"); + return U; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator~(E Val) { + return static_cast<E>(~Underlying(Val) & Mask<E>()); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator|(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) | Underlying(RHS)); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator&(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) & Underlying(RHS)); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator^(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) ^ Underlying(RHS)); +} + +// |=, &=, and ^= return a reference to LHS, to match the behavior of the +// operators on builtin types. + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator|=(E &LHS, E RHS) { + LHS = LHS | RHS; + return LHS; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator&=(E &LHS, E RHS) { + LHS = LHS & RHS; + return LHS; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator^=(E &LHS, E RHS) { + LHS = LHS ^ RHS; + return LHS; +} + +} // namespace BitmaskEnumDetail + +// Enable bitmask enums in namespace ::llvm and all nested namespaces. +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +} // namespace llvm + +#endif diff --git a/include/llvm/ADT/DenseMap.h b/include/llvm/ADT/DenseMap.h index 6ee1960b5c82..917c086beba3 100644 --- a/include/llvm/ADT/DenseMap.h +++ b/include/llvm/ADT/DenseMap.h @@ -81,11 +81,13 @@ public: } unsigned size() const { return getNumEntries(); } - /// Grow the densemap so that it has at least Size buckets. Does not shrink - void resize(size_type Size) { + /// Grow the densemap so that it can contain at least \p NumEntries items + /// before resizing again. + void reserve(size_type NumEntries) { + auto NumBuckets = getMinBucketToReserveForEntries(NumEntries); incrementEpoch(); - if (Size > getNumBuckets()) - grow(Size); + if (NumBuckets > getNumBuckets()) + grow(NumBuckets); } void clear() { @@ -195,6 +197,26 @@ public: true); } + /// Alternate version of insert() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV, + const LookupKeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val, + TheBucket); + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + /// insert - Range insertion of pairs. template<typename InputIt> void insert(InputIt I, InputIt E) { @@ -285,6 +307,17 @@ protected: ::new (&B->getFirst()) KeyT(EmptyKey); } + /// Returns the number of buckets to allocate to ensure that the DenseMap can + /// accommodate \p NumEntries without need to grow(). + unsigned getMinBucketToReserveForEntries(unsigned NumEntries) { + // Ensure that "NumEntries * 4 < NumBuckets * 3" + if (NumEntries == 0) + return 0; + // +1 is required because of the strict equality. + // For example if NumEntries is 48, we need to return 401. + return NextPowerOf2(NumEntries * 4 / 3 + 1); + } + void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) { initEmpty(); @@ -399,7 +432,7 @@ private: BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value, BucketT *TheBucket) { - TheBucket = InsertIntoBucketImpl(Key, TheBucket); + TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket); TheBucket->getFirst() = Key; ::new (&TheBucket->getSecond()) ValueT(Value); @@ -408,7 +441,7 @@ private: BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value, BucketT *TheBucket) { - TheBucket = InsertIntoBucketImpl(Key, TheBucket); + TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket); TheBucket->getFirst() = Key; ::new (&TheBucket->getSecond()) ValueT(std::move(Value)); @@ -416,14 +449,26 @@ private: } BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) { - TheBucket = InsertIntoBucketImpl(Key, TheBucket); + TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket); TheBucket->getFirst() = std::move(Key); ::new (&TheBucket->getSecond()) ValueT(std::move(Value)); return TheBucket; } - BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) { + template <typename LookupKeyT> + BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup, + BucketT *TheBucket) { + TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket); + + TheBucket->getFirst() = std::move(Key); + ::new (&TheBucket->getSecond()) ValueT(std::move(Value)); + return TheBucket; + } + + template <typename LookupKeyT> + BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup, + BucketT *TheBucket) { incrementEpoch(); // If the load of the hash table is more than 3/4, or if fewer than 1/8 of @@ -439,12 +484,12 @@ private: unsigned NumBuckets = getNumBuckets(); if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) { this->grow(NumBuckets * 2); - LookupBucketFor(Key, TheBucket); + LookupBucketFor(Lookup, TheBucket); NumBuckets = getNumBuckets(); } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <= NumBuckets/8)) { this->grow(NumBuckets); - LookupBucketFor(Key, TheBucket); + LookupBucketFor(Lookup, TheBucket); } assert(TheBucket); @@ -550,9 +595,9 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>, unsigned NumBuckets; public: - explicit DenseMap(unsigned NumInitBuckets = 0) { - init(NumInitBuckets); - } + /// Create a DenseMap wth an optional \p InitialReserve that guarantee that + /// this number of elements can be inserted in the map without grow() + explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); } DenseMap(const DenseMap &other) : BaseT() { init(0); @@ -566,7 +611,7 @@ public: template<typename InputIt> DenseMap(const InputIt &I, const InputIt &E) { - init(NextPowerOf2(std::distance(I, E))); + init(std::distance(I, E)); this->insert(I, E); } @@ -609,7 +654,8 @@ public: } } - void init(unsigned InitBuckets) { + void init(unsigned InitNumEntries) { + auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries); if (allocateBuckets(InitBuckets)) { this->BaseT::initEmpty(); } else { diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index a844ebcccf5b..18c692e0cbcc 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -30,6 +30,36 @@ struct DenseMapInfo { //static bool isEqual(const T &LHS, const T &RHS); }; +template <typename T> struct CachedHash { + CachedHash(T Val) : Val(std::move(Val)) { + Hash = DenseMapInfo<T>::getHashValue(Val); + } + CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {} + T Val; + unsigned Hash; +}; + +// Provide DenseMapInfo for all CachedHash<T>. +template <typename T> struct DenseMapInfo<CachedHash<T>> { + static CachedHash<T> getEmptyKey() { + T N = DenseMapInfo<T>::getEmptyKey(); + return {N, 0}; + } + static CachedHash<T> getTombstoneKey() { + T N = DenseMapInfo<T>::getTombstoneKey(); + return {N, 0}; + } + static unsigned getHashValue(CachedHash<T> Val) { + assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!"); + assert(!isEqual(Val, getTombstoneKey()) && + "Cannot hash the tombstone key!"); + return Val.Hash; + } + static bool isEqual(CachedHash<T> A, CachedHash<T> B) { + return DenseMapInfo<T>::isEqual(A.Val, B.Val); + } +}; + // Provide DenseMapInfo for all pointers. template<typename T> struct DenseMapInfo<T*> { diff --git a/include/llvm/ADT/DenseSet.h b/include/llvm/ADT/DenseSet.h index ef09dce37980..3724a09623f3 100644 --- a/include/llvm/ADT/DenseSet.h +++ b/include/llvm/ADT/DenseSet.h @@ -94,6 +94,7 @@ public: ValueT *operator->() { return &I->getFirst(); } Iterator& operator++() { ++I; return *this; } + Iterator operator++(int) { auto T = *this; ++I; return T; } bool operator==(const Iterator& X) const { return I == X.I; } bool operator!=(const Iterator& X) const { return I != X.I; } }; @@ -115,6 +116,7 @@ public: const ValueT *operator->() { return &I->getFirst(); } ConstIterator& operator++() { ++I; return *this; } + ConstIterator operator++(int) { auto T = *this; ++I; return T; } bool operator==(const ConstIterator& X) const { return I == X.I; } bool operator!=(const ConstIterator& X) const { return I != X.I; } }; @@ -152,6 +154,19 @@ public: return TheMap.insert(std::make_pair(V, Empty)); } + /// Alternative version of insert that uses a different (and possibly less + /// expensive) key type. + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(const ValueT &V, + const LookupKeyT &LookupKey) { + return insert_as(ValueT(V), LookupKey); + } + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) { + detail::DenseSetEmpty Empty; + return TheMap.insert_as(std::make_pair(std::move(V), Empty), LookupKey); + } + // Range insertion of values. template<typename InputIt> void insert(InputIt I, InputIt E) { diff --git a/include/llvm/ADT/FoldingSet.h b/include/llvm/ADT/FoldingSet.h index c9205396591b..f16258af4ae2 100644 --- a/include/llvm/ADT/FoldingSet.h +++ b/include/llvm/ADT/FoldingSet.h @@ -17,10 +17,8 @@ #define LLVM_ADT_FOLDINGSET_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/DataTypes.h" namespace llvm { /// This folding set used for two purposes: @@ -98,6 +96,7 @@ namespace llvm { /// The result indicates whether the node existed in the folding set. class FoldingSetNodeID; +class StringRef; //===----------------------------------------------------------------------===// /// FoldingSetImpl - Implements the folding set functionality. The main @@ -181,11 +180,26 @@ public: /// empty - Returns true if there are no nodes in the folding set. bool empty() const { return NumNodes == 0; } + /// reserve - Increase the number of buckets such that adding the + /// EltCount-th node won't cause a rebucket operation. reserve is permitted + /// to allocate more space than requested by EltCount. + void reserve(unsigned EltCount); + /// capacity - Returns the number of nodes permitted in the folding set + /// before a rebucket operation is performed. + unsigned capacity() { + // We allow a load factor of up to 2.0, + // so that means our capacity is NumBuckets * 2 + return NumBuckets * 2; + } + private: /// GrowHashTable - Double the size of the hash table and rehash everything. - /// void GrowHashTable(); + /// GrowBucketCount - resize the hash table and rehash everything. + /// NewBucketCount must be a power of two, and must be greater than the old + /// bucket count. + void GrowBucketCount(unsigned NewBucketCount); protected: /// GetNodeProfile - Instantiations of the FoldingSet template implement /// this function to gather data bits for the given node. diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index de56f91eddb1..c3b574102f69 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -52,7 +52,6 @@ #include <algorithm> #include <cassert> #include <cstring> -#include <iterator> #include <string> #include <utility> @@ -632,7 +631,8 @@ inline hash_code hash_integer_value(uint64_t value) { template <typename T> typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type hash_value(T value) { - return ::llvm::hashing::detail::hash_integer_value(value); + return ::llvm::hashing::detail::hash_integer_value( + static_cast<uint64_t>(value)); } // Declared and documented above, but defined here so that any of the hashing diff --git a/include/llvm/ADT/PointerEmbeddedInt.h b/include/llvm/ADT/PointerEmbeddedInt.h index 8781d1803ac7..2279d43405fa 100644 --- a/include/llvm/ADT/PointerEmbeddedInt.h +++ b/include/llvm/ADT/PointerEmbeddedInt.h @@ -11,6 +11,7 @@ #define LLVM_ADT_POINTEREMBEDDEDINT_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include <climits> @@ -30,6 +31,8 @@ template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT> class PointerEmbeddedInt { uintptr_t Value; + // Note: This '<' is correct; using '<=' would result in some shifts + // overflowing their storage types. static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT, "Cannot embed more bits than we have in a pointer!"); @@ -42,25 +45,36 @@ class PointerEmbeddedInt { Mask = static_cast<uintptr_t>(-1) << Bits }; + struct RawValueTag { + explicit RawValueTag() = default; + }; + friend class PointerLikeTypeTraits<PointerEmbeddedInt>; - explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {} + explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {} public: PointerEmbeddedInt() : Value(0) {} - PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) { - assert((I & Mask) == 0 && "Integer has bits outside those preserved!"); + PointerEmbeddedInt(IntT I) { + *this = I; } PointerEmbeddedInt &operator=(IntT I) { - assert((I & Mask) == 0 && "Integer has bits outside those preserved!"); + assert((std::is_signed<IntT>::value ? llvm::isInt<Bits>(I) + : llvm::isUInt<Bits>(I)) && + "Integer has bits outside those preserved!"); Value = static_cast<uintptr_t>(I) << Shift; + return *this; } - // Note that this imilict conversion additionally allows all of the basic + // Note that this implicit conversion additionally allows all of the basic // comparison operators to work transparently, etc. - operator IntT() const { return static_cast<IntT>(Value >> Shift); } + operator IntT() const { + if (std::is_signed<IntT>::value) + return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift); + return static_cast<IntT>(Value >> Shift); + } }; // Provide pointer like traits to support use with pointer unions and sum @@ -74,10 +88,10 @@ public: return reinterpret_cast<void *>(P.Value); } static inline T getFromVoidPointer(void *P) { - return T(reinterpret_cast<uintptr_t>(P)); + return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag()); } static inline T getFromVoidPointer(const void *P) { - return T(reinterpret_cast<uintptr_t>(P)); + return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag()); } enum { NumLowBitsAvailable = T::Shift }; diff --git a/include/llvm/ADT/PostOrderIterator.h b/include/llvm/ADT/PostOrderIterator.h index ce343a161b7b..0cc504b5c39e 100644 --- a/include/llvm/ADT/PostOrderIterator.h +++ b/include/llvm/ADT/PostOrderIterator.h @@ -28,7 +28,7 @@ namespace llvm { // visited nodes during the po_iterator's depth-first traversal. // // The default implementation simply contains a set of visited nodes, while -// the Extended=true version uses a reference to an external set. +// the External=true version uses a reference to an external set. // // It is possible to prune the depth-first traversal in several ways: // diff --git a/include/llvm/ADT/PriorityWorklist.h b/include/llvm/ADT/PriorityWorklist.h new file mode 100644 index 000000000000..00549b88fd02 --- /dev/null +++ b/include/llvm/ADT/PriorityWorklist.h @@ -0,0 +1,224 @@ +//===- PriorityWorklist.h - Worklist with insertion priority ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file provides a priority worklist. See the class comments for details. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_PRIORITYWORKLIST_H +#define LLVM_ADT_PRIORITYWORKLIST_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> +#include <cassert> +#include <utility> +#include <vector> + +namespace llvm { + +/// A FILO worklist that prioritizes on re-insertion without duplication. +/// +/// This is very similar to a \c SetVector with the primary difference that +/// while re-insertion does not create a duplicate, it does adjust the +/// visitation order to respect the last insertion point. This can be useful +/// when the visit order needs to be prioritized based on insertion point +/// without actually having duplicate visits. +/// +/// Note that this doesn't prevent re-insertion of elements which have been +/// visited -- if you need to break cycles, a set will still be necessary. +/// +/// The type \c T must be default constructable to a null value that will be +/// ignored. It is an error to insert such a value, and popping elements will +/// never produce such a value. It is expected to be used with common nullable +/// types like pointers or optionals. +/// +/// Internally this uses a vector to store the worklist and a map to identify +/// existing elements in the worklist. Both of these may be customized, but the +/// map must support the basic DenseMap API for mapping from a T to an integer +/// index into the vector. +/// +/// A partial specialization is provided to automatically select a SmallVector +/// and a SmallDenseMap if custom data structures are not provided. +template <typename T, typename VectorT = std::vector<T>, + typename MapT = DenseMap<T, ptrdiff_t>> +class PriorityWorklist { +public: + typedef T value_type; + typedef T key_type; + typedef T& reference; + typedef const T& const_reference; + typedef typename MapT::size_type size_type; + + /// Construct an empty PriorityWorklist + PriorityWorklist() {} + + /// Determine if the PriorityWorklist is empty or not. + bool empty() const { + return V.empty(); + } + + /// Returns the number of elements in the worklist. + size_type size() const { + return M.size(); + } + + /// Count the number of elements of a given key in the PriorityWorklist. + /// \returns 0 if the element is not in the PriorityWorklist, 1 if it is. + size_type count(const key_type &key) const { + return M.count(key); + } + + /// Return the last element of the PriorityWorklist. + const T &back() const { + assert(!empty() && "Cannot call back() on empty PriorityWorklist!"); + return V.back(); + } + + /// Insert a new element into the PriorityWorklist. + /// \returns true if the element was inserted into the PriorityWorklist. + bool insert(const T &X) { + assert(X != T() && "Cannot insert a null (default constructed) value!"); + auto InsertResult = M.insert({X, V.size()}); + if (InsertResult.second) { + // Fresh value, just append it to the vector. + V.push_back(X); + return true; + } + + auto &Index = InsertResult.first->second; + assert(V[Index] == X && "Value not actually at index in map!"); + if (Index != (ptrdiff_t)(V.size() - 1)) { + // If the element isn't at the back, null it out and append a fresh one. + V[Index] = T(); + Index = (ptrdiff_t)V.size(); + V.push_back(X); + } + return false; + } + + /// Remove the last element of the PriorityWorklist. + void pop_back() { + assert(!empty() && "Cannot remove an element when empty!"); + assert(back() != T() && "Cannot have a null element at the back!"); + M.erase(back()); + do { + V.pop_back(); + } while (!V.empty() && V.back() == T()); + } + + T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() { + T Ret = back(); + pop_back(); + return Ret; + } + + /// Erase an item from the worklist. + /// + /// Note that this is constant time due to the nature of the worklist implementation. + bool erase(const T& X) { + auto I = M.find(X); + if (I == M.end()) + return false; + + assert(V[I->second] == X && "Value not actually at index in map!"); + if (I->second == (ptrdiff_t)(V.size() - 1)) { + do { + V.pop_back(); + } while (!V.empty() && V.back() == T()); + } else { + V[I->second] = T(); + } + M.erase(I); + return true; + } + + /// Erase items from the set vector based on a predicate function. + /// + /// This is intended to be equivalent to the following code, if we could + /// write it: + /// + /// \code + /// V.erase(std::remove_if(V.begin(), V.end(), P), V.end()); + /// \endcode + /// + /// However, PriorityWorklist doesn't expose non-const iterators, making any + /// algorithm like remove_if impossible to use. + /// + /// \returns true if any element is removed. + template <typename UnaryPredicate> + bool erase_if(UnaryPredicate P) { + typename VectorT::iterator E = std::remove_if( + V.begin(), V.end(), TestAndEraseFromMap<UnaryPredicate>(P, M)); + if (E == V.end()) + return false; + for (auto I = V.begin(); I != E; ++I) + if (*I != T()) + M[*I] = I - V.begin(); + V.erase(E, V.end()); + return true; + } + + /// Completely clear the PriorityWorklist + void clear() { + M.clear(); + V.clear(); + } + +private: + /// A wrapper predicate designed for use with std::remove_if. + /// + /// This predicate wraps a predicate suitable for use with std::remove_if to + /// call M.erase(x) on each element which is slated for removal. This just + /// allows the predicate to be move only which we can't do with lambdas + /// today. + template <typename UnaryPredicateT> + class TestAndEraseFromMap { + UnaryPredicateT P; + MapT &M; + + public: + TestAndEraseFromMap(UnaryPredicateT P, MapT &M) + : P(std::move(P)), M(M) {} + + bool operator()(const T &Arg) { + if (Arg == T()) + // Skip null values in the PriorityWorklist. + return false; + + if (P(Arg)) { + M.erase(Arg); + return true; + } + return false; + } + }; + + /// The map from value to index in the vector. + MapT M; + + /// The vector of elements in insertion order. + VectorT V; +}; + +/// A version of \c PriorityWorklist that selects small size optimized data +/// structures for the vector and map. +template <typename T, unsigned N> +class SmallPriorityWorklist + : public PriorityWorklist<T, SmallVector<T, N>, + SmallDenseMap<T, ptrdiff_t>> { +public: + SmallPriorityWorklist() {} +}; + +} + +#endif diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index d4360fa8d218..abd39dacc671 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -17,7 +17,6 @@ #ifndef LLVM_ADT_STLEXTRAS_H #define LLVM_ADT_STLEXTRAS_H -#include "llvm/Support/Compiler.h" #include <algorithm> // for std::all_of #include <cassert> #include <cstddef> // for std::size_t @@ -27,6 +26,9 @@ #include <memory> #include <utility> // for std::pair +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compiler.h" + namespace llvm { //===----------------------------------------------------------------------===// @@ -117,7 +119,9 @@ public: iterator_category; typedef typename std::iterator_traits<RootIt>::difference_type difference_type; - typedef typename UnaryFunc::result_type value_type; + typedef typename std::result_of< + UnaryFunc(decltype(*std::declval<RootIt>()))> + ::type value_type; typedef void pointer; //typedef typename UnaryFunc::result_type *pointer; @@ -379,6 +383,14 @@ bool any_of(R &&Range, UnaryPredicate &&P) { std::forward<UnaryPredicate>(P)); } +/// Provide wrappers to std::none_of which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, class UnaryPredicate> +bool none_of(R &&Range, UnaryPredicate &&P) { + return std::none_of(Range.begin(), Range.end(), + std::forward<UnaryPredicate>(P)); +} + /// Provide wrappers to std::find which take ranges instead of having to pass /// begin/end explicitly. template<typename R, class T> @@ -386,6 +398,43 @@ auto find(R &&Range, const T &val) -> decltype(Range.begin()) { return std::find(Range.begin(), Range.end(), val); } +/// Provide wrappers to std::find_if which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, class T> +auto find_if(R &&Range, const T &Pred) -> decltype(Range.begin()) { + return std::find_if(Range.begin(), Range.end(), Pred); +} + +/// Provide wrappers to std::remove_if which take ranges instead of having to +/// pass begin/end explicitly. +template<typename R, class UnaryPredicate> +auto remove_if(R &&Range, UnaryPredicate &&P) -> decltype(Range.begin()) { + return std::remove_if(Range.begin(), Range.end(), P); +} + +/// Wrapper function around std::find to detect if an element exists +/// in a container. +template <typename R, typename E> +bool is_contained(R &&Range, const E &Element) { + return std::find(Range.begin(), Range.end(), Element) != Range.end(); +} + +/// Wrapper function around std::count_if to count the number of times an +/// element satisfying a given predicate occurs in a range. +template <typename R, typename UnaryPredicate> +auto count_if(R &&Range, UnaryPredicate &&P) + -> typename std::iterator_traits<decltype(Range.begin())>::difference_type { + return std::count_if(Range.begin(), Range.end(), P); +} + +/// Wrapper function around std::transform to apply a function to a range and +/// store the result elsewhere. +template <typename R, class OutputIt, typename UnaryPredicate> +OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate &&P) { + return std::transform(Range.begin(), Range.end(), d_first, + std::forward<UnaryPredicate>(P)); +} + //===----------------------------------------------------------------------===// // Extra additions to <memory> //===----------------------------------------------------------------------===// diff --git a/include/llvm/ADT/Sequence.h b/include/llvm/ADT/Sequence.h new file mode 100644 index 000000000000..5d36831cc128 --- /dev/null +++ b/include/llvm/ADT/Sequence.h @@ -0,0 +1,79 @@ +//===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This routine provides some synthesis utilities to produce sequences of +/// values. The names are intentionally kept very short as they tend to occur +/// in common and widely used contexts. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SEQ_H +#define LLVM_ADT_SEQ_H + +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" + +namespace llvm { + +namespace detail { +template <typename ValueT> +class value_sequence_iterator + : public iterator_facade_base<value_sequence_iterator<ValueT>, + std::random_access_iterator_tag, + const ValueT> { + typedef typename value_sequence_iterator::iterator_facade_base BaseT; + + ValueT Value; + +public: + typedef typename BaseT::difference_type difference_type; + typedef typename BaseT::reference reference; + + value_sequence_iterator() = default; + value_sequence_iterator(const value_sequence_iterator &) = default; + value_sequence_iterator(value_sequence_iterator &&Arg) + : Value(std::move(Arg.Value)) {} + + template <typename U, typename Enabler = decltype(ValueT(std::declval<U>()))> + value_sequence_iterator(U &&Value) : Value(std::forward<U>(Value)) {} + + value_sequence_iterator &operator+=(difference_type N) { + Value += N; + return *this; + } + value_sequence_iterator &operator-=(difference_type N) { + Value -= N; + return *this; + } + using BaseT::operator-; + difference_type operator-(const value_sequence_iterator &RHS) const { + return Value - RHS.Value; + } + + bool operator==(const value_sequence_iterator &RHS) const { + return Value == RHS.Value; + } + bool operator<(const value_sequence_iterator &RHS) const { + return Value < RHS.Value; + } + + reference operator*() const { return Value; } +}; +} // End detail namespace. + +template <typename ValueT> +iterator_range<detail::value_sequence_iterator<ValueT>> seq(ValueT Begin, + ValueT End) { + return make_range(detail::value_sequence_iterator<ValueT>(Begin), + detail::value_sequence_iterator<ValueT>(End)); +} + +} + +#endif diff --git a/include/llvm/ADT/SetVector.h b/include/llvm/ADT/SetVector.h index bc563570c203..2bb0fdbd3370 100644 --- a/include/llvm/ADT/SetVector.h +++ b/include/llvm/ADT/SetVector.h @@ -24,6 +24,7 @@ #include "llvm/ADT/SmallSet.h" #include <algorithm> #include <cassert> +#include <utility> #include <vector> namespace llvm { @@ -123,7 +124,7 @@ public: } /// \brief Insert a new element into the SetVector. - /// \returns true iff the element was inserted into the SetVector. + /// \returns true if the element was inserted into the SetVector. bool insert(const value_type &X) { bool result = set_.insert(X).second; if (result) @@ -151,6 +152,24 @@ public: return false; } + /// Erase a single element from the set vector. + /// \returns an iterator pointing to the next element that followed the + /// element erased. This is the end of the SetVector if the last element is + /// erased. + iterator erase(iterator I) { + const key_type &V = *I; + assert(set_.count(V) && "Corrupted SetVector instances!"); + set_.erase(V); + + // FIXME: No need to use the non-const iterator when built with + // std:vector.erase(const_iterator) as defined in C++11. This is for + // compatibility with non-standard libstdc++ up to 4.8 (fixed in 4.9). + auto NI = vector_.begin(); + std::advance(NI, std::distance<iterator>(NI, I)); + + return vector_.erase(NI); + } + /// \brief Remove items from the set vector based on a predicate function. /// /// This is intended to be equivalent to the following code, if we could @@ -207,6 +226,31 @@ public: bool operator!=(const SetVector &that) const { return vector_ != that.vector_; } + + /// \brief Compute This := This u S, return whether 'This' changed. + /// TODO: We should be able to use set_union from SetOperations.h, but + /// SetVector interface is inconsistent with DenseSet. + template <class STy> + bool set_union(const STy &S) { + bool Changed = false; + + for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; + ++SI) + if (insert(*SI)) + Changed = true; + + return Changed; + } + + /// \brief Compute This := This - B + /// TODO: We should be able to use set_subtract from SetOperations.h, but + /// SetVector interface is inconsistent with DenseSet. + template <class STy> + void set_subtract(const STy &S) { + for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; + ++SI) + remove(*SI); + } private: /// \brief A wrapper predicate designed for use with std::remove_if. @@ -219,7 +263,8 @@ private: set_type &set_; public: - TestAndEraseFromSet(UnaryPredicate P, set_type &set_) : P(P), set_(set_) {} + TestAndEraseFromSet(UnaryPredicate P, set_type &set_) + : P(std::move(P)), set_(set_) {} template <typename ArgumentT> bool operator()(const ArgumentT &Arg) { diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h index 4aa3bc217f41..bb99e0cf221f 100644 --- a/include/llvm/ADT/SmallBitVector.h +++ b/include/llvm/ADT/SmallBitVector.h @@ -15,19 +15,16 @@ #define LLVM_ADT_SMALLBITVECTOR_H #include "llvm/ADT/BitVector.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include <cassert> namespace llvm { -/// SmallBitVector - This is a 'bitvector' (really, a variable-sized bit array), -/// optimized for the case when the array is small. It contains one -/// pointer-sized field, which is directly used as a plain collection of bits -/// when possible, or as a pointer to a larger heap-allocated array when -/// necessary. This allows normal "small" cases to be fast without losing -/// generality for large inputs. -/// +/// This is a 'bitvector' (really, a variable-sized bit array), optimized for +/// the case when the array is small. It contains one pointer-sized field, which +/// is directly used as a plain collection of bits when possible, or as a +/// pointer to a larger heap-allocated array when necessary. This allows normal +/// "small" cases to be fast without losing generality for large inputs. class SmallBitVector { // TODO: In "large" mode, a pointer to a BitVector is used, leading to an // unnecessary level of indirection. It would be more efficient to use a @@ -139,11 +136,11 @@ private: } public: - /// SmallBitVector default ctor - Creates an empty bitvector. + /// Creates an empty bitvector. SmallBitVector() : X(1) {} - /// SmallBitVector ctor - Creates a bitvector of specified number of bits. All - /// bits are initialized to the specified value. + /// Creates a bitvector of specified number of bits. All bits are initialized + /// to the specified value. explicit SmallBitVector(unsigned s, bool t = false) { if (s <= SmallNumDataBits) switchToSmall(t ? ~uintptr_t(0) : 0, s); @@ -168,17 +165,17 @@ public: delete getPointer(); } - /// empty - Tests whether there are no bits in this bitvector. + /// Tests whether there are no bits in this bitvector. bool empty() const { return isSmall() ? getSmallSize() == 0 : getPointer()->empty(); } - /// size - Returns the number of bits in this bitvector. + /// Returns the number of bits in this bitvector. size_t size() const { return isSmall() ? getSmallSize() : getPointer()->size(); } - /// count - Returns the number of bits which are set. + /// Returns the number of bits which are set. size_type count() const { if (isSmall()) { uintptr_t Bits = getSmallBits(); @@ -187,29 +184,28 @@ public: return getPointer()->count(); } - /// any - Returns true if any bit is set. + /// Returns true if any bit is set. bool any() const { if (isSmall()) return getSmallBits() != 0; return getPointer()->any(); } - /// all - Returns true if all bits are set. + /// Returns true if all bits are set. bool all() const { if (isSmall()) return getSmallBits() == (uintptr_t(1) << getSmallSize()) - 1; return getPointer()->all(); } - /// none - Returns true if none of the bits are set. + /// Returns true if none of the bits are set. bool none() const { if (isSmall()) return getSmallBits() == 0; return getPointer()->none(); } - /// find_first - Returns the index of the first set bit, -1 if none - /// of the bits are set. + /// Returns the index of the first set bit, -1 if none of the bits are set. int find_first() const { if (isSmall()) { uintptr_t Bits = getSmallBits(); @@ -220,8 +216,8 @@ public: return getPointer()->find_first(); } - /// find_next - Returns the index of the next set bit following the - /// "Prev" bit. Returns -1 if the next set bit is not found. + /// Returns the index of the next set bit following the "Prev" bit. + /// Returns -1 if the next set bit is not found. int find_next(unsigned Prev) const { if (isSmall()) { uintptr_t Bits = getSmallBits(); @@ -234,14 +230,14 @@ public: return getPointer()->find_next(Prev); } - /// clear - Clear all bits. + /// Clear all bits. void clear() { if (!isSmall()) delete getPointer(); switchToSmall(0, 0); } - /// resize - Grow or shrink the bitvector. + /// Grow or shrink the bitvector. void resize(unsigned N, bool t = false) { if (!isSmall()) { getPointer()->resize(N, t); @@ -296,7 +292,7 @@ public: return *this; } - /// set - Efficiently set a range of bits in [I, E) + /// Efficiently set a range of bits in [I, E) SmallBitVector &set(unsigned I, unsigned E) { assert(I <= E && "Attempted to set backwards range!"); assert(E <= size() && "Attempted to set out-of-bounds range!"); @@ -327,7 +323,7 @@ public: return *this; } - /// reset - Efficiently reset a range of bits in [I, E) + /// Efficiently reset a range of bits in [I, E) SmallBitVector &reset(unsigned I, unsigned E) { assert(I <= E && "Attempted to reset backwards range!"); assert(E <= size() && "Attempted to reset out-of-bounds range!"); @@ -422,7 +418,7 @@ public: return *this; } - /// reset - Reset bits that are set in RHS. Same as *this &= ~RHS. + /// Reset bits that are set in RHS. Same as *this &= ~RHS. SmallBitVector &reset(const SmallBitVector &RHS) { if (isSmall() && RHS.isSmall()) setSmallBits(getSmallBits() & ~RHS.getSmallBits()); @@ -436,8 +432,7 @@ public: return *this; } - /// test - Check if (This - RHS) is zero. - /// This is the same as reset(RHS) and any(). + /// Check if (This - RHS) is zero. This is the same as reset(RHS) and any(). bool test(const SmallBitVector &RHS) const { if (isSmall() && RHS.isSmall()) return (getSmallBits() & ~RHS.getSmallBits()) != 0; @@ -514,7 +509,7 @@ public: std::swap(X, RHS.X); } - /// setBitsInMask - Add '1' bits from Mask to this vector. Don't resize. + /// Add '1' bits from Mask to this vector. Don't resize. /// This computes "*this |= Mask". void setBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { if (isSmall()) @@ -523,8 +518,8 @@ public: getPointer()->setBitsInMask(Mask, MaskWords); } - /// clearBitsInMask - Clear any bits in this vector that are set in Mask. - /// Don't resize. This computes "*this &= ~Mask". + /// Clear any bits in this vector that are set in Mask. Don't resize. + /// This computes "*this &= ~Mask". void clearBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { if (isSmall()) applyMask<false, false>(Mask, MaskWords); @@ -532,8 +527,8 @@ public: getPointer()->clearBitsInMask(Mask, MaskWords); } - /// setBitsNotInMask - Add a bit to this vector for every '0' bit in Mask. - /// Don't resize. This computes "*this |= ~Mask". + /// Add a bit to this vector for every '0' bit in Mask. Don't resize. + /// This computes "*this |= ~Mask". void setBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { if (isSmall()) applyMask<true, true>(Mask, MaskWords); @@ -541,8 +536,8 @@ public: getPointer()->setBitsNotInMask(Mask, MaskWords); } - /// clearBitsNotInMask - Clear a bit in this vector for every '0' bit in Mask. - /// Don't resize. This computes "*this &= Mask". + /// Clear a bit in this vector for every '0' bit in Mask. Don't resize. + /// This computes "*this &= Mask". void clearBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { if (isSmall()) applyMask<false, true>(Mask, MaskWords); diff --git a/include/llvm/ADT/SmallPtrSet.h b/include/llvm/ADT/SmallPtrSet.h index 3d98e8fac43b..eaed6aa05dcb 100644 --- a/include/llvm/ADT/SmallPtrSet.h +++ b/include/llvm/ADT/SmallPtrSet.h @@ -21,6 +21,7 @@ #include <cassert> #include <cstddef> #include <cstring> +#include <cstdlib> #include <iterator> #include <utility> @@ -58,36 +59,45 @@ protected: /// CurArraySize - The allocated size of CurArray, always a power of two. unsigned CurArraySize; - // If small, this is # elts allocated consecutively - unsigned NumElements; + /// Number of elements in CurArray that contain a value or are a tombstone. + /// If small, all these elements are at the beginning of CurArray and the rest + /// is uninitialized. + unsigned NumNonEmpty; + /// Number of tombstones in CurArray. unsigned NumTombstones; // Helpers to copy and move construct a SmallPtrSet. - SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that); + SmallPtrSetImplBase(const void **SmallStorage, + const SmallPtrSetImplBase &that); SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize, - SmallPtrSetImplBase &&that); - explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) : - SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) { + SmallPtrSetImplBase &&that); + explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) + : SmallArray(SmallStorage), CurArray(SmallStorage), + CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) { assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 && "Initial size must be a power of two!"); - clear(); } - ~SmallPtrSetImplBase(); + ~SmallPtrSetImplBase() { + if (!isSmall()) + free(CurArray); + } public: typedef unsigned size_type; bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; } - size_type size() const { return NumElements; } + size_type size() const { return NumNonEmpty - NumTombstones; } void clear() { // If the capacity of the array is huge, and the # elements used is small, // shrink the array. - if (!isSmall() && NumElements*4 < CurArraySize && CurArraySize > 32) - return shrink_and_clear(); + if (!isSmall()) { + if (size() * 4 < CurArraySize && CurArraySize > 32) + return shrink_and_clear(); + // Fill the array with empty markers. + memset(CurArray, -1, CurArraySize * sizeof(void *)); + } - // Fill the array with empty markers. - memset(CurArray, -1, CurArraySize*sizeof(void*)); - NumElements = 0; + NumNonEmpty = 0; NumTombstones = 0; } @@ -99,10 +109,42 @@ protected: return reinterpret_cast<void*>(-1); } + const void **EndPointer() const { + return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize; + } + /// insert_imp - This returns true if the pointer was new to the set, false if /// it was already in the set. This is hidden from the client so that the /// derived class can check that the right type of pointer is passed in. - std::pair<const void *const *, bool> insert_imp(const void *Ptr); + std::pair<const void *const *, bool> insert_imp(const void *Ptr) { + if (isSmall()) { + // Check to see if it is already in the set. + const void **LastTombstone = nullptr; + for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty; + APtr != E; ++APtr) { + const void *Value = *APtr; + if (Value == Ptr) + return std::make_pair(APtr, false); + if (Value == getTombstoneMarker()) + LastTombstone = APtr; + } + + // Did we find any tombstone marker? + if (LastTombstone != nullptr) { + *LastTombstone = Ptr; + --NumTombstones; + return std::make_pair(LastTombstone, true); + } + + // Nope, there isn't. If we stay small, just 'pushback' now. + if (NumNonEmpty < CurArraySize) { + SmallArray[NumNonEmpty++] = Ptr; + return std::make_pair(SmallArray + (NumNonEmpty - 1), true); + } + // Otherwise, hit the big set case, which will call grow. + } + return insert_imp_big(Ptr); + } /// erase_imp - If the set contains the specified pointer, remove it and /// return true, otherwise return false. This is hidden from the client so @@ -114,7 +156,7 @@ protected: if (isSmall()) { // Linear search for the item. for (const void *const *APtr = SmallArray, - *const *E = SmallArray+NumElements; APtr != E; ++APtr) + *const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr) if (*APtr == Ptr) return true; return false; @@ -127,6 +169,8 @@ protected: private: bool isSmall() const { return CurArray == SmallArray; } + std::pair<const void *const *, bool> insert_imp_big(const void *Ptr); + const void * const *FindBucketFor(const void *Ptr) const; void shrink_and_clear(); @@ -142,6 +186,12 @@ protected: void CopyFrom(const SmallPtrSetImplBase &RHS); void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS); + +private: + /// Code shared by MoveFrom() and move constructor. + void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS); + /// Code shared by CopyFrom() and copy constructor. + void CopyHelper(const SmallPtrSetImplBase &RHS); }; /// SmallPtrSetIteratorImpl - This is the common base class shared between all @@ -154,7 +204,7 @@ protected: public: explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E) : Bucket(BP), End(E) { - AdvanceIfNotValid(); + AdvanceIfNotValid(); } bool operator==(const SmallPtrSetIteratorImpl &RHS) const { @@ -266,7 +316,7 @@ public: /// the element equal to Ptr. std::pair<iterator, bool> insert(PtrType Ptr) { auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr)); - return std::make_pair(iterator(p.first, CurArray + CurArraySize), p.second); + return std::make_pair(iterator(p.first, EndPointer()), p.second); } /// erase - If the set contains the specified pointer, remove it and return @@ -287,10 +337,11 @@ public: } inline iterator begin() const { - return iterator(CurArray, CurArray+CurArraySize); + return iterator(CurArray, EndPointer()); } inline iterator end() const { - return iterator(CurArray+CurArraySize, CurArray+CurArraySize); + const void *const *End = EndPointer(); + return iterator(End, End); } }; @@ -300,6 +351,11 @@ public: /// SmallPtrSetImplBase for details of the algorithm. template<class PtrType, unsigned SmallSize> class SmallPtrSet : public SmallPtrSetImpl<PtrType> { + // In small mode SmallPtrSet uses linear search for the elements, so it is + // not a good idea to choose this value too high. You may consider using a + // DenseSet<> instead if you expect many elements in the set. + static_assert(SmallSize <= 32, "SmallSize should be small"); + typedef SmallPtrSetImpl<PtrType> BaseT; // Make sure that SmallSize is a power of two, round up if not. diff --git a/include/llvm/ADT/SmallSet.h b/include/llvm/ADT/SmallSet.h index 39a57b87b2a7..aaa5ff0ae939 100644 --- a/include/llvm/ADT/SmallSet.h +++ b/include/llvm/ADT/SmallSet.h @@ -38,6 +38,11 @@ class SmallSet { typedef typename SmallVector<T, N>::const_iterator VIterator; typedef typename SmallVector<T, N>::iterator mutable_iterator; + // In small mode SmallPtrSet uses linear search for the elements, so it is + // not a good idea to choose this value too high. You may consider using a + // DenseSet<> instead if you expect many elements in the set. + static_assert(N <= 32, "N should be small"); + public: typedef size_t size_type; SmallSet() {} diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h index d1062acbbb61..42eedc63e079 100644 --- a/include/llvm/ADT/SmallVector.h +++ b/include/llvm/ADT/SmallVector.h @@ -184,33 +184,12 @@ protected: } } - /// Use move-assignment to move the range [I, E) onto the - /// objects starting with "Dest". This is just <memory>'s - /// std::move, but not all stdlibs actually provide that. - template<typename It1, typename It2> - static It2 move(It1 I, It1 E, It2 Dest) { - for (; I != E; ++I, ++Dest) - *Dest = ::std::move(*I); - return Dest; - } - - /// Use move-assignment to move the range - /// [I, E) onto the objects ending at "Dest", moving objects - /// in reverse order. This is just <algorithm>'s - /// std::move_backward, but not all stdlibs actually provide that. - template<typename It1, typename It2> - static It2 move_backward(It1 I, It1 E, It2 Dest) { - while (I != E) - *--Dest = ::std::move(*--E); - return Dest; - } - /// Move the range [I, E) into the uninitialized memory starting with "Dest", /// constructing elements as needed. template<typename It1, typename It2> static void uninitialized_move(It1 I, It1 E, It2 Dest) { - for (; I != E; ++I, ++Dest) - ::new ((void*) &*Dest) T(::std::move(*I)); + std::uninitialized_copy(std::make_move_iterator(I), + std::make_move_iterator(E), Dest); } /// Copy the range [I, E) onto the uninitialized memory starting with "Dest", @@ -283,20 +262,6 @@ protected: // No need to do a destroy loop for POD's. static void destroy_range(T *, T *) {} - /// Use move-assignment to move the range [I, E) onto the - /// objects starting with "Dest". For PODs, this is just memcpy. - template<typename It1, typename It2> - static It2 move(It1 I, It1 E, It2 Dest) { - return ::std::copy(I, E, Dest); - } - - /// Use move-assignment to move the range [I, E) onto the objects ending at - /// "Dest", moving objects in reverse order. - template<typename It1, typename It2> - static It2 move_backward(It1 I, It1 E, It2 Dest) { - return ::std::copy_backward(I, E, Dest); - } - /// Move the range [I, E) onto the uninitialized memory /// starting with "Dest", constructing elements into it as needed. template<typename It1, typename It2> @@ -356,6 +321,7 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> { SmallVectorImpl(const SmallVectorImpl&) = delete; public: typedef typename SuperClass::iterator iterator; + typedef typename SuperClass::const_iterator const_iterator; typedef typename SuperClass::size_type size_type; protected: @@ -459,26 +425,33 @@ public: append(IL); } - iterator erase(iterator I) { + iterator erase(const_iterator CI) { + // Just cast away constness because this is a non-const member function. + iterator I = const_cast<iterator>(CI); + assert(I >= this->begin() && "Iterator to erase is out of bounds."); assert(I < this->end() && "Erasing at past-the-end iterator."); iterator N = I; // Shift all elts down one. - this->move(I+1, this->end(), I); + std::move(I+1, this->end(), I); // Drop the last elt. this->pop_back(); return(N); } - iterator erase(iterator S, iterator E) { + iterator erase(const_iterator CS, const_iterator CE) { + // Just cast away constness because this is a non-const member function. + iterator S = const_cast<iterator>(CS); + iterator E = const_cast<iterator>(CE); + assert(S >= this->begin() && "Range to erase is out of bounds."); assert(S <= E && "Trying to erase invalid range."); assert(E <= this->end() && "Trying to erase past the end."); iterator N = S; // Shift all elts down. - iterator I = this->move(E, this->end(), S); + iterator I = std::move(E, this->end(), S); // Drop the last elts. this->destroy_range(I, this->end()); this->setEnd(I); @@ -502,7 +475,7 @@ public: ::new ((void*) this->end()) T(::std::move(this->back())); // Push everything else over. - this->move_backward(I, this->end()-1, this->end()); + std::move_backward(I, this->end()-1, this->end()); this->setEnd(this->end()+1); // If we just moved the element we're inserting, be sure to update @@ -531,7 +504,7 @@ public: } ::new ((void*) this->end()) T(std::move(this->back())); // Push everything else over. - this->move_backward(I, this->end()-1, this->end()); + std::move_backward(I, this->end()-1, this->end()); this->setEnd(this->end()+1); // If we just moved the element we're inserting, be sure to update @@ -572,7 +545,7 @@ public: std::move_iterator<iterator>(this->end())); // Copy the existing elements that get replaced. - this->move_backward(I, OldEnd-NumToInsert, OldEnd); + std::move_backward(I, OldEnd-NumToInsert, OldEnd); std::fill_n(I, NumToInsert, Elt); return I; @@ -626,7 +599,7 @@ public: std::move_iterator<iterator>(this->end())); // Copy the existing elements that get replaced. - this->move_backward(I, OldEnd-NumToInsert, OldEnd); + std::move_backward(I, OldEnd-NumToInsert, OldEnd); std::copy(From, To, I); return I; @@ -807,7 +780,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) { // Assign common elements. iterator NewEnd = this->begin(); if (RHSSize) - NewEnd = this->move(RHS.begin(), RHS.end(), NewEnd); + NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd); // Destroy excess elements and trim the bounds. this->destroy_range(NewEnd, this->end()); @@ -831,7 +804,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) { this->grow(RHSSize); } else if (CurSize) { // Otherwise, use assignment for the already-constructed elements. - this->move(RHS.begin(), RHS.begin()+CurSize, this->begin()); + std::move(RHS.begin(), RHS.begin()+CurSize, this->begin()); } // Move-construct the new elements in place. diff --git a/include/llvm/ADT/SparseSet.h b/include/llvm/ADT/SparseSet.h index a45d1c8d6b8a..5b6494d17129 100644 --- a/include/llvm/ADT/SparseSet.h +++ b/include/llvm/ADT/SparseSet.h @@ -263,6 +263,11 @@ public: return *insert(ValueT(Key)).first; } + ValueT pop_back_val() { + // Sparse does not need to be cleared, see find(). + return Dense.pop_back_val(); + } + /// erase - Erases an existing element identified by a valid iterator. /// /// This invalidates all iterators, but erase() returns an iterator pointing diff --git a/include/llvm/ADT/Statistic.h b/include/llvm/ADT/Statistic.h index 7c84e3ef6b4d..32175fdc7c5c 100644 --- a/include/llvm/ADT/Statistic.h +++ b/include/llvm/ADT/Statistic.h @@ -27,7 +27,8 @@ #define LLVM_ADT_STATISTIC_H #include "llvm/Support/Atomic.h" -#include "llvm/Support/Valgrind.h" +#include "llvm/Support/Compiler.h" +#include <atomic> #include <memory> namespace llvm { @@ -36,77 +37,66 @@ class raw_fd_ostream; class Statistic { public: + const char *DebugType; const char *Name; const char *Desc; - volatile llvm::sys::cas_flag Value; + std::atomic<unsigned> Value; bool Initialized; - llvm::sys::cas_flag getValue() const { return Value; } + unsigned getValue() const { return Value.load(std::memory_order_relaxed); } + const char *getDebugType() const { return DebugType; } const char *getName() const { return Name; } const char *getDesc() const { return Desc; } /// construct - This should only be called for non-global statistics. - void construct(const char *name, const char *desc) { - Name = name; Desc = desc; - Value = 0; Initialized = false; + void construct(const char *debugtype, const char *name, const char *desc) { + DebugType = debugtype; + Name = name; + Desc = desc; + Value = 0; + Initialized = false; } // Allow use of this class as the value itself. - operator unsigned() const { return Value; } + operator unsigned() const { return getValue(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) const Statistic &operator=(unsigned Val) { - Value = Val; + Value.store(Val, std::memory_order_relaxed); return init(); } const Statistic &operator++() { - // FIXME: This function and all those that follow carefully use an - // atomic operation to update the value safely in the presence of - // concurrent accesses, but not to read the return value, so the - // return value is not thread safe. - sys::AtomicIncrement(&Value); + Value.fetch_add(1, std::memory_order_relaxed); return init(); } unsigned operator++(int) { init(); - unsigned OldValue = Value; - sys::AtomicIncrement(&Value); - return OldValue; + return Value.fetch_add(1, std::memory_order_relaxed); } const Statistic &operator--() { - sys::AtomicDecrement(&Value); + Value.fetch_sub(1, std::memory_order_relaxed); return init(); } unsigned operator--(int) { init(); - unsigned OldValue = Value; - sys::AtomicDecrement(&Value); - return OldValue; + return Value.fetch_sub(1, std::memory_order_relaxed); } - const Statistic &operator+=(const unsigned &V) { - if (!V) return *this; - sys::AtomicAdd(&Value, V); - return init(); - } - - const Statistic &operator-=(const unsigned &V) { - if (!V) return *this; - sys::AtomicAdd(&Value, -V); - return init(); - } - - const Statistic &operator*=(const unsigned &V) { - sys::AtomicMul(&Value, V); + const Statistic &operator+=(unsigned V) { + if (V == 0) + return *this; + Value.fetch_add(V, std::memory_order_relaxed); return init(); } - const Statistic &operator/=(const unsigned &V) { - sys::AtomicDiv(&Value, V); + const Statistic &operator-=(unsigned V) { + if (V == 0) + return *this; + Value.fetch_sub(V, std::memory_order_relaxed); return init(); } @@ -140,14 +130,6 @@ public: return *this; } - const Statistic &operator*=(const unsigned &V) { - return *this; - } - - const Statistic &operator/=(const unsigned &V) { - return *this; - } - #endif // !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) protected: @@ -163,8 +145,8 @@ protected: // STATISTIC - A macro to make definition of statistics really simple. This // automatically passes the DEBUG_TYPE of the file into the statistic. -#define STATISTIC(VARNAME, DESC) \ - static llvm::Statistic VARNAME = { DEBUG_TYPE, DESC, 0, 0 } +#define STATISTIC(VARNAME, DESC) \ + static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, 0} /// \brief Enable the collection and printing of statistics. void EnableStatistics(); @@ -181,6 +163,9 @@ void PrintStatistics(); /// \brief Print statistics to the given output stream. void PrintStatistics(raw_ostream &OS); -} // End llvm namespace +/// Print statistics in JSON format. +void PrintStatisticsJSON(raw_ostream &OS); + +} // end llvm namespace -#endif +#endif // LLVM_ADT_STATISTIC_H diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index 0992f5d4a549..bdbb4d3f5932 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -44,55 +44,40 @@ static inline unsigned hexDigitValue(char C) { return -1U; } -/// utohex_buffer - Emit the specified number into the buffer specified by -/// BufferEnd, returning a pointer to the start of the string. This can be used -/// like this: (note that the buffer must be large enough to handle any number): -/// char Buffer[40]; -/// printf("0x%s", utohex_buffer(X, Buffer+40)); -/// -/// This should only be used with unsigned types. -/// -template<typename IntTy> -static inline char *utohex_buffer(IntTy X, char *BufferEnd, bool LowerCase = false) { - char *BufPtr = BufferEnd; - *--BufPtr = 0; // Null terminate buffer. - if (X == 0) { - *--BufPtr = '0'; // Handle special case. - return BufPtr; - } +static inline std::string utohexstr(uint64_t X, bool LowerCase = false) { + char Buffer[17]; + char *BufPtr = std::end(Buffer); + + if (X == 0) *--BufPtr = '0'; while (X) { unsigned char Mod = static_cast<unsigned char>(X) & 15; *--BufPtr = hexdigit(Mod, LowerCase); X >>= 4; } - return BufPtr; -} -static inline std::string utohexstr(uint64_t X, bool LowerCase = false) { - char Buffer[17]; - return utohex_buffer(X, Buffer+17, LowerCase); + return std::string(BufPtr, std::end(Buffer)); } -static inline std::string utostr_32(uint32_t X, bool isNeg = false) { - char Buffer[11]; - char *BufPtr = Buffer+11; - - if (X == 0) *--BufPtr = '0'; // Handle special case... - - while (X) { - *--BufPtr = '0' + char(X % 10); - X /= 10; +/// Convert buffer \p Input to its hexadecimal representation. +/// The returned string is double the size of \p Input. +static inline std::string toHex(StringRef Input) { + static const char *const LUT = "0123456789ABCDEF"; + size_t Length = Input.size(); + + std::string Output; + Output.reserve(2 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Input[i]; + Output.push_back(LUT[c >> 4]); + Output.push_back(LUT[c & 15]); } - - if (isNeg) *--BufPtr = '-'; // Add negative sign... - - return std::string(BufPtr, Buffer+11); + return Output; } static inline std::string utostr(uint64_t X, bool isNeg = false) { char Buffer[21]; - char *BufPtr = Buffer+21; + char *BufPtr = std::end(Buffer); if (X == 0) *--BufPtr = '0'; // Handle special case... @@ -102,7 +87,7 @@ static inline std::string utostr(uint64_t X, bool isNeg = false) { } if (isNeg) *--BufPtr = '-'; // Add negative sign... - return std::string(BufPtr, Buffer+21); + return std::string(BufPtr, std::end(Buffer)); } diff --git a/include/llvm/ADT/StringMap.h b/include/llvm/ADT/StringMap.h index 700bb9e10ef7..260275295c99 100644 --- a/include/llvm/ADT/StringMap.h +++ b/include/llvm/ADT/StringMap.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/PointerLikeTypeTraits.h" #include <cstring> #include <utility> @@ -88,12 +89,15 @@ protected: /// table, returning it. If the key is not in the table, this returns null. StringMapEntryBase *RemoveKey(StringRef Key); -private: + /// Allocate the table with the specified number of buckets and otherwise + /// setup the map as empty. void init(unsigned Size); public: static StringMapEntryBase *getTombstoneVal() { - return (StringMapEntryBase*)-1; + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable; + return reinterpret_cast<StringMapEntryBase *>(Val); } unsigned getNumBuckets() const { return NumBuckets; } @@ -122,9 +126,9 @@ public: explicit StringMapEntry(unsigned strLen) : StringMapEntryBase(strLen), second() {} - template <class InitTy> - StringMapEntry(unsigned strLen, InitTy &&V) - : StringMapEntryBase(strLen), second(std::forward<InitTy>(V)) {} + template <typename... InitTy> + StringMapEntry(unsigned strLen, InitTy &&... InitVals) + : StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {} StringRef getKey() const { return StringRef(getKeyData(), getKeyLength()); @@ -142,11 +146,11 @@ public: StringRef first() const { return StringRef(getKeyData(), getKeyLength()); } - /// Create - Create a StringMapEntry for the specified key and default - /// construct the value. - template <typename AllocatorTy, typename InitType> + /// Create a StringMapEntry for the specified key construct the value using + /// \p InitiVals. + template <typename AllocatorTy, typename... InitTy> static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator, - InitType &&InitVal) { + InitTy &&... InitVals) { unsigned KeyLength = Key.size(); // Allocate a new item with space for the string at the end and a null @@ -158,8 +162,8 @@ public: StringMapEntry *NewItem = static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment)); - // Default construct the value. - new (NewItem) StringMapEntry(KeyLength, std::forward<InitType>(InitVal)); + // Construct the value. + new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...); // Copy the string information. char *StrBuffer = const_cast<char*>(NewItem->getKeyData()); @@ -169,16 +173,11 @@ public: return NewItem; } - template<typename AllocatorTy> - static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator) { - return Create(Key, Allocator, ValueTy()); - } - /// Create - Create a StringMapEntry with normal malloc/free. - template<typename InitType> - static StringMapEntry *Create(StringRef Key, InitType &&InitVal) { + template <typename... InitType> + static StringMapEntry *Create(StringRef Key, InitType &&... InitVal) { MallocAllocator A; - return Create(Key, A, std::forward<InitType>(InitVal)); + return Create(Key, A, std::forward<InitType>(InitVal)...); } static StringMapEntry *Create(StringRef Key) { @@ -233,7 +232,7 @@ public: Allocator(A) {} StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List) - : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) { + : StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) { for (const auto &P : List) { insert(P); } @@ -248,7 +247,40 @@ public: return *this; } - // FIXME: Implement copy operations if/when they're needed. + StringMap(const StringMap &RHS) : + StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), + Allocator(RHS.Allocator) { + if (RHS.empty()) + return; + + // Allocate TheTable of the same size as RHS's TheTable, and set the + // sentinel appropriately (and NumBuckets). + init(RHS.NumBuckets); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1), + *RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1); + + NumItems = RHS.NumItems; + NumTombstones = RHS.NumTombstones; + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = RHS.TheTable[I]; + if (!Bucket || Bucket == getTombstoneVal()) { + TheTable[I] = Bucket; + continue; + } + + TheTable[I] = MapEntryTy::Create( + static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator, + static_cast<MapEntryTy *>(Bucket)->getValue()); + HashTable[I] = RHSHashTable[I]; + } + + // Note that here we've copied everything from the RHS into this object, + // tombstones included. We could, instead, have re-probed for each key to + // instantiate this new object without any tombstone buckets. The + // assumption here is that items are rarely deleted from most StringMaps, + // and so tombstones are rare, so the cost of re-probing for all inputs is + // not worthwhile. + } AllocatorTy &getAllocator() { return Allocator; } const AllocatorTy &getAllocator() const { return Allocator; } @@ -295,8 +327,10 @@ public: return ValueTy(); } + /// Lookup the ValueTy for the \p Key, or create a default constructed value + /// if the key is not in the map. ValueTy &operator[](StringRef Key) { - return insert(std::make_pair(Key, ValueTy())).first->second; + return emplace_second(Key).first->second; } /// count - Return 1 if the element is in the map, 0 otherwise. @@ -328,7 +362,16 @@ public: /// if and only if the insertion takes place, and the iterator component of /// the pair points to the element with key equivalent to the key of the pair. std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) { - unsigned BucketNo = LookupBucketFor(KV.first); + return emplace_second(KV.first, std::move(KV.second)); + } + + /// Emplace a new element for the specified key into the map if the key isn't + /// already in the map. The bool component of the returned pair is true + /// if and only if the insertion takes place, and the iterator component of + /// the pair points to the element with key equivalent to the key of the pair. + template <typename... ArgsTy> + std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) { + unsigned BucketNo = LookupBucketFor(Key); StringMapEntryBase *&Bucket = TheTable[BucketNo]; if (Bucket && Bucket != getTombstoneVal()) return std::make_pair(iterator(TheTable + BucketNo, false), @@ -336,8 +379,7 @@ public: if (Bucket == getTombstoneVal()) --NumTombstones; - Bucket = - MapEntryTy::Create(KV.first, Allocator, std::move(KV.second)); + Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...); ++NumItems; assert(NumItems + NumTombstones <= NumBuckets); diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index 350032b8c4e7..398ca6920249 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -10,6 +10,7 @@ #ifndef LLVM_ADT_STRINGREF_H #define LLVM_ADT_STRINGREF_H +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include <algorithm> #include <cassert> @@ -101,6 +102,9 @@ namespace llvm { const unsigned char *bytes_end() const { return reinterpret_cast<const unsigned char *>(end()); } + iterator_range<const unsigned char *> bytes() const { + return make_range(bytes_begin(), bytes_end()); + } /// @} /// @name String Operations @@ -133,6 +137,9 @@ namespace llvm { // copy - Allocate copy in Allocator and return StringRef to it. template <typename Allocator> StringRef copy(Allocator &A) const { + // Don't request a length 0 copy from the allocator. + if (empty()) + return StringRef(); char *S = A.template Allocate<char>(Length); std::copy(begin(), end(), S); return StringRef(S, Length); @@ -443,9 +450,10 @@ namespace llvm { /// empty substring will be returned. /// /// \param End The index following the last character to include in the - /// substring. If this is npos, or less than \p Start, or exceeds the - /// number of characters remaining in the string, the string suffix - /// (starting with \p Start) will be returned. + /// substring. If this is npos or exceeds the number of characters + /// remaining in the string, the string suffix (starting with \p Start) + /// will be returned. If this is less than \p Start, an empty string will + /// be returned. LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef slice(size_t Start, size_t End) const { Start = std::min(Start, Length); @@ -539,18 +547,36 @@ namespace llvm { return std::make_pair(slice(0, Idx), slice(Idx+1, npos)); } + /// Return string with consecutive \p Char characters starting from the + /// the left removed. + StringRef ltrim(char Char) const { + return drop_front(std::min(Length, find_first_not_of(Char))); + } + /// Return string with consecutive characters in \p Chars starting from /// the left removed. StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const { return drop_front(std::min(Length, find_first_not_of(Chars))); } + /// Return string with consecutive \p Char characters starting from the + /// right removed. + StringRef rtrim(char Char) const { + return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1)); + } + /// Return string with consecutive characters in \p Chars starting from /// the right removed. StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const { return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1)); } + /// Return string with consecutive \p Char characters starting from the + /// left and right removed. + StringRef trim(char Char) const { + return ltrim(Char).rtrim(Char); + } + /// Return string with consecutive characters in \p Chars starting from /// the left and right removed. StringRef trim(StringRef Chars = " \t\n\v\f\r") const { diff --git a/include/llvm/ADT/StringSet.h b/include/llvm/ADT/StringSet.h index 08626dc7af84..c32c2a497438 100644 --- a/include/llvm/ADT/StringSet.h +++ b/include/llvm/ADT/StringSet.h @@ -33,6 +33,12 @@ namespace llvm { assert(!Key.empty()); return base::insert(std::make_pair(Key, '\0')); } + + template <typename InputIt> + void insert(const InputIt &Begin, const InputIt &End) { + for (auto It = Begin; It != End; ++It) + base::insert(std::make_pair(*It, '\0')); + } }; } diff --git a/include/llvm/ADT/TinyPtrVector.h b/include/llvm/ADT/TinyPtrVector.h index 487aa46cf642..605f0e70a857 100644 --- a/include/llvm/ADT/TinyPtrVector.h +++ b/include/llvm/ADT/TinyPtrVector.h @@ -104,8 +104,16 @@ public: /// This also is a constructor for individual array elements due to the single /// element constructor for ArrayRef. explicit TinyPtrVector(ArrayRef<EltTy> Elts) - : Val(Elts.size() == 1 ? PtrUnion(Elts[0]) - : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {} + : Val(Elts.empty() + ? PtrUnion() + : Elts.size() == 1 + ? PtrUnion(Elts[0]) + : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {} + + TinyPtrVector(size_t Count, EltTy Value) + : Val(Count == 0 ? PtrUnion() + : Count == 1 ? PtrUnion(Value) + : PtrUnion(new VecTy(Count, Value))) {} // implicit conversion operator to ArrayRef. operator ArrayRef<EltTy>() const { @@ -125,6 +133,15 @@ public: return *Val.template get<VecTy*>(); } + // Implicit conversion to ArrayRef<U> if EltTy* implicitly converts to U*. + template<typename U, + typename std::enable_if< + std::is_convertible<ArrayRef<EltTy>, ArrayRef<U>>::value, + bool>::type = false> + operator ArrayRef<U>() const { + return operator ArrayRef<EltTy>(); + } + bool empty() const { // This vector can be empty if it contains no element, or if it // contains a pointer to an empty vector. @@ -142,8 +159,10 @@ public: return Val.template get<VecTy*>()->size(); } - typedef const EltTy *const_iterator; typedef EltTy *iterator; + typedef const EltTy *const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; iterator begin() { if (Val.template is<EltTy>()) @@ -166,6 +185,15 @@ public: return (const_iterator)const_cast<TinyPtrVector*>(this)->end(); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + EltTy operator[](unsigned i) const { assert(!Val.isNull() && "can't index into an empty vector"); if (EltTy V = Val.template dyn_cast<EltTy>()) { diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index e01db0a61fd5..47813049d2f2 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -46,49 +46,52 @@ public: enum ArchType { UnknownArch, - arm, // ARM (little endian): arm, armv.*, xscale - armeb, // ARM (big endian): armeb - aarch64, // AArch64 (little endian): aarch64 - aarch64_be, // AArch64 (big endian): aarch64_be - avr, // AVR: Atmel AVR microcontroller - bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) - bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) - hexagon, // Hexagon: hexagon - mips, // MIPS: mips, mipsallegrex - mipsel, // MIPSEL: mipsel, mipsallegrexel - mips64, // MIPS64: mips64 - mips64el, // MIPS64EL: mips64el - msp430, // MSP430: msp430 - ppc, // PPC: powerpc - ppc64, // PPC64: powerpc64, ppu - ppc64le, // PPC64LE: powerpc64le - r600, // R600: AMD GPUs HD2XXX - HD6XXX - amdgcn, // AMDGCN: AMD GCN GPUs - sparc, // Sparc: sparc - sparcv9, // Sparcv9: Sparcv9 - sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant - systemz, // SystemZ: s390x - tce, // TCE (http://tce.cs.tut.fi/): tce - thumb, // Thumb (little endian): thumb, thumbv.* - thumbeb, // Thumb (big endian): thumbeb - x86, // X86: i[3-9]86 - x86_64, // X86-64: amd64, x86_64 - xcore, // XCore: xcore - nvptx, // NVPTX: 32-bit - nvptx64, // NVPTX: 64-bit - le32, // le32: generic little-endian 32-bit CPU (PNaCl) - le64, // le64: generic little-endian 64-bit CPU (PNaCl) - amdil, // AMDIL - amdil64, // AMDIL with 64-bit pointers - hsail, // AMD HSAIL - hsail64, // AMD HSAIL with 64-bit pointers - spir, // SPIR: standard portable IR for OpenCL 32-bit version - spir64, // SPIR: standard portable IR for OpenCL 64-bit version - kalimba, // Kalimba: generic kalimba - shave, // SHAVE: Movidius vector VLIW processors - wasm32, // WebAssembly with 32-bit pointers - wasm64, // WebAssembly with 64-bit pointers - LastArchType = wasm64 + arm, // ARM (little endian): arm, armv.*, xscale + armeb, // ARM (big endian): armeb + aarch64, // AArch64 (little endian): aarch64 + aarch64_be, // AArch64 (big endian): aarch64_be + avr, // AVR: Atmel AVR microcontroller + bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) + bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) + hexagon, // Hexagon: hexagon + mips, // MIPS: mips, mipsallegrex + mipsel, // MIPSEL: mipsel, mipsallegrexel + mips64, // MIPS64: mips64 + mips64el, // MIPS64EL: mips64el + msp430, // MSP430: msp430 + ppc, // PPC: powerpc + ppc64, // PPC64: powerpc64, ppu + ppc64le, // PPC64LE: powerpc64le + r600, // R600: AMD GPUs HD2XXX - HD6XXX + amdgcn, // AMDGCN: AMD GCN GPUs + sparc, // Sparc: sparc + sparcv9, // Sparcv9: Sparcv9 + sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant + systemz, // SystemZ: s390x + tce, // TCE (http://tce.cs.tut.fi/): tce + thumb, // Thumb (little endian): thumb, thumbv.* + thumbeb, // Thumb (big endian): thumbeb + x86, // X86: i[3-9]86 + x86_64, // X86-64: amd64, x86_64 + xcore, // XCore: xcore + nvptx, // NVPTX: 32-bit + nvptx64, // NVPTX: 64-bit + le32, // le32: generic little-endian 32-bit CPU (PNaCl) + le64, // le64: generic little-endian 64-bit CPU (PNaCl) + amdil, // AMDIL + amdil64, // AMDIL with 64-bit pointers + hsail, // AMD HSAIL + hsail64, // AMD HSAIL with 64-bit pointers + spir, // SPIR: standard portable IR for OpenCL 32-bit version + spir64, // SPIR: standard portable IR for OpenCL 64-bit version + kalimba, // Kalimba: generic kalimba + shave, // SHAVE: Movidius vector VLIW processors + lanai, // Lanai: Lanai 32-bit + wasm32, // WebAssembly with 32-bit pointers + wasm64, // WebAssembly with 64-bit pointers + renderscript32, // 32-bit RenderScript + renderscript64, // 64-bit RenderScript + LastArchType = renderscript64 }; enum SubArchType { NoSubArch, @@ -96,6 +99,8 @@ public: ARMSubArch_v8_2a, ARMSubArch_v8_1a, ARMSubArch_v8, + ARMSubArch_v8m_baseline, + ARMSubArch_v8m_mainline, ARMSubArch_v7, ARMSubArch_v7em, ARMSubArch_v7m, @@ -128,7 +133,9 @@ public: NVIDIA, CSR, Myriad, - LastVendorType = Myriad + AMD, + Mesa, + LastVendorType = Mesa }; enum OSType { UnknownOS, @@ -160,7 +167,8 @@ public: ELFIAMCU, TvOS, // Apple tvOS WatchOS, // Apple watchOS - LastOSType = WatchOS + Mesa3D, + LastOSType = Mesa3D }; enum EnvironmentType { UnknownEnvironment, @@ -173,6 +181,9 @@ public: EABI, EABIHF, Android, + Musl, + MuslEABI, + MuslEABIHF, MSVC, Itanium, @@ -390,8 +401,8 @@ public: /// isMacOSXVersionLT - Comparison function for checking OS X version /// compatibility, which handles supporting skewed version numbering schemes /// used by the "darwin" triples. - unsigned isMacOSXVersionLT(unsigned Major, unsigned Minor = 0, - unsigned Micro = 0) const { + bool isMacOSXVersionLT(unsigned Major, unsigned Minor = 0, + unsigned Micro = 0) const { assert(isMacOSX() && "Not an OS X triple!"); // If this is OS X, expect a sane version number. @@ -428,6 +439,10 @@ public: return getOS() == Triple::WatchOS; } + bool isWatchABI() const { + return getSubArch() == Triple::ARMSubArch_v7k; + } + /// isOSDarwin - Is this a "Darwin" OS (OS X, iOS, or watchOS). bool isOSDarwin() const { return isMacOSX() || isiOS() || isWatchOS(); @@ -459,6 +474,12 @@ public: return getOS() == Triple::ELFIAMCU; } + bool isGNUEnvironment() const { + EnvironmentType Env = getEnvironment(); + return Env == Triple::GNU || Env == Triple::GNUEABI || + Env == Triple::GNUEABIHF || Env == Triple::GNUX32; + } + /// Checks if the environment could be MSVC. bool isWindowsMSVCEnvironment() const { return getOS() == Triple::Win32 && @@ -513,6 +534,16 @@ public: return getOS() == Triple::Linux; } + /// Tests whether the OS is kFreeBSD. + bool isOSKFreeBSD() const { + return getOS() == Triple::KFreeBSD; + } + + /// Tests whether the OS uses glibc. + bool isOSGlibc() const { + return getOS() == Triple::Linux || getOS() == Triple::KFreeBSD; + } + /// Tests whether the OS uses the ELF binary format. bool isOSBinFormatELF() const { return getObjectFormat() == Triple::ELF; @@ -544,6 +575,21 @@ public: /// Tests whether the target is Android bool isAndroid() const { return getEnvironment() == Triple::Android; } + /// Tests whether the environment is musl-libc + bool isMusl() const { + return getEnvironment() == Triple::Musl || + getEnvironment() == Triple::MuslEABI || + getEnvironment() == Triple::MuslEABIHF; + } + + /// Tests whether the target is NVPTX (32- or 64-bit). + bool isNVPTX() const { + return getArch() == Triple::nvptx || getArch() == Triple::nvptx64; + } + + /// Tests wether the target supports comdat + bool supportsCOMDAT() const { return !isOSBinFormatMachO(); } + /// @} /// @name Mutators /// @{ @@ -632,6 +678,11 @@ public: /// string then the triple's arch name is used. StringRef getARMCPUForArch(StringRef Arch = StringRef()) const; + /// Tests whether the target triple is little endian. + /// + /// \returns true if the triple is little endian, false otherwise. + bool isLittleEndian() const; + /// @} /// @name Static helpers for IDs. /// @{ diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index 3044a6c435f1..8e4d45dfef22 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -186,53 +186,38 @@ template<typename Ty> struct ilist_traits<const Ty> : public ilist_traits<Ty> {}; //===----------------------------------------------------------------------===// -// ilist_iterator<Node> - Iterator for intrusive list. +// Iterator for intrusive list. // -template<typename NodeTy> +template <typename NodeTy> class ilist_iterator - : public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> { - + : public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> { public: typedef ilist_traits<NodeTy> Traits; - typedef std::iterator<std::bidirectional_iterator_tag, - NodeTy, ptrdiff_t> super; + typedef std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> + super; typedef typename super::value_type value_type; typedef typename super::difference_type difference_type; typedef typename super::pointer pointer; typedef typename super::reference reference; + private: pointer NodePtr; - // ilist_iterator is not a random-access iterator, but it has an - // implicit conversion to pointer-type, which is. Declare (but - // don't define) these functions as private to help catch - // accidental misuse. - void operator[](difference_type) const; - void operator+(difference_type) const; - void operator-(difference_type) const; - void operator+=(difference_type) const; - void operator-=(difference_type) const; - template<class T> void operator<(T) const; - template<class T> void operator<=(T) const; - template<class T> void operator>(T) const; - template<class T> void operator>=(T) const; - template<class T> void operator-(T) const; public: - explicit ilist_iterator(pointer NP) : NodePtr(NP) {} explicit ilist_iterator(reference NR) : NodePtr(&NR) {} ilist_iterator() : NodePtr(nullptr) {} // This is templated so that we can allow constructing a const iterator from // a nonconst iterator... - template<class node_ty> + template <class node_ty> ilist_iterator(const ilist_iterator<node_ty> &RHS) - : NodePtr(RHS.getNodePtrUnchecked()) {} + : NodePtr(RHS.getNodePtrUnchecked()) {} // This is templated so that we can allow assigning to a const iterator from // a nonconst iterator... - template<class node_ty> + template <class node_ty> const ilist_iterator &operator=(const ilist_iterator<node_ty> &RHS) { NodePtr = RHS.getNodePtrUnchecked(); return *this; @@ -241,13 +226,8 @@ public: void reset(pointer NP) { NodePtr = NP; } // Accessors... - explicit operator pointer() const { - return NodePtr; - } - - reference operator*() const { - return *NodePtr; - } + explicit operator pointer() const { return NodePtr; } + reference operator*() const { return *NodePtr; } pointer operator->() const { return &operator*(); } // Comparison operators @@ -259,21 +239,21 @@ public: } // Increment and decrement operators... - ilist_iterator &operator--() { // predecrement - Back up + ilist_iterator &operator--() { NodePtr = Traits::getPrev(NodePtr); assert(NodePtr && "--'d off the beginning of an ilist!"); return *this; } - ilist_iterator &operator++() { // preincrement - Advance + ilist_iterator &operator++() { NodePtr = Traits::getNext(NodePtr); return *this; } - ilist_iterator operator--(int) { // postdecrement operators... + ilist_iterator operator--(int) { ilist_iterator tmp = *this; --*this; return tmp; } - ilist_iterator operator++(int) { // postincrement operators... + ilist_iterator operator++(int) { ilist_iterator tmp = *this; ++*this; return tmp; @@ -283,38 +263,6 @@ public: pointer getNodePtrUnchecked() const { return NodePtr; } }; -// These are to catch errors when people try to use them as random access -// iterators. -template<typename T> -void operator-(int, ilist_iterator<T>) = delete; -template<typename T> -void operator-(ilist_iterator<T>,int) = delete; - -template<typename T> -void operator+(int, ilist_iterator<T>) = delete; -template<typename T> -void operator+(ilist_iterator<T>,int) = delete; - -// operator!=/operator== - Allow mixed comparisons without dereferencing -// the iterator, which could very likely be pointing to end(). -template<typename T> -bool operator!=(const T* LHS, const ilist_iterator<const T> &RHS) { - return LHS != RHS.getNodePtrUnchecked(); -} -template<typename T> -bool operator==(const T* LHS, const ilist_iterator<const T> &RHS) { - return LHS == RHS.getNodePtrUnchecked(); -} -template<typename T> -bool operator!=(T* LHS, const ilist_iterator<T> &RHS) { - return LHS != RHS.getNodePtrUnchecked(); -} -template<typename T> -bool operator==(T* LHS, const ilist_iterator<T> &RHS) { - return LHS == RHS.getNodePtrUnchecked(); -} - - // Allow ilist_iterators to convert into pointers to a node automatically when // used by the dyn_cast, cast, isa mechanisms... @@ -474,6 +422,10 @@ public: return iterator(New); } + iterator insert(iterator where, const NodeTy &New) { + return this->insert(where, new NodeTy(New)); + } + iterator insertAfter(iterator where, NodeTy *New) { if (empty()) return insert(begin(), New); @@ -720,7 +672,7 @@ struct ilist : public iplist<NodeTy> { typedef typename iplist<NodeTy>::iterator iterator; ilist() {} - ilist(const ilist &right) { + ilist(const ilist &right) : iplist<NodeTy>() { insert(this->begin(), right.begin(), right.end()); } explicit ilist(size_type count) { diff --git a/include/llvm/ADT/iterator.h b/include/llvm/ADT/iterator.h index c30792892703..2898a677db37 100644 --- a/include/llvm/ADT/iterator.h +++ b/include/llvm/ADT/iterator.h @@ -46,6 +46,22 @@ protected: std::is_base_of<std::bidirectional_iterator_tag, IteratorCategoryT>::value, }; + /// A proxy object for computing a reference via indirecting a copy of an + /// iterator. This is used in APIs which need to produce a reference via + /// indirection but for which the iterator object might be a temporary. The + /// proxy preserves the iterator internally and exposes the indirected + /// reference via a conversion operator. + class ReferenceProxy { + friend iterator_facade_base; + + DerivedT I; + + ReferenceProxy(DerivedT I) : I(std::move(I)) {} + + public: + operator ReferenceT() const { return *I; } + }; + public: DerivedT operator+(DifferenceTypeT n) const { static_assert( @@ -120,10 +136,10 @@ public: PointerT operator->() const { return &static_cast<const DerivedT *>(this)->operator*(); } - ReferenceT operator[](DifferenceTypeT n) const { + ReferenceProxy operator[](DifferenceTypeT n) const { static_assert(IsRandomAccess, "Subscripting is only defined for random access iterators."); - return *static_cast<const DerivedT *>(this)->operator+(n); + return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n)); } }; diff --git a/include/llvm/Analysis/AliasAnalysis.h b/include/llvm/Analysis/AliasAnalysis.h index 5cc840a64a62..d6308b7073a0 100644 --- a/include/llvm/Analysis/AliasAnalysis.h +++ b/include/llvm/Analysis/AliasAnalysis.h @@ -38,11 +38,11 @@ #ifndef LLVM_ANALYSIS_ALIASANALYSIS_H #define LLVM_ANALYSIS_ALIASANALYSIS_H -#include "llvm/ADT/DenseMap.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PassManager.h" #include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/TargetLibraryInfo.h" namespace llvm { class BasicAAResult; @@ -50,7 +50,6 @@ class LoadInst; class StoreInst; class VAArgInst; class DataLayout; -class TargetLibraryInfo; class Pass; class AnalysisUsage; class MemTransferInst; @@ -141,7 +140,7 @@ enum FunctionModRefBehavior { /// non-volatile loads and stores from objects pointed to by its /// pointer-typed arguments, with arbitrary offsets. /// - /// This property corresponds to the IntrReadWriteArgMem LLVM intrinsic flag. + /// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag. FMRB_OnlyAccessesArgumentPointees = FMRL_ArgumentPointees | MRI_ModRef, /// This function does not perform any non-local stores or volatile loads, @@ -152,6 +151,13 @@ enum FunctionModRefBehavior { /// This property corresponds to the IntrReadMem LLVM intrinsic flag. FMRB_OnlyReadsMemory = FMRL_Anywhere | MRI_Ref, + // This function does not read from memory anywhere, but may write to any + // memory location. + // + // This property corresponds to the LLVM IR 'writeonly' attribute. + // This property corresponds to the IntrWriteMem LLVM intrinsic flag. + FMRB_DoesNotReadMemory = FMRL_Anywhere | MRI_Mod, + /// This indicates that the function could not be classified into one of the /// behaviors above. FMRB_UnknownModRefBehavior = FMRL_Anywhere | MRI_ModRef @@ -161,9 +167,8 @@ class AAResults { public: // Make these results default constructable and movable. We have to spell // these out because MSVC won't synthesize them. - AAResults() {} + AAResults(const TargetLibraryInfo &TLI) : TLI(TLI) {} AAResults(AAResults &&Arg); - AAResults &operator=(AAResults &&Arg); ~AAResults(); /// Register a specific AA result. @@ -314,6 +319,12 @@ public: return !(MRB & MRI_Mod); } + /// Checks if functions with the specified behavior are known to only write + /// memory (or not access memory at all). + static bool doesNotReadMemory(FunctionModRefBehavior MRB) { + return !(MRB & MRI_Ref); + } + /// Checks if functions with the specified behavior are known to read and /// write at most from objects pointed to by their pointer-typed arguments /// (with arbitrary offsets). @@ -450,11 +461,11 @@ public: ModRefInfo getModRefInfo(const Instruction *I) { if (auto CS = ImmutableCallSite(I)) { auto MRB = getModRefBehavior(CS); - if (MRB & MRI_ModRef) + if ((MRB & MRI_ModRef) == MRI_ModRef) return MRI_ModRef; - else if (MRB & MRI_Ref) + if (MRB & MRI_Ref) return MRI_Ref; - else if (MRB & MRI_Mod) + if (MRB & MRI_Mod) return MRI_Mod; return MRI_NoModRef; } @@ -557,6 +568,8 @@ private: template <typename T> friend class AAResultBase; + const TargetLibraryInfo &TLI; + std::vector<std::unique_ptr<Concept>> AAs; }; @@ -753,20 +766,23 @@ protected: } }; - const TargetLibraryInfo &TLI; - - explicit AAResultBase(const TargetLibraryInfo &TLI) : TLI(TLI) {} + explicit AAResultBase() {} // Provide all the copy and move constructors so that derived types aren't // constrained. - AAResultBase(const AAResultBase &Arg) : TLI(Arg.TLI) {} - AAResultBase(AAResultBase &&Arg) : TLI(Arg.TLI) {} + AAResultBase(const AAResultBase &Arg) {} + AAResultBase(AAResultBase &&Arg) {} /// Get a proxy for the best AA result set to query at this time. /// /// When this result is part of a larger aggregation, this will proxy to that /// aggregation. When this result is used in isolation, it will just delegate /// back to the derived class's implementation. + /// + /// Note that callers of this need to take considerable care to not cause + /// performance problems when they use this routine, in the case of a large + /// number of alias analyses being aggregated, it can be expensive to walk + /// back across the chain. AAResultsProxy getBestAAResults() { return AAResultsProxy(AAR, derived()); } public: @@ -783,13 +799,6 @@ public: } FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) { - if (!CS.hasOperandBundles()) - // If CS has operand bundles then aliasing attributes from the function it - // calls do not directly apply to the CallSite. This can be made more - // precise in the future. - if (const Function *F = CS.getCalledFunction()) - return getBestAAResults().getModRefBehavior(F); - return FMRB_UnknownModRefBehavior; } @@ -797,170 +806,24 @@ public: return FMRB_UnknownModRefBehavior; } - ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc); - - ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2); -}; - -/// Synthesize \c ModRefInfo for a call site and memory location by examining -/// the general behavior of the call site and any specific information for its -/// arguments. -/// -/// This essentially, delegates across the alias analysis interface to collect -/// information which may be enough to (conservatively) fulfill the query. -template <typename DerivedT> -ModRefInfo AAResultBase<DerivedT>::getModRefInfo(ImmutableCallSite CS, - const MemoryLocation &Loc) { - auto MRB = getBestAAResults().getModRefBehavior(CS); - if (MRB == FMRB_DoesNotAccessMemory) - return MRI_NoModRef; - - ModRefInfo Mask = MRI_ModRef; - if (AAResults::onlyReadsMemory(MRB)) - Mask = MRI_Ref; - - if (AAResults::onlyAccessesArgPointees(MRB)) { - bool DoesAlias = false; - ModRefInfo AllArgsMask = MRI_NoModRef; - if (AAResults::doesAccessArgPointees(MRB)) { - for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), - AE = CS.arg_end(); - AI != AE; ++AI) { - const Value *Arg = *AI; - if (!Arg->getType()->isPointerTy()) - continue; - unsigned ArgIdx = std::distance(CS.arg_begin(), AI); - MemoryLocation ArgLoc = MemoryLocation::getForArgument(CS, ArgIdx, TLI); - AliasResult ArgAlias = getBestAAResults().alias(ArgLoc, Loc); - if (ArgAlias != NoAlias) { - ModRefInfo ArgMask = getBestAAResults().getArgModRefInfo(CS, ArgIdx); - DoesAlias = true; - AllArgsMask = ModRefInfo(AllArgsMask | ArgMask); - } - } - } - if (!DoesAlias) - return MRI_NoModRef; - Mask = ModRefInfo(Mask & AllArgsMask); - } - - // If Loc is a constant memory location, the call definitely could not - // modify the memory location. - if ((Mask & MRI_Mod) && - getBestAAResults().pointsToConstantMemory(Loc, /*OrLocal*/ false)) - Mask = ModRefInfo(Mask & ~MRI_Mod); - - return Mask; -} - -/// Synthesize \c ModRefInfo for two call sites by examining the general -/// behavior of the call site and any specific information for its arguments. -/// -/// This essentially, delegates across the alias analysis interface to collect -/// information which may be enough to (conservatively) fulfill the query. -template <typename DerivedT> -ModRefInfo AAResultBase<DerivedT>::getModRefInfo(ImmutableCallSite CS1, - ImmutableCallSite CS2) { - // If CS1 or CS2 are readnone, they don't interact. - auto CS1B = getBestAAResults().getModRefBehavior(CS1); - if (CS1B == FMRB_DoesNotAccessMemory) - return MRI_NoModRef; - - auto CS2B = getBestAAResults().getModRefBehavior(CS2); - if (CS2B == FMRB_DoesNotAccessMemory) - return MRI_NoModRef; - - // If they both only read from memory, there is no dependence. - if (AAResults::onlyReadsMemory(CS1B) && AAResults::onlyReadsMemory(CS2B)) - return MRI_NoModRef; - - ModRefInfo Mask = MRI_ModRef; - - // If CS1 only reads memory, the only dependence on CS2 can be - // from CS1 reading memory written by CS2. - if (AAResults::onlyReadsMemory(CS1B)) - Mask = ModRefInfo(Mask & MRI_Ref); - - // If CS2 only access memory through arguments, accumulate the mod/ref - // information from CS1's references to the memory referenced by - // CS2's arguments. - if (AAResults::onlyAccessesArgPointees(CS2B)) { - ModRefInfo R = MRI_NoModRef; - if (AAResults::doesAccessArgPointees(CS2B)) { - for (ImmutableCallSite::arg_iterator I = CS2.arg_begin(), - E = CS2.arg_end(); - I != E; ++I) { - const Value *Arg = *I; - if (!Arg->getType()->isPointerTy()) - continue; - unsigned CS2ArgIdx = std::distance(CS2.arg_begin(), I); - auto CS2ArgLoc = MemoryLocation::getForArgument(CS2, CS2ArgIdx, TLI); - - // ArgMask indicates what CS2 might do to CS2ArgLoc, and the dependence - // of CS1 on that location is the inverse. - ModRefInfo ArgMask = - getBestAAResults().getArgModRefInfo(CS2, CS2ArgIdx); - if (ArgMask == MRI_Mod) - ArgMask = MRI_ModRef; - else if (ArgMask == MRI_Ref) - ArgMask = MRI_Mod; - - ArgMask = ModRefInfo(ArgMask & - getBestAAResults().getModRefInfo(CS1, CS2ArgLoc)); - - R = ModRefInfo((R | ArgMask) & Mask); - if (R == Mask) - break; - } - } - return R; + ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc) { + return MRI_ModRef; } - // If CS1 only accesses memory through arguments, check if CS2 references - // any of the memory referenced by CS1's arguments. If not, return NoModRef. - if (AAResults::onlyAccessesArgPointees(CS1B)) { - ModRefInfo R = MRI_NoModRef; - if (AAResults::doesAccessArgPointees(CS1B)) { - for (ImmutableCallSite::arg_iterator I = CS1.arg_begin(), - E = CS1.arg_end(); - I != E; ++I) { - const Value *Arg = *I; - if (!Arg->getType()->isPointerTy()) - continue; - unsigned CS1ArgIdx = std::distance(CS1.arg_begin(), I); - auto CS1ArgLoc = MemoryLocation::getForArgument(CS1, CS1ArgIdx, TLI); - - // ArgMask indicates what CS1 might do to CS1ArgLoc; if CS1 might Mod - // CS1ArgLoc, then we care about either a Mod or a Ref by CS2. If CS1 - // might Ref, then we care only about a Mod by CS2. - ModRefInfo ArgMask = getBestAAResults().getArgModRefInfo(CS1, CS1ArgIdx); - ModRefInfo ArgR = getBestAAResults().getModRefInfo(CS2, CS1ArgLoc); - if (((ArgMask & MRI_Mod) != MRI_NoModRef && - (ArgR & MRI_ModRef) != MRI_NoModRef) || - ((ArgMask & MRI_Ref) != MRI_NoModRef && - (ArgR & MRI_Mod) != MRI_NoModRef)) - R = ModRefInfo((R | ArgMask) & Mask); - - if (R == Mask) - break; - } - } - return R; + ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { + return MRI_ModRef; } +}; - return Mask; -} -/// isNoAliasCall - Return true if this pointer is returned by a noalias -/// function. +/// Return true if this pointer is returned by a noalias function. bool isNoAliasCall(const Value *V); -/// isNoAliasArgument - Return true if this is an argument with the noalias -/// attribute. +/// Return true if this is an argument with the noalias attribute. bool isNoAliasArgument(const Value *V); -/// isIdentifiedObject - Return true if this pointer refers to a distinct and -/// identifiable object. This returns true for: +/// Return true if this pointer refers to a distinct and identifiable object. +/// This returns true for: /// Global Variables and Functions (but not Global Aliases) /// Allocas /// ByVal and NoAlias Arguments @@ -968,8 +831,8 @@ bool isNoAliasArgument(const Value *V); /// bool isIdentifiedObject(const Value *V); -/// isIdentifiedFunctionLocal - Return true if V is umabigously identified -/// at the function-level. Different IdentifiedFunctionLocals can't alias. +/// Return true if V is umabigously identified at the function-level. +/// Different IdentifiedFunctionLocals can't alias. /// Further, an IdentifiedFunctionLocal can not alias with any function /// arguments other than itself, which is not necessarily true for /// IdentifiedObjects. @@ -987,42 +850,48 @@ bool isIdentifiedFunctionLocal(const Value *V); /// This manager effectively wraps the AnalysisManager for registering alias /// analyses. When you register your alias analysis with this manager, it will /// ensure the analysis itself is registered with its AnalysisManager. -class AAManager { +class AAManager : public AnalysisInfoMixin<AAManager> { public: typedef AAResults Result; // This type hase value semantics. We have to spell these out because MSVC // won't synthesize them. AAManager() {} - AAManager(AAManager &&Arg) - : FunctionResultGetters(std::move(Arg.FunctionResultGetters)) {} - AAManager(const AAManager &Arg) - : FunctionResultGetters(Arg.FunctionResultGetters) {} + AAManager(AAManager &&Arg) : ResultGetters(std::move(Arg.ResultGetters)) {} + AAManager(const AAManager &Arg) : ResultGetters(Arg.ResultGetters) {} AAManager &operator=(AAManager &&RHS) { - FunctionResultGetters = std::move(RHS.FunctionResultGetters); + ResultGetters = std::move(RHS.ResultGetters); return *this; } AAManager &operator=(const AAManager &RHS) { - FunctionResultGetters = RHS.FunctionResultGetters; + ResultGetters = RHS.ResultGetters; return *this; } /// Register a specific AA result. template <typename AnalysisT> void registerFunctionAnalysis() { - FunctionResultGetters.push_back(&getFunctionAAResultImpl<AnalysisT>); + ResultGetters.push_back(&getFunctionAAResultImpl<AnalysisT>); + } + + /// Register a specific AA result. + template <typename AnalysisT> void registerModuleAnalysis() { + ResultGetters.push_back(&getModuleAAResultImpl<AnalysisT>); } Result run(Function &F, AnalysisManager<Function> &AM) { - Result R; - for (auto &Getter : FunctionResultGetters) + Result R(AM.getResult<TargetLibraryAnalysis>(F)); + for (auto &Getter : ResultGetters) (*Getter)(F, AM, R); return R; } private: + friend AnalysisInfoMixin<AAManager>; + static char PassID; + SmallVector<void (*)(Function &F, AnalysisManager<Function> &AM, AAResults &AAResults), - 4> FunctionResultGetters; + 4> ResultGetters; template <typename AnalysisT> static void getFunctionAAResultImpl(Function &F, @@ -1030,6 +899,15 @@ private: AAResults &AAResults) { AAResults.addAAResult(AM.template getResult<AnalysisT>(F)); } + + template <typename AnalysisT> + static void getModuleAAResultImpl(Function &F, AnalysisManager<Function> &AM, + AAResults &AAResults) { + auto &MAM = + AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); + if (auto *R = MAM.template getCachedResult<AnalysisT>(*F.getParent())) + AAResults.addAAResult(*R); + } }; /// A wrapper pass to provide the legacy pass manager access to a suitably @@ -1065,8 +943,16 @@ ImmutablePass *createExternalAAWrapperPass( /// A helper for the legacy pass manager to create a \c AAResults /// object populated to the best of our ability for a particular function when /// inside of a \c ModulePass or a \c CallGraphSCCPass. +/// +/// If a \c ModulePass or a \c CallGraphSCCPass calls \p +/// createLegacyPMAAResults, it also needs to call \p addUsedAAAnalyses in \p +/// getAnalysisUsage. AAResults createLegacyPMAAResults(Pass &P, Function &F, BasicAAResult &BAR); +/// A helper for the legacy pass manager to populate \p AU to add uses to make +/// sure the analyses required by \p createLegacyPMAAResults are available. +void getAAResultsAnalysisUsage(AnalysisUsage &AU); + } // End llvm namespace #endif diff --git a/include/llvm/Analysis/AliasAnalysisEvaluator.h b/include/llvm/Analysis/AliasAnalysisEvaluator.h new file mode 100644 index 000000000000..505ed0d9723a --- /dev/null +++ b/include/llvm/Analysis/AliasAnalysisEvaluator.h @@ -0,0 +1,70 @@ +//===- AliasAnalysisEvaluator.h - Alias Analysis Accuracy Evaluator -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements a simple N^2 alias analysis accuracy evaluator. The +/// analysis result is a set of statistics of how many times the AA +/// infrastructure provides each kind of alias result and mod/ref result when +/// queried with all pairs of pointers in the function. +/// +/// It can be used to evaluate a change in an alias analysis implementation, +/// algorithm, or the AA pipeline infrastructure itself. It acts like a stable +/// and easily tested consumer of all AA information exposed. +/// +/// This is inspired and adapted from code by: Naveen Neelakantam, Francesco +/// Spadini, and Wojciech Stryjewski. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_ALIASANALYSISEVALUATOR_H +#define LLVM_ANALYSIS_ALIASANALYSISEVALUATOR_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class AAResults; + +class AAEvaluator : public PassInfoMixin<AAEvaluator> { + int64_t FunctionCount; + int64_t NoAliasCount, MayAliasCount, PartialAliasCount, MustAliasCount; + int64_t NoModRefCount, ModCount, RefCount, ModRefCount; + +public: + AAEvaluator() + : FunctionCount(), NoAliasCount(), MayAliasCount(), PartialAliasCount(), + MustAliasCount(), NoModRefCount(), ModCount(), RefCount(), + ModRefCount() {} + AAEvaluator(AAEvaluator &&Arg) + : FunctionCount(Arg.FunctionCount), NoAliasCount(Arg.NoAliasCount), + MayAliasCount(Arg.MayAliasCount), + PartialAliasCount(Arg.PartialAliasCount), + MustAliasCount(Arg.MustAliasCount), NoModRefCount(Arg.NoModRefCount), + ModCount(Arg.ModCount), RefCount(Arg.RefCount), + ModRefCount(Arg.ModRefCount) { + Arg.FunctionCount = 0; + } + ~AAEvaluator(); + + /// \brief Run the pass over the function. + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); + +private: + // Allow the legacy pass to run this using an internal API. + friend class AAEvalLegacyPass; + + void runInternal(Function &F, AAResults &AA); +}; + +/// Create a wrapper of the above for the legacy pass manager. +FunctionPass *createAAEvalPass(); + +} + +#endif diff --git a/include/llvm/Analysis/AliasSetTracker.h b/include/llvm/Analysis/AliasSetTracker.h index 37fd69b081cc..cec56889c0ae 100644 --- a/include/llvm/Analysis/AliasSetTracker.h +++ b/include/llvm/Analysis/AliasSetTracker.h @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// // -// This file defines two classes: AliasSetTracker and AliasSet. These interface +// This file defines two classes: AliasSetTracker and AliasSet. These interfaces // are used to classify a collection of pointer references into a maximal number -// of disjoint sets. Each AliasSet object constructed by the AliasSetTracker +// of disjoint sets. Each AliasSet object constructed by the AliasSetTracker // object refers to memory disjoint from the other sets. // //===----------------------------------------------------------------------===// @@ -30,6 +30,7 @@ namespace llvm { class LoadInst; class StoreInst; class VAArgInst; +class MemSetInst; class AliasSetTracker; class AliasSet; @@ -58,8 +59,12 @@ class AliasSet : public ilist_node<AliasSet> { return &NextInList; } - void updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) { - if (NewSize > Size) Size = NewSize; + bool updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) { + bool SizeChanged = false; + if (NewSize > Size) { + Size = NewSize; + SizeChanged = true; + } if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey()) // We don't have a AAInfo yet. Set it to NewAAInfo. @@ -67,12 +72,14 @@ class AliasSet : public ilist_node<AliasSet> { else if (AAInfo != NewAAInfo) // NewAAInfo conflicts with AAInfo. AAInfo = DenseMapInfo<AAMDNodes>::getTombstoneKey(); + + return SizeChanged; } uint64_t getSize() const { return Size; } - /// getAAInfo - Return the AAInfo, or null if there is no - /// information or conflicting information. + /// Return the AAInfo, or null if there is no information or conflicting + /// information. AAMDNodes getAAInfo() const { // If we have missing or conflicting AAInfo, return null. if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey() || @@ -111,11 +118,11 @@ class AliasSet : public ilist_node<AliasSet> { PointerRec *PtrList, **PtrListEnd; // Doubly linked list of nodes. AliasSet *Forward; // Forwarding pointer. - // All instructions without a specific address in this alias set. + /// All instructions without a specific address in this alias set. std::vector<AssertingVH<Instruction> > UnknownInsts; - // RefCount - Number of nodes pointing to this AliasSet plus the number of - // AliasSets forwarding to it. + /// Number of nodes pointing to this AliasSet plus the number of AliasSets + /// forwarding to it. unsigned RefCount : 28; /// The kinds of access this alias set models. @@ -143,8 +150,8 @@ class AliasSet : public ilist_node<AliasSet> { }; unsigned Alias : 1; - // Volatile - True if this alias set contains volatile loads or stores. - bool Volatile : 1; + /// True if this alias set contains volatile loads or stores. + unsigned Volatile : 1; void addRef() { ++RefCount; } void dropRef(AliasSetTracker &AST) { @@ -165,20 +172,18 @@ public: bool isMustAlias() const { return Alias == SetMustAlias; } bool isMayAlias() const { return Alias == SetMayAlias; } - // isVolatile - Return true if this alias set contains volatile loads or - // stores. + /// Return true if this alias set contains volatile loads or stores. bool isVolatile() const { return Volatile; } - /// isForwardingAliasSet - Return true if this alias set should be ignored as - /// part of the AliasSetTracker object. + /// Return true if this alias set should be ignored as part of the + /// AliasSetTracker object. bool isForwardingAliasSet() const { return Forward; } - /// mergeSetIn - Merge the specified alias set into this alias set... - /// + /// Merge the specified alias set into this alias set. void mergeSetIn(AliasSet &AS, AliasSetTracker &AST); - // Alias Set iteration - Allow access to all of the pointer which are part of - // this alias set... + // Alias Set iteration - Allow access to all of the pointers which are part of + // this alias set. class iterator; iterator begin() const { return iterator(PtrList); } iterator end() const { return iterator(); } @@ -236,9 +241,9 @@ private: return PtrList; } - /// getForwardedTarget - Return the real alias set this represents. If this - /// has been merged with another set and is forwarding, return the ultimate - /// destination set. This also implements the union-find collapsing as well. + /// Return the real alias set this represents. If this has been merged with + /// another set and is forwarding, return the ultimate destination set. This + /// also implements the union-find collapsing as well. AliasSet *getForwardedTarget(AliasSetTracker &AST) { if (!Forward) return this; @@ -271,9 +276,8 @@ private: void setVolatile() { Volatile = true; } public: - /// aliasesPointer - Return true if the specified pointer "may" (or must) - /// alias one of the members in the set. - /// + /// Return true if the specified pointer "may" (or must) alias one of the + /// members in the set. bool aliasesPointer(const Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo, AliasAnalysis &AA) const; bool aliasesUnknownInst(const Instruction *Inst, AliasAnalysis &AA) const; @@ -285,8 +289,8 @@ inline raw_ostream& operator<<(raw_ostream &OS, const AliasSet &AS) { } class AliasSetTracker { - /// CallbackVH - A CallbackVH to arrange for AliasSetTracker to be - /// notified whenever a Value is deleted. + /// A CallbackVH to arrange for AliasSetTracker to be notified whenever a + /// Value is deleted. class ASTCallbackVH final : public CallbackVH { AliasSetTracker *AST; void deleted() override; @@ -296,8 +300,8 @@ class AliasSetTracker { ASTCallbackVH(Value *V, AliasSetTracker *AST = nullptr); ASTCallbackVH &operator=(Value *V); }; - /// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to - /// compare and hash the value handle. + /// Traits to tell DenseMap that tell us how to compare and hash the value + /// handle. struct ASTCallbackVHDenseMapInfo : public DenseMapInfo<Value *> {}; AliasAnalysis &AA; @@ -311,15 +315,14 @@ class AliasSetTracker { PointerMapType PointerMap; public: - /// AliasSetTracker ctor - Create an empty collection of AliasSets, and use - /// the specified alias analysis object to disambiguate load and store - /// addresses. + /// Create an empty collection of AliasSets, and use the specified alias + /// analysis object to disambiguate load and store addresses. explicit AliasSetTracker(AliasAnalysis &aa) : AA(aa) {} ~AliasSetTracker() { clear(); } - /// add methods - These methods are used to add different types of - /// instructions to the alias sets. Adding a new instruction can result in - /// one of three actions happening: + /// These methods are used to add different types of instructions to the alias + /// sets. Adding a new instruction can result in one of three actions + /// happening: /// /// 1. If the instruction doesn't alias any other sets, create a new set. /// 2. If the instruction aliases exactly one set, add it to the set @@ -333,47 +336,46 @@ public: bool add(LoadInst *LI); bool add(StoreInst *SI); bool add(VAArgInst *VAAI); + bool add(MemSetInst *MSI); bool add(Instruction *I); // Dispatch to one of the other add methods... void add(BasicBlock &BB); // Add all instructions in basic block void add(const AliasSetTracker &AST); // Add alias relations from another AST bool addUnknown(Instruction *I); - /// remove methods - These methods are used to remove all entries that might - /// be aliased by the specified instruction. These methods return true if any - /// alias sets were eliminated. - // Remove a location + /// These methods are used to remove all entries that might be aliased by the + /// specified instruction. These methods return true if any alias sets were + /// eliminated. bool remove(Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo); bool remove(LoadInst *LI); bool remove(StoreInst *SI); bool remove(VAArgInst *VAAI); + bool remove(MemSetInst *MSI); bool remove(Instruction *I); void remove(AliasSet &AS); bool removeUnknown(Instruction *I); void clear(); - /// getAliasSets - Return the alias sets that are active. - /// + /// Return the alias sets that are active. const ilist<AliasSet> &getAliasSets() const { return AliasSets; } - /// getAliasSetForPointer - Return the alias set that the specified pointer - /// lives in. If the New argument is non-null, this method sets the value to - /// true if a new alias set is created to contain the pointer (because the - /// pointer didn't alias anything). + /// Return the alias set that the specified pointer lives in. If the New + /// argument is non-null, this method sets the value to true if a new alias + /// set is created to contain the pointer (because the pointer didn't alias + /// anything). AliasSet &getAliasSetForPointer(Value *P, uint64_t Size, const AAMDNodes &AAInfo, bool *New = nullptr); - /// getAliasSetForPointerIfExists - Return the alias set containing the - /// location specified if one exists, otherwise return null. + /// Return the alias set containing the location specified if one exists, + /// otherwise return null. AliasSet *getAliasSetForPointerIfExists(const Value *P, uint64_t Size, const AAMDNodes &AAInfo) { - return findAliasSetForPointer(P, Size, AAInfo); + return mergeAliasSetsForPointer(P, Size, AAInfo); } - /// containsPointer - Return true if the specified location is represented by - /// this alias set, false otherwise. This does not modify the AST object or - /// alias sets. + /// Return true if the specified location is represented by this alias set, + /// false otherwise. This does not modify the AST object or alias sets. bool containsPointer(const Value *P, uint64_t Size, const AAMDNodes &AAInfo) const; @@ -381,23 +383,19 @@ public: /// members in any of the sets. bool containsUnknown(const Instruction *I) const; - /// getAliasAnalysis - Return the underlying alias analysis object used by - /// this tracker. + /// Return the underlying alias analysis object used by this tracker. AliasAnalysis &getAliasAnalysis() const { return AA; } - /// deleteValue method - This method is used to remove a pointer value from - /// the AliasSetTracker entirely. It should be used when an instruction is - /// deleted from the program to update the AST. If you don't use this, you - /// would have dangling pointers to deleted instructions. - /// + /// This method is used to remove a pointer value from the AliasSetTracker + /// entirely. It should be used when an instruction is deleted from the + /// program to update the AST. If you don't use this, you would have dangling + /// pointers to deleted instructions. void deleteValue(Value *PtrVal); - /// copyValue - This method should be used whenever a preexisting value in the - /// program is copied or cloned, introducing a new value. Note that it is ok - /// for clients that use this method to introduce the same value multiple - /// times: if the tracker already knows about a value, it will ignore the - /// request. - /// + /// This method should be used whenever a preexisting value in the program is + /// copied or cloned, introducing a new value. Note that it is ok for clients + /// that use this method to introduce the same value multiple times: if the + /// tracker already knows about a value, it will ignore the request. void copyValue(Value *From, Value *To); typedef ilist<AliasSet>::iterator iterator; @@ -416,8 +414,8 @@ private: friend class AliasSet; void removeAliasSet(AliasSet *AS); - // getEntryFor - Just like operator[] on the map, except that it creates an - // entry for the pointer if it doesn't already exist. + /// Just like operator[] on the map, except that it creates an entry for the + /// pointer if it doesn't already exist. AliasSet::PointerRec &getEntryFor(Value *V) { AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)]; if (!Entry) @@ -433,8 +431,8 @@ private: AS.Access |= E; return AS; } - AliasSet *findAliasSetForPointer(const Value *Ptr, uint64_t Size, - const AAMDNodes &AAInfo); + AliasSet *mergeAliasSetsForPointer(const Value *Ptr, uint64_t Size, + const AAMDNodes &AAInfo); AliasSet *findAliasSetForUnknownInst(Instruction *Inst); }; diff --git a/include/llvm/Analysis/AssumptionCache.h b/include/llvm/Analysis/AssumptionCache.h index b903f96d55b2..06f2a117ac21 100644 --- a/include/llvm/Analysis/AssumptionCache.h +++ b/include/llvm/Analysis/AssumptionCache.h @@ -22,16 +22,12 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include <memory> namespace llvm { -// FIXME: Replace this brittle forward declaration with the include of the new -// PassManager.h when doing so doesn't break the PassManagerBuilder. -template <typename IRUnitT> class AnalysisManager; -class PreservedAnalyses; - /// \brief A cache of @llvm.assume calls within a function. /// /// This cache provides fast lookup of assumptions within a function by caching @@ -97,36 +93,31 @@ public: /// /// This analysis is intended for use with the new pass manager and will vend /// assumption caches for a given function. -class AssumptionAnalysis { +class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> { + friend AnalysisInfoMixin<AssumptionAnalysis>; static char PassID; public: typedef AssumptionCache Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - /// \brief Provide a name for the analysis for debugging and logging. - static StringRef name() { return "AssumptionAnalysis"; } - AssumptionAnalysis() {} AssumptionAnalysis(const AssumptionAnalysis &Arg) {} AssumptionAnalysis(AssumptionAnalysis &&Arg) {} AssumptionAnalysis &operator=(const AssumptionAnalysis &RHS) { return *this; } AssumptionAnalysis &operator=(AssumptionAnalysis &&RHS) { return *this; } - AssumptionCache run(Function &F) { return AssumptionCache(F); } + AssumptionCache run(Function &F, FunctionAnalysisManager &) { + return AssumptionCache(F); + } }; /// \brief Printer pass for the \c AssumptionAnalysis results. -class AssumptionPrinterPass { +class AssumptionPrinterPass : public PassInfoMixin<AssumptionPrinterPass> { raw_ostream &OS; public: explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {} - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); - - static StringRef name() { return "AssumptionPrinterPass"; } + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief An immutable pass that tracks lazily created \c AssumptionCache diff --git a/include/llvm/Analysis/BasicAliasAnalysis.h b/include/llvm/Analysis/BasicAliasAnalysis.h index 181a9327024c..a3195d17b029 100644 --- a/include/llvm/Analysis/BasicAliasAnalysis.h +++ b/include/llvm/Analysis/BasicAliasAnalysis.h @@ -40,6 +40,7 @@ class BasicAAResult : public AAResultBase<BasicAAResult> { friend AAResultBase<BasicAAResult>; const DataLayout &DL; + const TargetLibraryInfo &TLI; AssumptionCache &AC; DominatorTree *DT; LoopInfo *LI; @@ -48,13 +49,14 @@ public: BasicAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI, AssumptionCache &AC, DominatorTree *DT = nullptr, LoopInfo *LI = nullptr) - : AAResultBase(TLI), DL(DL), AC(AC), DT(DT), LI(LI) {} + : AAResultBase(), DL(DL), TLI(TLI), AC(AC), DT(DT), LI(LI) {} BasicAAResult(const BasicAAResult &Arg) - : AAResultBase(Arg), DL(Arg.DL), AC(Arg.AC), DT(Arg.DT), LI(Arg.LI) {} - BasicAAResult(BasicAAResult &&Arg) - : AAResultBase(std::move(Arg)), DL(Arg.DL), AC(Arg.AC), DT(Arg.DT), + : AAResultBase(Arg), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT), LI(Arg.LI) {} + BasicAAResult(BasicAAResult &&Arg) + : AAResultBase(std::move(Arg)), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC), + DT(Arg.DT), LI(Arg.LI) {} /// Handle invalidation events from the new pass manager. /// @@ -107,6 +109,20 @@ private: } }; + // Represents the internal structure of a GEP, decomposed into a base pointer, + // constant offsets, and variable scaled indices. + struct DecomposedGEP { + // Base pointer of the GEP + const Value *Base; + // Total constant offset w.r.t the base from indexing into structs + int64_t StructOffset; + // Total constant offset w.r.t the base from indexing through + // pointers/arrays/vectors + int64_t OtherOffset; + // Scaled variable (non-constant) indices. + SmallVector<VariableGEPIndex, 4> VarIndices; + }; + /// Track alias queries to guard against recursion. typedef std::pair<MemoryLocation, MemoryLocation> LocPair; typedef SmallDenseMap<LocPair, AliasResult, 8> AliasCacheTy; @@ -137,11 +153,13 @@ private: const DataLayout &DL, unsigned Depth, AssumptionCache *AC, DominatorTree *DT, bool &NSW, bool &NUW); - static const Value * - DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, - SmallVectorImpl<VariableGEPIndex> &VarIndices, - bool &MaxLookupReached, const DataLayout &DL, - AssumptionCache *AC, DominatorTree *DT); + static bool DecomposeGEPExpression(const Value *V, DecomposedGEP &Decomposed, + const DataLayout &DL, AssumptionCache *AC, DominatorTree *DT); + + static bool isGEPBaseAtNegativeOffset(const GEPOperator *GEPOp, + const DecomposedGEP &DecompGEP, const DecomposedGEP &DecompObject, + uint64_t ObjectAccessSize); + /// \brief A Heuristic for aliasGEP that searches for a constant offset /// between the variables. /// @@ -178,20 +196,14 @@ private: }; /// Analysis pass providing a never-invalidated alias analysis result. -class BasicAA { +class BasicAA : public AnalysisInfoMixin<BasicAA> { + friend AnalysisInfoMixin<BasicAA>; + static char PassID; + public: typedef BasicAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - BasicAAResult run(Function &F, AnalysisManager<Function> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "BasicAliasAnalysis"; } - -private: - static char PassID; + BasicAAResult run(Function &F, AnalysisManager<Function> &AM); }; /// Legacy wrapper pass to provide the BasicAAResult object. diff --git a/include/llvm/Analysis/BlockFrequencyInfo.h b/include/llvm/Analysis/BlockFrequencyInfo.h index 6f2a2b522769..7d48dfc9121e 100644 --- a/include/llvm/Analysis/BlockFrequencyInfo.h +++ b/include/llvm/Analysis/BlockFrequencyInfo.h @@ -14,6 +14,8 @@ #ifndef LLVM_ANALYSIS_BLOCKFREQUENCYINFO_H #define LLVM_ANALYSIS_BLOCKFREQUENCYINFO_H +#include "llvm/ADT/Optional.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/BlockFrequency.h" #include <climits> @@ -30,12 +32,21 @@ class BlockFrequencyInfo { typedef BlockFrequencyInfoImpl<BasicBlock> ImplType; std::unique_ptr<ImplType> BFI; + void operator=(const BlockFrequencyInfo &) = delete; + BlockFrequencyInfo(const BlockFrequencyInfo &) = delete; + public: BlockFrequencyInfo(); BlockFrequencyInfo(const Function &F, const BranchProbabilityInfo &BPI, const LoopInfo &LI); + BlockFrequencyInfo(BlockFrequencyInfo &&Arg); + + BlockFrequencyInfo &operator=(BlockFrequencyInfo &&RHS); + + ~BlockFrequencyInfo(); const Function *getFunction() const; + const BranchProbabilityInfo *getBPI() const; void view() const; /// getblockFreq - Return block frequency. Return 0 if we don't have the @@ -45,6 +56,11 @@ public: /// floating points. BlockFrequency getBlockFreq(const BasicBlock *BB) const; + /// \brief Returns the estimated profile count of \p BB. + /// This computes the relative block frequency of \p BB and multiplies it by + /// the enclosing function's count (if available) and returns the value. + Optional<uint64_t> getBlockProfileCount(const BasicBlock *BB) const; + // Set the frequency of the given basic block. void setBlockFreq(const BasicBlock *BB, uint64_t Freq); @@ -65,6 +81,30 @@ public: void print(raw_ostream &OS) const; }; +/// \brief Analysis pass which computes \c BlockFrequencyInfo. +class BlockFrequencyAnalysis + : public AnalysisInfoMixin<BlockFrequencyAnalysis> { + friend AnalysisInfoMixin<BlockFrequencyAnalysis>; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef BlockFrequencyInfo Result; + + /// \brief Run the analysis pass over a function and produce BFI. + Result run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for the \c BlockFrequencyInfo results. +class BlockFrequencyPrinterPass + : public PassInfoMixin<BlockFrequencyPrinterPass> { + raw_ostream &OS; + +public: + explicit BlockFrequencyPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + /// \brief Legacy analysis pass which computes \c BlockFrequencyInfo. class BlockFrequencyInfoWrapperPass : public FunctionPass { BlockFrequencyInfo BFI; diff --git a/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/include/llvm/Analysis/BlockFrequencyInfoImpl.h index 387e9a887d93..7ed06b1bb68f 100644 --- a/include/llvm/Analysis/BlockFrequencyInfoImpl.h +++ b/include/llvm/Analysis/BlockFrequencyInfoImpl.h @@ -16,12 +16,16 @@ #define LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/BasicBlock.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/BranchProbability.h" +#include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ScaledNumber.h" #include "llvm/Support/raw_ostream.h" #include <deque> @@ -476,6 +480,8 @@ public: Scaled64 getFloatingBlockFreq(const BlockNode &Node) const; BlockFrequency getBlockFreq(const BlockNode &Node) const; + Optional<uint64_t> getBlockProfileCount(const Function &F, + const BlockNode &Node) const; void setBlockFreq(const BlockNode &Node, uint64_t Freq); @@ -915,11 +921,17 @@ public: BlockFrequency getBlockFreq(const BlockT *BB) const { return BlockFrequencyInfoImplBase::getBlockFreq(getNode(BB)); } + Optional<uint64_t> getBlockProfileCount(const Function &F, + const BlockT *BB) const { + return BlockFrequencyInfoImplBase::getBlockProfileCount(F, getNode(BB)); + } void setBlockFreq(const BlockT *BB, uint64_t Freq); Scaled64 getFloatingBlockFreq(const BlockT *BB) const { return BlockFrequencyInfoImplBase::getFloatingBlockFreq(getNode(BB)); } + const BranchProbabilityInfoT &getBPI() const { return *BPI; } + /// \brief Print the frequencies for the current function. /// /// Prints the frequencies for the blocks in the current function. @@ -1173,12 +1185,10 @@ void BlockFrequencyInfoImpl<BT>::computeIrreducibleMass( updateLoopWithIrreducible(*OuterLoop); } -namespace { // A helper function that converts a branch probability into weight. inline uint32_t getWeightFromBranchProb(const BranchProbability Prob) { return Prob.getNumerator(); } -} // namespace template <class BT> bool @@ -1224,6 +1234,115 @@ raw_ostream &BlockFrequencyInfoImpl<BT>::print(raw_ostream &OS) const { return OS; } +// Graph trait base class for block frequency information graph +// viewer. + +enum GVDAGType { GVDT_None, GVDT_Fraction, GVDT_Integer, GVDT_Count }; + +template <class BlockFrequencyInfoT, class BranchProbabilityInfoT> +struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits { + explicit BFIDOTGraphTraitsBase(bool isSimple = false) + : DefaultDOTGraphTraits(isSimple) {} + + typedef GraphTraits<BlockFrequencyInfoT *> GTraits; + typedef typename GTraits::NodeType NodeType; + typedef typename GTraits::ChildIteratorType EdgeIter; + typedef typename GTraits::nodes_iterator NodeIter; + + uint64_t MaxFrequency = 0; + static std::string getGraphName(const BlockFrequencyInfoT *G) { + return G->getFunction()->getName(); + } + + std::string getNodeAttributes(const NodeType *Node, + const BlockFrequencyInfoT *Graph, + unsigned HotPercentThreshold = 0) { + std::string Result; + if (!HotPercentThreshold) + return Result; + + // Compute MaxFrequency on the fly: + if (!MaxFrequency) { + for (NodeIter I = GTraits::nodes_begin(Graph), + E = GTraits::nodes_end(Graph); + I != E; ++I) { + NodeType &N = *I; + MaxFrequency = + std::max(MaxFrequency, Graph->getBlockFreq(&N).getFrequency()); + } + } + BlockFrequency Freq = Graph->getBlockFreq(Node); + BlockFrequency HotFreq = + (BlockFrequency(MaxFrequency) * + BranchProbability::getBranchProbability(HotPercentThreshold, 100)); + + if (Freq < HotFreq) + return Result; + + raw_string_ostream OS(Result); + OS << "color=\"red\""; + OS.flush(); + return Result; + } + + std::string getNodeLabel(const NodeType *Node, + const BlockFrequencyInfoT *Graph, GVDAGType GType) { + std::string Result; + raw_string_ostream OS(Result); + + OS << Node->getName().str() << " : "; + switch (GType) { + case GVDT_Fraction: + Graph->printBlockFreq(OS, Node); + break; + case GVDT_Integer: + OS << Graph->getBlockFreq(Node).getFrequency(); + break; + case GVDT_Count: { + auto Count = Graph->getBlockProfileCount(Node); + if (Count) + OS << Count.getValue(); + else + OS << "Unknown"; + break; + } + case GVDT_None: + llvm_unreachable("If we are not supposed to render a graph we should " + "never reach this point."); + } + return Result; + } + + std::string getEdgeAttributes(const NodeType *Node, EdgeIter EI, + const BlockFrequencyInfoT *BFI, + const BranchProbabilityInfoT *BPI, + unsigned HotPercentThreshold = 0) { + std::string Str; + if (!BPI) + return Str; + + BranchProbability BP = BPI->getEdgeProbability(Node, EI); + uint32_t N = BP.getNumerator(); + uint32_t D = BP.getDenominator(); + double Percent = 100.0 * N / D; + raw_string_ostream OS(Str); + OS << format("label=\"%.1f%%\"", Percent); + + if (HotPercentThreshold) { + BlockFrequency EFreq = BFI->getBlockFreq(Node) * BP; + BlockFrequency HotFreq = BlockFrequency(MaxFrequency) * + BranchProbability(HotPercentThreshold, 100); + + if (EFreq >= HotFreq) { + OS << ",color=\"red\""; + } + } + + OS.flush(); + return Str; + } +}; + } // end namespace llvm #undef DEBUG_TYPE diff --git a/include/llvm/Analysis/BranchProbabilityInfo.h b/include/llvm/Analysis/BranchProbabilityInfo.h index cfdf218491bd..6434ba962ebc 100644 --- a/include/llvm/Analysis/BranchProbabilityInfo.h +++ b/include/llvm/Analysis/BranchProbabilityInfo.h @@ -15,8 +15,11 @@ #define LLVM_ANALYSIS_BRANCHPROBABILITYINFO_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/ValueHandle.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/BranchProbability.h" @@ -40,7 +43,22 @@ class raw_ostream; class BranchProbabilityInfo { public: BranchProbabilityInfo() {} - BranchProbabilityInfo(Function &F, const LoopInfo &LI) { calculate(F, LI); } + BranchProbabilityInfo(const Function &F, const LoopInfo &LI) { + calculate(F, LI); + } + + BranchProbabilityInfo(BranchProbabilityInfo &&Arg) + : Probs(std::move(Arg.Probs)), LastF(Arg.LastF), + PostDominatedByUnreachable(std::move(Arg.PostDominatedByUnreachable)), + PostDominatedByColdCall(std::move(Arg.PostDominatedByColdCall)) {} + + BranchProbabilityInfo &operator=(BranchProbabilityInfo &&RHS) { + releaseMemory(); + Probs = std::move(RHS.Probs); + PostDominatedByColdCall = std::move(RHS.PostDominatedByColdCall); + PostDominatedByUnreachable = std::move(RHS.PostDominatedByUnreachable); + return *this; + } void releaseMemory(); @@ -74,7 +92,7 @@ public: /// /// Given a basic block, look through its successors and if one exists for /// which \see isEdgeHot would return true, return that successor block. - BasicBlock *getHotSucc(BasicBlock *BB) const; + const BasicBlock *getHotSucc(const BasicBlock *BB) const; /// \brief Print an edge's probability. /// @@ -98,9 +116,31 @@ public: return IsLikely ? LikelyProb : LikelyProb.getCompl(); } - void calculate(Function &F, const LoopInfo& LI); + void calculate(const Function &F, const LoopInfo &LI); + + /// Forget analysis results for the given basic block. + void eraseBlock(const BasicBlock *BB); private: + void operator=(const BranchProbabilityInfo &) = delete; + BranchProbabilityInfo(const BranchProbabilityInfo &) = delete; + + // We need to store CallbackVH's in order to correctly handle basic block + // removal. + class BasicBlockCallbackVH final : public CallbackVH { + BranchProbabilityInfo *BPI; + void deleted() override { + assert(BPI != nullptr); + BPI->eraseBlock(cast<BasicBlock>(getValPtr())); + BPI->Handles.erase(*this); + } + + public: + BasicBlockCallbackVH(const Value *V, BranchProbabilityInfo *BPI=nullptr) + : CallbackVH(const_cast<Value *>(V)), BPI(BPI) {} + }; + DenseSet<BasicBlockCallbackVH, DenseMapInfo<Value*>> Handles; + // Since we allow duplicate edges from one basic block to another, we use // a pair (PredBlock and an index in the successors) to specify an edge. typedef std::pair<const BasicBlock *, unsigned> Edge; @@ -116,22 +156,46 @@ private: DenseMap<Edge, BranchProbability> Probs; /// \brief Track the last function we run over for printing. - Function *LastF; + const Function *LastF; /// \brief Track the set of blocks directly succeeded by a returning block. - SmallPtrSet<BasicBlock *, 16> PostDominatedByUnreachable; + SmallPtrSet<const BasicBlock *, 16> PostDominatedByUnreachable; /// \brief Track the set of blocks that always lead to a cold call. - SmallPtrSet<BasicBlock *, 16> PostDominatedByColdCall; - - bool calcUnreachableHeuristics(BasicBlock *BB); - bool calcMetadataWeights(BasicBlock *BB); - bool calcColdCallHeuristics(BasicBlock *BB); - bool calcPointerHeuristics(BasicBlock *BB); - bool calcLoopBranchHeuristics(BasicBlock *BB, const LoopInfo &LI); - bool calcZeroHeuristics(BasicBlock *BB); - bool calcFloatingPointHeuristics(BasicBlock *BB); - bool calcInvokeHeuristics(BasicBlock *BB); + SmallPtrSet<const BasicBlock *, 16> PostDominatedByColdCall; + + bool calcUnreachableHeuristics(const BasicBlock *BB); + bool calcMetadataWeights(const BasicBlock *BB); + bool calcColdCallHeuristics(const BasicBlock *BB); + bool calcPointerHeuristics(const BasicBlock *BB); + bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI); + bool calcZeroHeuristics(const BasicBlock *BB); + bool calcFloatingPointHeuristics(const BasicBlock *BB); + bool calcInvokeHeuristics(const BasicBlock *BB); +}; + +/// \brief Analysis pass which computes \c BranchProbabilityInfo. +class BranchProbabilityAnalysis + : public AnalysisInfoMixin<BranchProbabilityAnalysis> { + friend AnalysisInfoMixin<BranchProbabilityAnalysis>; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef BranchProbabilityInfo Result; + + /// \brief Run the analysis pass over a function and produce BPI. + BranchProbabilityInfo run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for the \c BranchProbabilityAnalysis results. +class BranchProbabilityPrinterPass + : public PassInfoMixin<BranchProbabilityPrinterPass> { + raw_ostream &OS; + +public: + explicit BranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Legacy analysis pass which computes \c BranchProbabilityInfo. diff --git a/include/llvm/Analysis/CFLAndersAliasAnalysis.h b/include/llvm/Analysis/CFLAndersAliasAnalysis.h new file mode 100644 index 000000000000..48eca888419a --- /dev/null +++ b/include/llvm/Analysis/CFLAndersAliasAnalysis.h @@ -0,0 +1,138 @@ +//=- CFLAndersAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface for LLVM's inclusion-based alias analysis +/// implemented with CFL graph reachability. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include <forward_list> + +namespace llvm { + +class TargetLibraryInfo; + +namespace cflaa { +struct AliasSummary; +} + +class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> { + friend AAResultBase<CFLAndersAAResult>; + class FunctionInfo; + +public: + explicit CFLAndersAAResult(const TargetLibraryInfo &); + CFLAndersAAResult(CFLAndersAAResult &&); + ~CFLAndersAAResult(); + + /// Handle invalidation events from the new pass manager. + /// By definition, this result is stateless and so remains valid. + bool invalidate(Function &, const PreservedAnalyses &) { return false; } + /// Evict the given function from cache + void evict(const Function &Fn); + + /// \brief Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(const Function &); + + AliasResult query(const MemoryLocation &, const MemoryLocation &); + AliasResult alias(const MemoryLocation &, const MemoryLocation &); + +private: + struct FunctionHandle final : public CallbackVH { + FunctionHandle(Function *Fn, CFLAndersAAResult *Result) + : CallbackVH(Fn), Result(Result) { + assert(Fn != nullptr); + assert(Result != nullptr); + } + + void deleted() override { removeSelfFromCache(); } + void allUsesReplacedWith(Value *) override { removeSelfFromCache(); } + + private: + CFLAndersAAResult *Result; + + void removeSelfFromCache() { + assert(Result != nullptr); + auto *Val = getValPtr(); + Result->evict(*cast<Function>(Val)); + setValPtr(nullptr); + } + }; + + /// \brief Ensures that the given function is available in the cache. + /// Returns the appropriate entry from the cache. + const Optional<FunctionInfo> &ensureCached(const Function &); + + /// \brief Inserts the given Function into the cache. + void scan(const Function &); + + /// \brief Build summary for a given function + FunctionInfo buildInfoFrom(const Function &); + + const TargetLibraryInfo &TLI; + + /// \brief Cached mapping of Functions to their StratifiedSets. + /// If a function's sets are currently being built, it is marked + /// in the cache as an Optional without a value. This way, if we + /// have any kind of recursion, it is discernable from a function + /// that simply has empty sets. + DenseMap<const Function *, Optional<FunctionInfo>> Cache; + + std::forward_list<FunctionHandle> Handles; +}; + +/// Analysis pass providing a never-invalidated alias analysis result. +/// +/// FIXME: We really should refactor CFL to use the analysis more heavily, and +/// in particular to leverage invalidation to trigger re-computation. +class CFLAndersAA : public AnalysisInfoMixin<CFLAndersAA> { + friend AnalysisInfoMixin<CFLAndersAA>; + static char PassID; + +public: + typedef CFLAndersAAResult Result; + + CFLAndersAAResult run(Function &F, AnalysisManager<Function> &AM); +}; + +/// Legacy wrapper pass to provide the CFLAndersAAResult object. +class CFLAndersAAWrapperPass : public ImmutablePass { + std::unique_ptr<CFLAndersAAResult> Result; + +public: + static char ID; + + CFLAndersAAWrapperPass(); + + CFLAndersAAResult &getResult() { return *Result; } + const CFLAndersAAResult &getResult() const { return *Result; } + + void initializePass() override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +//===--------------------------------------------------------------------===// +// +// createCFLAndersAAWrapperPass - This pass implements a set-based approach to +// alias analysis. +// +ImmutablePass *createCFLAndersAAWrapperPass(); +} + +#endif diff --git a/include/llvm/Analysis/CFLAliasAnalysis.h b/include/llvm/Analysis/CFLSteensAliasAnalysis.h index 7473a454ab30..80a00d02b811 100644 --- a/include/llvm/Analysis/CFLAliasAnalysis.h +++ b/include/llvm/Analysis/CFLSteensAliasAnalysis.h @@ -1,4 +1,4 @@ -//===- CFLAliasAnalysis.h - CFL-Based Alias Analysis Interface ---*- C++ -*-==// +//=- CFLSteensAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,18 @@ // //===----------------------------------------------------------------------===// /// \file -/// This is the interface for LLVM's primary stateless and local alias analysis. +/// This is the interface for LLVM's unification-based alias analysis +/// implemented with CFL graph reachability. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_ANALYSIS_CFLALIASANALYSIS_H -#define LLVM_ANALYSIS_CFLALIASANALYSIS_H +#ifndef LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" @@ -26,14 +27,20 @@ namespace llvm { -class CFLAAResult : public AAResultBase<CFLAAResult> { - friend AAResultBase<CFLAAResult>; +class TargetLibraryInfo; - struct FunctionInfo; +namespace cflaa { +struct AliasSummary; +} + +class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> { + friend AAResultBase<CFLSteensAAResult>; + class FunctionInfo; public: - explicit CFLAAResult(const TargetLibraryInfo &TLI); - CFLAAResult(CFLAAResult &&Arg); + explicit CFLSteensAAResult(const TargetLibraryInfo &); + CFLSteensAAResult(CFLSteensAAResult &&Arg); + ~CFLSteensAAResult(); /// Handle invalidation events from the new pass manager. /// @@ -49,26 +56,23 @@ public: /// Returns the appropriate entry from the cache. const Optional<FunctionInfo> &ensureCached(Function *Fn); + /// \brief Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(Function &Fn); + AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB); AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { - if (LocA.Ptr == LocB.Ptr) { - if (LocA.Size == LocB.Size) { - return MustAlias; - } else { - return PartialAlias; - } - } + if (LocA.Ptr == LocB.Ptr) + return LocA.Size == LocB.Size ? MustAlias : PartialAlias; // Comparisons between global variables and other constants should be // handled by BasicAA. - // TODO: ConstantExpr handling -- CFLAA may report NoAlias when comparing - // a GlobalValue and ConstantExpr, but every query needs to have at least - // one Value tied to a Function, and neither GlobalValues nor ConstantExprs - // are. - if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr)) { + // CFLSteensAA may report NoAlias when comparing a GlobalValue and + // ConstantExpr, but every query needs to have at least one Value tied to a + // Function, and neither GlobalValues nor ConstantExprs are. + if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr)) return AAResultBase::alias(LocA, LocB); - } AliasResult QueryResult = query(LocA, LocB); if (QueryResult == MayAlias) @@ -77,9 +81,19 @@ public: return QueryResult; } + /// Get the location associated with a pointer argument of a callsite. + ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx); + + /// Returns the behavior when calling the given call site. + FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS); + + /// Returns the behavior when calling the given function. For use when the + /// call site is not known. + FunctionModRefBehavior getModRefBehavior(const Function *F); + private: struct FunctionHandle final : public CallbackVH { - FunctionHandle(Function *Fn, CFLAAResult *Result) + FunctionHandle(Function *Fn, CFLSteensAAResult *Result) : CallbackVH(Fn), Result(Result) { assert(Fn != nullptr); assert(Result != nullptr); @@ -89,7 +103,7 @@ private: void allUsesReplacedWith(Value *) override { removeSelfFromCache(); } private: - CFLAAResult *Result; + CFLSteensAAResult *Result; void removeSelfFromCache() { assert(Result != nullptr); @@ -99,6 +113,8 @@ private: } }; + const TargetLibraryInfo &TLI; + /// \brief Cached mapping of Functions to their StratifiedSets. /// If a function's sets are currently being built, it is marked /// in the cache as an Optional without a value. This way, if we @@ -114,45 +130,38 @@ private: /// /// FIXME: We really should refactor CFL to use the analysis more heavily, and /// in particular to leverage invalidation to trigger re-computation of sets. -class CFLAA { -public: - typedef CFLAAResult Result; - - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - CFLAAResult run(Function &F, AnalysisManager<Function> *AM); +class CFLSteensAA : public AnalysisInfoMixin<CFLSteensAA> { + friend AnalysisInfoMixin<CFLSteensAA>; + static char PassID; - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "CFLAA"; } +public: + typedef CFLSteensAAResult Result; -private: - static char PassID; + CFLSteensAAResult run(Function &F, AnalysisManager<Function> &AM); }; -/// Legacy wrapper pass to provide the CFLAAResult object. -class CFLAAWrapperPass : public ImmutablePass { - std::unique_ptr<CFLAAResult> Result; +/// Legacy wrapper pass to provide the CFLSteensAAResult object. +class CFLSteensAAWrapperPass : public ImmutablePass { + std::unique_ptr<CFLSteensAAResult> Result; public: static char ID; - CFLAAWrapperPass(); + CFLSteensAAWrapperPass(); - CFLAAResult &getResult() { return *Result; } - const CFLAAResult &getResult() const { return *Result; } + CFLSteensAAResult &getResult() { return *Result; } + const CFLSteensAAResult &getResult() const { return *Result; } - bool doInitialization(Module &M) override; - bool doFinalization(Module &M) override; + void initializePass() override; void getAnalysisUsage(AnalysisUsage &AU) const override; }; //===--------------------------------------------------------------------===// // -// createCFLAAWrapperPass - This pass implements a set-based approach to +// createCFLSteensAAWrapperPass - This pass implements a set-based approach to // alias analysis. // -ImmutablePass *createCFLAAWrapperPass(); +ImmutablePass *createCFLSteensAAWrapperPass(); } #endif diff --git a/include/llvm/Analysis/CGSCCPassManager.h b/include/llvm/Analysis/CGSCCPassManager.h index e7635eb1ab67..3263ecec4e26 100644 --- a/include/llvm/Analysis/CGSCCPassManager.h +++ b/include/llvm/Analysis/CGSCCPassManager.h @@ -11,7 +11,7 @@ /// This header provides classes for managing passes over SCCs of the call /// graph. These passes form an important component of LLVM's interprocedural /// optimizations. Because they operate on the SCCs of the call graph, and they -/// wtraverse the graph in post order, they can effectively do pair-wise +/// traverse the graph in post order, they can effectively do pair-wise /// interprocedural optimizations for all call edges in the program. At each /// call site edge, the callee has already been optimized as much as is /// possible. This in turn allows very accurate analysis of it for IPO. @@ -26,6 +26,7 @@ namespace llvm { +extern template class PassManager<LazyCallGraph::SCC>; /// \brief The CGSCC pass manager. /// /// See the documentation for the PassManager template for details. It runs @@ -33,6 +34,7 @@ namespace llvm { /// typedef serves as a convenient way to refer to this construct. typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager; +extern template class AnalysisManager<LazyCallGraph::SCC>; /// \brief The CGSCC analysis manager. /// /// See the documentation for the AnalysisManager template for detail @@ -41,147 +43,16 @@ typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager; /// pass manager infrastructure. typedef AnalysisManager<LazyCallGraph::SCC> CGSCCAnalysisManager; -/// \brief A module analysis which acts as a proxy for a CGSCC analysis -/// manager. -/// -/// This primarily proxies invalidation information from the module analysis -/// manager and module pass manager to a CGSCC analysis manager. You should -/// never use a CGSCC analysis manager from within (transitively) a module -/// pass manager unless your parent module pass has received a proxy result -/// object for it. -class CGSCCAnalysisManagerModuleProxy { -public: - class Result { - public: - explicit Result(CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : CGAM(Arg.CGAM) {} - Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {} - Result &operator=(Result RHS) { - std::swap(CGAM, RHS.CGAM); - return *this; - } - ~Result(); - - /// \brief Accessor for the \c CGSCCAnalysisManager. - CGSCCAnalysisManager &getManager() { return *CGAM; } - - /// \brief Handler for invalidation of the module. - /// - /// If this analysis itself is preserved, then we assume that the call - /// graph of the module hasn't changed and thus we don't need to invalidate - /// *all* cached data associated with a \c SCC* in the \c - /// CGSCCAnalysisManager. - /// - /// Regardless of whether this analysis is marked as preserved, all of the - /// analyses in the \c CGSCCAnalysisManager are potentially invalidated - /// based on the set of preserved analyses. - bool invalidate(Module &M, const PreservedAnalyses &PA); - - private: - CGSCCAnalysisManager *CGAM; - }; - - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "CGSCCAnalysisManagerModuleProxy"; } - - explicit CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManager &CGAM) - : CGAM(&CGAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - CGSCCAnalysisManagerModuleProxy(const CGSCCAnalysisManagerModuleProxy &Arg) - : CGAM(Arg.CGAM) {} - CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManagerModuleProxy &&Arg) - : CGAM(std::move(Arg.CGAM)) {} - CGSCCAnalysisManagerModuleProxy & - operator=(CGSCCAnalysisManagerModuleProxy RHS) { - std::swap(CGAM, RHS.CGAM); - return *this; - } - - /// \brief Run the analysis pass and create our proxy result object. - /// - /// This doesn't do any interesting work, it is primarily used to insert our - /// proxy result object into the module analysis cache so that we can proxy - /// invalidation to the CGSCC analysis manager. - /// - /// In debug builds, it will also assert that the analysis manager is empty - /// as no queries should arrive at the CGSCC analysis manager prior to - /// this analysis being requested. - Result run(Module &M); +extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>; +/// A proxy from a \c CGSCCAnalysisManager to a \c Module. +typedef InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module> + CGSCCAnalysisManagerModuleProxy; -private: - static char PassID; - - CGSCCAnalysisManager *CGAM; -}; - -/// \brief A CGSCC analysis which acts as a proxy for a module analysis -/// manager. -/// -/// This primarily provides an accessor to a parent module analysis manager to -/// CGSCC passes. Only the const interface of the module analysis manager is -/// provided to indicate that once inside of a CGSCC analysis pass you -/// cannot request a module analysis to actually run. Instead, the user must -/// rely on the \c getCachedResult API. -/// -/// This proxy *doesn't* manage the invalidation in any way. That is handled by -/// the recursive return path of each layer of the pass manager and the -/// returned PreservedAnalysis set. -class ModuleAnalysisManagerCGSCCProxy { -public: - /// \brief Result proxy object for \c ModuleAnalysisManagerCGSCCProxy. - class Result { - public: - explicit Result(const ModuleAnalysisManager &MAM) : MAM(&MAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : MAM(Arg.MAM) {} - Result(Result &&Arg) : MAM(std::move(Arg.MAM)) {} - Result &operator=(Result RHS) { - std::swap(MAM, RHS.MAM); - return *this; - } - - const ModuleAnalysisManager &getManager() const { return *MAM; } - - /// \brief Handle invalidation by ignoring it, this pass is immutable. - bool invalidate(LazyCallGraph::SCC &) { return false; } - - private: - const ModuleAnalysisManager *MAM; - }; - - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "ModuleAnalysisManagerCGSCCProxy"; } - - ModuleAnalysisManagerCGSCCProxy(const ModuleAnalysisManager &MAM) - : MAM(&MAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - ModuleAnalysisManagerCGSCCProxy(const ModuleAnalysisManagerCGSCCProxy &Arg) - : MAM(Arg.MAM) {} - ModuleAnalysisManagerCGSCCProxy(ModuleAnalysisManagerCGSCCProxy &&Arg) - : MAM(std::move(Arg.MAM)) {} - ModuleAnalysisManagerCGSCCProxy & - operator=(ModuleAnalysisManagerCGSCCProxy RHS) { - std::swap(MAM, RHS.MAM); - return *this; - } - - /// \brief Run the analysis pass and create our proxy result object. - /// Nothing to see here, it just forwards the \c MAM reference into the - /// result. - Result run(LazyCallGraph::SCC &) { return Result(*MAM); } - -private: - static char PassID; - - const ModuleAnalysisManager *MAM; -}; +extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager, + LazyCallGraph::SCC>; +/// A proxy from a \c ModuleAnalysisManager to an \c SCC. +typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC> + ModuleAnalysisManagerCGSCCProxy; /// \brief The core module pass which does a post-order walk of the SCCs and /// runs a CGSCC pass over each one. @@ -192,21 +63,24 @@ private: /// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC /// pass over the module to enable a \c FunctionAnalysisManager to be used /// within this run safely. -template <typename CGSCCPassT> class ModuleToPostOrderCGSCCPassAdaptor { +template <typename CGSCCPassT> +class ModuleToPostOrderCGSCCPassAdaptor + : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> { public: - explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) - : Pass(std::move(Pass)) {} + explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. ModuleToPostOrderCGSCCPassAdaptor( const ModuleToPostOrderCGSCCPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, ModuleToPostOrderCGSCCPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } ModuleToPostOrderCGSCCPassAdaptor & operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { @@ -215,33 +89,36 @@ public: } /// \brief Runs the CGSCC pass across every SCC in the module. - PreservedAnalyses run(Module &M, ModuleAnalysisManager *AM) { - assert(AM && "We need analyses to compute the call graph!"); - + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { // Setup the CGSCC analysis manager from its proxy. CGSCCAnalysisManager &CGAM = - AM->getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager(); + AM.getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager(); // Get the call graph for this module. - LazyCallGraph &CG = AM->getResult<LazyCallGraphAnalysis>(M); + LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M); PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::SCC &C : CG.postorder_sccs()) { - PreservedAnalyses PassPA = Pass.run(C, &CGAM); - - // We know that the CGSCC pass couldn't have invalidated any other - // SCC's analyses (that's the contract of a CGSCC pass), so - // directly handle the CGSCC analysis manager's invalidation here. We - // also update the preserved set of analyses to reflect that invalidated - // analyses are now safe to preserve. - // FIXME: This isn't quite correct. We need to handle the case where the - // pass updated the CG, particularly some child of the current SCC, and - // invalidate its analyses. - PassPA = CGAM.invalidate(C, std::move(PassPA)); - - // Then intersect the preserved set so that invalidation of module - // analyses will eventually occur when the module pass completes. - PA.intersect(std::move(PassPA)); + for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) { + if (DebugLogging) + dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n"; + + for (LazyCallGraph::SCC &C : RC) { + PreservedAnalyses PassPA = Pass.run(C, CGAM); + + // We know that the CGSCC pass couldn't have invalidated any other + // SCC's analyses (that's the contract of a CGSCC pass), so + // directly handle the CGSCC analysis manager's invalidation here. We + // also update the preserved set of analyses to reflect that invalidated + // analyses are now safe to preserve. + // FIXME: This isn't quite correct. We need to handle the case where the + // pass updated the CG, particularly some child of the current SCC, and + // invalidate its analyses. + PassPA = CGAM.invalidate(C, std::move(PassPA)); + + // Then intersect the preserved set so that invalidation of module + // analyses will eventually occur when the module pass completes. + PA.intersect(std::move(PassPA)); + } } // By definition we preserve the proxy. This precludes *any* invalidation @@ -252,163 +129,29 @@ public: return PA; } - static StringRef name() { return "ModuleToPostOrderCGSCCPassAdaptor"; } - private: CGSCCPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template <typename CGSCCPassT> ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT> -createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { - return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass)); +createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) { + return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging); } -/// \brief A CGSCC analysis which acts as a proxy for a function analysis -/// manager. -/// -/// This primarily proxies invalidation information from the CGSCC analysis -/// manager and CGSCC pass manager to a function analysis manager. You should -/// never use a function analysis manager from within (transitively) a CGSCC -/// pass manager unless your parent CGSCC pass has received a proxy result -/// object for it. -class FunctionAnalysisManagerCGSCCProxy { -public: - class Result { - public: - explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : FAM(Arg.FAM) {} - Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {} - Result &operator=(Result RHS) { - std::swap(FAM, RHS.FAM); - return *this; - } - ~Result(); - - /// \brief Accessor for the \c FunctionAnalysisManager. - FunctionAnalysisManager &getManager() { return *FAM; } - - /// \brief Handler for invalidation of the SCC. - /// - /// If this analysis itself is preserved, then we assume that the set of \c - /// Function objects in the \c SCC hasn't changed and thus we don't need - /// to invalidate *all* cached data associated with a \c Function* in the \c - /// FunctionAnalysisManager. - /// - /// Regardless of whether this analysis is marked as preserved, all of the - /// analyses in the \c FunctionAnalysisManager are potentially invalidated - /// based on the set of preserved analyses. - bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA); - - private: - FunctionAnalysisManager *FAM; - }; - - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "FunctionAnalysisManagerCGSCCProxy"; } - - explicit FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManager &FAM) - : FAM(&FAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - FunctionAnalysisManagerCGSCCProxy( - const FunctionAnalysisManagerCGSCCProxy &Arg) - : FAM(Arg.FAM) {} - FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManagerCGSCCProxy &&Arg) - : FAM(std::move(Arg.FAM)) {} - FunctionAnalysisManagerCGSCCProxy & - operator=(FunctionAnalysisManagerCGSCCProxy RHS) { - std::swap(FAM, RHS.FAM); - return *this; - } - - /// \brief Run the analysis pass and create our proxy result object. - /// - /// This doesn't do any interesting work, it is primarily used to insert our - /// proxy result object into the module analysis cache so that we can proxy - /// invalidation to the function analysis manager. - /// - /// In debug builds, it will also assert that the analysis manager is empty - /// as no queries should arrive at the function analysis manager prior to - /// this analysis being requested. - Result run(LazyCallGraph::SCC &C); - -private: - static char PassID; - - FunctionAnalysisManager *FAM; -}; - -/// \brief A function analysis which acts as a proxy for a CGSCC analysis -/// manager. -/// -/// This primarily provides an accessor to a parent CGSCC analysis manager to -/// function passes. Only the const interface of the CGSCC analysis manager is -/// provided to indicate that once inside of a function analysis pass you -/// cannot request a CGSCC analysis to actually run. Instead, the user must -/// rely on the \c getCachedResult API. -/// -/// This proxy *doesn't* manage the invalidation in any way. That is handled by -/// the recursive return path of each layer of the pass manager and the -/// returned PreservedAnalysis set. -class CGSCCAnalysisManagerFunctionProxy { -public: - /// \brief Result proxy object for \c CGSCCAnalysisManagerFunctionProxy. - class Result { - public: - explicit Result(const CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : CGAM(Arg.CGAM) {} - Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {} - Result &operator=(Result RHS) { - std::swap(CGAM, RHS.CGAM); - return *this; - } - - const CGSCCAnalysisManager &getManager() const { return *CGAM; } - - /// \brief Handle invalidation by ignoring it, this pass is immutable. - bool invalidate(Function &) { return false; } +extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager, + LazyCallGraph::SCC>; +/// A proxy from a \c FunctionAnalysisManager to an \c SCC. +typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, LazyCallGraph::SCC> + FunctionAnalysisManagerCGSCCProxy; - private: - const CGSCCAnalysisManager *CGAM; - }; - - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "CGSCCAnalysisManagerFunctionProxy"; } - - CGSCCAnalysisManagerFunctionProxy(const CGSCCAnalysisManager &CGAM) - : CGAM(&CGAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - CGSCCAnalysisManagerFunctionProxy( - const CGSCCAnalysisManagerFunctionProxy &Arg) - : CGAM(Arg.CGAM) {} - CGSCCAnalysisManagerFunctionProxy(CGSCCAnalysisManagerFunctionProxy &&Arg) - : CGAM(std::move(Arg.CGAM)) {} - CGSCCAnalysisManagerFunctionProxy & - operator=(CGSCCAnalysisManagerFunctionProxy RHS) { - std::swap(CGAM, RHS.CGAM); - return *this; - } - - /// \brief Run the analysis pass and create our proxy result object. - /// Nothing to see here, it just forwards the \c CGAM reference into the - /// result. - Result run(Function &) { return Result(*CGAM); } - -private: - static char PassID; - - const CGSCCAnalysisManager *CGAM; -}; +extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>; +/// A proxy from a \c CGSCCAnalysisManager to a \c Function. +typedef OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function> + CGSCCAnalysisManagerFunctionProxy; /// \brief Adaptor that maps from a SCC to its functions. /// @@ -418,20 +161,23 @@ private: /// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function /// pass over the SCC to enable a \c FunctionAnalysisManager to be used /// within this run safely. -template <typename FunctionPassT> class CGSCCToFunctionPassAdaptor { +template <typename FunctionPassT> +class CGSCCToFunctionPassAdaptor + : public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> { public: - explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass) - : Pass(std::move(Pass)) {} + explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { swap(*this, RHS); @@ -439,23 +185,24 @@ public: } /// \brief Runs the function pass across every function in the module. - PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager *AM) { - FunctionAnalysisManager *FAM = nullptr; - if (AM) - // Setup the function analysis manager from its proxy. - FAM = &AM->getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager(); + PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { + // Setup the function analysis manager from its proxy. + FunctionAnalysisManager &FAM = + AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager(); + + if (DebugLogging) + dbgs() << "Running function passes across an SCC: " << C << "\n"; PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::Node *N : C) { - PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM); + for (LazyCallGraph::Node &N : C) { + PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM); // We know that the function pass couldn't have invalidated any other // function's analyses (that's the contract of a function pass), so // directly handle the function analysis manager's invalidation here. // Also, update the preserved analyses to reflect that once invalidated // these can again be preserved. - if (FAM) - PassPA = FAM->invalidate(N->getFunction(), std::move(PassPA)); + PassPA = FAM.invalidate(N.getFunction(), std::move(PassPA)); // Then intersect the preserved set so that invalidation of module // analyses will eventually occur when the module pass completes. @@ -472,18 +219,18 @@ public: return PA; } - static StringRef name() { return "CGSCCToFunctionPassAdaptor"; } - private: FunctionPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template <typename FunctionPassT> CGSCCToFunctionPassAdaptor<FunctionPassT> -createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) { - return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass)); +createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) { + return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass), + DebugLogging); } } diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index 5562e9b9465f..4ecacb0f0be2 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -57,6 +57,7 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/Function.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include <map> @@ -294,20 +295,27 @@ private: /// This class implements the concept of an analysis pass used by the \c /// ModuleAnalysisManager to run an analysis over a module and cache the /// resulting data. -class CallGraphAnalysis { +class CallGraphAnalysis : public AnalysisInfoMixin<CallGraphAnalysis> { + friend AnalysisInfoMixin<CallGraphAnalysis>; + static char PassID; + public: /// \brief A formulaic typedef to inform clients of the result type. typedef CallGraph Result; - static void *ID() { return (void *)&PassID; } - /// \brief Compute the \c CallGraph for the module \c M. /// /// The real work here is done in the \c CallGraph constructor. - CallGraph run(Module *M) { return CallGraph(*M); } + CallGraph run(Module &M, ModuleAnalysisManager &) { return CallGraph(M); } +}; -private: - static char PassID; +/// \brief Printer pass for the \c CallGraphAnalysis results. +class CallGraphPrinterPass : public PassInfoMixin<CallGraphPrinterPass> { + raw_ostream &OS; + +public: + explicit CallGraphPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); }; /// \brief The \c ModulePass which wraps up a \c CallGraph and the logic to diff --git a/include/llvm/Analysis/CallGraphSCCPass.h b/include/llvm/Analysis/CallGraphSCCPass.h index 9c7f7bd34cce..cb35b3292be7 100644 --- a/include/llvm/Analysis/CallGraphSCCPass.h +++ b/include/llvm/Analysis/CallGraphSCCPass.h @@ -23,6 +23,7 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Pass.h" +#include "llvm/PassSupport.h" namespace llvm { @@ -77,15 +78,21 @@ public: /// the call graph. If the derived class implements this method, it should /// always explicitly call the implementation here. void getAnalysisUsage(AnalysisUsage &Info) const override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipSCC(CallGraphSCC &SCC) const; }; /// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on. class CallGraphSCC { + const CallGraph &CG; // The call graph for this SCC. void *Context; // The CGPassManager object that is vending this. std::vector<CallGraphNode*> Nodes; public: - CallGraphSCC(void *context) : Context(context) {} + CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {} void initialize(CallGraphNode *const *I, CallGraphNode *const *E) { Nodes.assign(I, E); @@ -101,6 +108,25 @@ public: typedef std::vector<CallGraphNode *>::const_iterator iterator; iterator begin() const { return Nodes.begin(); } iterator end() const { return Nodes.end(); } + + const CallGraph &getCallGraph() { return CG; } +}; + +void initializeDummyCGSCCPassPass(PassRegistry &); + +/// This pass is required by interprocedural register allocation. It forces +/// codegen to follow bottom up order on call graph. +class DummyCGSCCPass : public CallGraphSCCPass { +public: + static char ID; + DummyCGSCCPass() : CallGraphSCCPass(ID) { + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializeDummyCGSCCPassPass(Registry); + }; + bool runOnSCC(CallGraphSCC &SCC) override { return false; } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } }; } // End llvm namespace diff --git a/include/llvm/Analysis/CallPrinter.h b/include/llvm/Analysis/CallPrinter.h index 5f5d160c3ca0..8b697d5aa149 100644 --- a/include/llvm/Analysis/CallPrinter.h +++ b/include/llvm/Analysis/CallPrinter.h @@ -17,10 +17,10 @@ namespace llvm { - class ModulePass; +class ModulePass; - ModulePass *createCallGraphViewerPass(); - ModulePass *createCallGraphPrinterPass(); +ModulePass *createCallGraphViewerPass(); +ModulePass *createCallGraphDOTPrinterPass(); } // end namespace llvm diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h index 2f5969129e02..f512aca57865 100644 --- a/include/llvm/Analysis/CodeMetrics.h +++ b/include/llvm/Analysis/CodeMetrics.h @@ -42,50 +42,48 @@ bool callIsSmall(ImmutableCallSite CS); struct CodeMetrics { /// \brief True if this function contains a call to setjmp or other functions /// with attribute "returns twice" without having the attribute itself. - bool exposesReturnsTwice; + bool exposesReturnsTwice = false; /// \brief True if this function calls itself. - bool isRecursive; + bool isRecursive = false; /// \brief True if this function cannot be duplicated. /// /// True if this function contains one or more indirect branches, or it contains /// one or more 'noduplicate' instructions. - bool notDuplicatable; + bool notDuplicatable = false; + + /// \brief True if this function contains a call to a convergent function. + bool convergent = false; /// \brief True if this function calls alloca (in the C sense). - bool usesDynamicAlloca; + bool usesDynamicAlloca = false; /// \brief Number of instructions in the analyzed blocks. - unsigned NumInsts; + unsigned NumInsts = false; /// \brief Number of analyzed blocks. - unsigned NumBlocks; + unsigned NumBlocks = false; /// \brief Keeps track of basic block code size estimates. DenseMap<const BasicBlock *, unsigned> NumBBInsts; /// \brief Keep track of the number of calls to 'big' functions. - unsigned NumCalls; + unsigned NumCalls = false; /// \brief The number of calls to internal functions with a single caller. /// /// These are likely targets for future inlining, likely exposed by /// interleaved devirtualization. - unsigned NumInlineCandidates; + unsigned NumInlineCandidates = 0; /// \brief How many instructions produce vector values. /// /// The inliner is more aggressive with inlining vector kernels. - unsigned NumVectorInsts; + unsigned NumVectorInsts = 0; /// \brief How many 'ret' instructions the blocks contain. - unsigned NumRets; - - CodeMetrics() - : exposesReturnsTwice(false), isRecursive(false), notDuplicatable(false), - usesDynamicAlloca(false), NumInsts(0), NumBlocks(0), NumCalls(0), - NumInlineCandidates(0), NumVectorInsts(0), NumRets(0) {} + unsigned NumRets = 0; /// \brief Add information about a block to the current state. void analyzeBasicBlock(const BasicBlock *BB, const TargetTransformInfo &TTI, diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h index e8185b3b6307..b1504004d83c 100644 --- a/include/llvm/Analysis/ConstantFolding.h +++ b/include/llvm/Analysis/ConstantFolding.h @@ -21,30 +21,46 @@ #define LLVM_ANALYSIS_CONSTANTFOLDING_H namespace llvm { - class Constant; - class ConstantExpr; - class Instruction; - class DataLayout; - class TargetLibraryInfo; - class Function; - class Type; - template<typename T> - class ArrayRef; +class APInt; +template <typename T> class ArrayRef; +class Constant; +class ConstantExpr; +class DataLayout; +class Function; +class GlobalValue; +class Instruction; +class TargetLibraryInfo; +class Type; + +/// If this constant is a constant offset from a global, return the global and +/// the constant. Because of constantexprs, this function is recursive. +bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset, + const DataLayout &DL); /// ConstantFoldInstruction - Try to constant fold the specified instruction. /// If successful, the constant result is returned, if not, null is returned. /// Note that this fails if not all of the operands are constant. Otherwise, /// this function can only fail when attempting to fold instructions like loads /// and stores, which have no constant expression form. - Constant *ConstantFoldInstruction(Instruction *I, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); +Constant *ConstantFoldInstruction(Instruction *I, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr); /// ConstantFoldConstantExpression - Attempt to fold the constant expression /// using the specified DataLayout. If successful, the constant result is /// result is returned, if not, null is returned. - Constant * - ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); +Constant * +ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr); + +/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the +/// specified operands. If successful, the constant result is returned, if not, +/// null is returned. Note that this function can fail when attempting to +/// fold instructions like loads and stores, which have no constant expression +/// form. +/// +Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops, + const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr); /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the /// specified operands. If successful, the constant result is returned, if not, @@ -52,19 +68,32 @@ namespace llvm { /// fold instructions like loads and stores, which have no constant expression /// form. /// - Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy, - ArrayRef<Constant *> Ops, - const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); +/// This function doesn't work for compares (use ConstantFoldCompareInstOperands +/// for this) and GEPs. +Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy, + ArrayRef<Constant *> Ops, + const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr); /// ConstantFoldCompareInstOperands - Attempt to constant fold a compare /// instruction (icmp/fcmp) with the specified operands. If it fails, it /// returns a constant expression of the specified operands. /// - Constant * - ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS, - Constant *RHS, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); +Constant * +ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS, + Constant *RHS, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr); + +/// \brief Attempt to constant fold a binary operation with the specified +/// operands. If it fails, it returns a constant expression of the specified +/// operands. +Constant *ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS, + Constant *RHS, const DataLayout &DL); + +/// \brief Attempt to constant fold a cast with the specified operand. If it +/// fails, it returns a constant expression of the specified operand. +Constant *ConstantFoldCastOperand(unsigned Opcode, Constant *C, Type *DestTy, + const DataLayout &DL); /// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue /// instruction with the specified operands and indices. The constant result is @@ -86,7 +115,7 @@ Constant *ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx); /// ConstantFoldLoadFromConstPtr - Return the value that a load from C would /// produce if it is constant and determinable. If this is not determinable, /// return null. -Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout &DL); +Constant *ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, const DataLayout &DL); /// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a /// getelementptr constantexpr, return the constant value being addressed by the @@ -98,7 +127,7 @@ Constant *ConstantFoldLoadThroughGEPConstantExpr(Constant *C, ConstantExpr *CE); /// return the constant value being addressed by a virtual load, or null if /// something is funny and we can't decide. Constant *ConstantFoldLoadThroughGEPIndices(Constant *C, - ArrayRef<Constant*> Indices); + ArrayRef<Constant *> Indices); /// canConstantFoldCallTo - Return true if its even possible to fold a call to /// the specified function. diff --git a/include/llvm/Analysis/DemandedBits.h b/include/llvm/Analysis/DemandedBits.h index 42932bfd3491..fafd5d00b481 100644 --- a/include/llvm/Analysis/DemandedBits.h +++ b/include/llvm/Analysis/DemandedBits.h @@ -26,6 +26,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/PassManager.h" namespace llvm { @@ -35,40 +36,81 @@ class Instruction; class DominatorTree; class AssumptionCache; -struct DemandedBits : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - DemandedBits(); +class DemandedBits { +public: + DemandedBits(Function &F, AssumptionCache &AC, DominatorTree &DT) : + F(F), AC(AC), DT(DT), Analyzed(false) {} - bool runOnFunction(Function& F) override; - void getAnalysisUsage(AnalysisUsage& AU) const override; - void print(raw_ostream &OS, const Module *M) const override; - /// Return the bits demanded from instruction I. APInt getDemandedBits(Instruction *I); /// Return true if, during analysis, I could not be reached. bool isInstructionDead(Instruction *I); + + void print(raw_ostream &OS); private: + Function &F; + AssumptionCache &AC; + DominatorTree &DT; + void performAnalysis(); void determineLiveOperandBits(const Instruction *UserI, - const Instruction *I, unsigned OperandNo, - const APInt &AOut, APInt &AB, - APInt &KnownZero, APInt &KnownOne, - APInt &KnownZero2, APInt &KnownOne2); - - AssumptionCache *AC; - DominatorTree *DT; - Function *F; + const Instruction *I, unsigned OperandNo, + const APInt &AOut, APInt &AB, + APInt &KnownZero, APInt &KnownOne, + APInt &KnownZero2, APInt &KnownOne2); + bool Analyzed; // The set of visited instructions (non-integer-typed only). - SmallPtrSet<Instruction*, 128> Visited; + SmallPtrSet<Instruction*, 32> Visited; DenseMap<Instruction *, APInt> AliveBits; }; +class DemandedBitsWrapperPass : public FunctionPass { +private: + mutable Optional<DemandedBits> DB; +public: + static char ID; // Pass identification, replacement for typeid + DemandedBitsWrapperPass(); + + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Clean up memory in between runs + void releaseMemory() override; + + DemandedBits &getDemandedBits() { return *DB; } + + void print(raw_ostream &OS, const Module *M) const override; +}; + +/// An analysis that produces \c DemandedBits for a function. +class DemandedBitsAnalysis : public AnalysisInfoMixin<DemandedBitsAnalysis> { + friend AnalysisInfoMixin<DemandedBitsAnalysis>; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef DemandedBits Result; + + /// \brief Run the analysis pass over a function and produce demanded bits + /// information. + DemandedBits run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for DemandedBits +class DemandedBitsPrinterPass : public PassInfoMixin<DemandedBitsPrinterPass> { + raw_ostream &OS; + +public: + explicit DemandedBitsPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + /// Create a demanded bits analysis pass. -FunctionPass *createDemandedBitsPass(); +FunctionPass *createDemandedBitsWrapperPass(); } // End llvm namespace diff --git a/include/llvm/Analysis/DependenceAnalysis.h b/include/llvm/Analysis/DependenceAnalysis.h index 5290552b41dc..32dd367a9c0a 100644 --- a/include/llvm/Analysis/DependenceAnalysis.h +++ b/include/llvm/Analysis/DependenceAnalysis.h @@ -41,12 +41,12 @@ #define LLVM_ANALYSIS_DEPENDENCEANALYSIS_H #include "llvm/ADT/SmallBitVector.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/Instructions.h" #include "llvm/Pass.h" namespace llvm { +template <typename T> class ArrayRef; class Loop; class LoopInfo; class ScalarEvolution; @@ -206,7 +206,7 @@ namespace llvm { private: Instruction *Src, *Dst; const Dependence *NextPredecessor, *NextSuccessor; - friend class DependenceAnalysis; + friend class DependenceInfo; }; /// FullDependence - This class represents a dependence between two memory @@ -274,16 +274,17 @@ namespace llvm { bool LoopIndependent; bool Consistent; // Init to true, then refine. std::unique_ptr<DVEntry[]> DV; - friend class DependenceAnalysis; + friend class DependenceInfo; }; - /// DependenceAnalysis - This class is the main dependence-analysis driver. + /// DependenceInfo - This class is the main dependence-analysis driver. /// - class DependenceAnalysis : public FunctionPass { - void operator=(const DependenceAnalysis &) = delete; - DependenceAnalysis(const DependenceAnalysis &) = delete; - + class DependenceInfo { public: + DependenceInfo(Function *F, AliasAnalysis *AA, ScalarEvolution *SE, + LoopInfo *LI) + : AA(AA), SE(SE), LI(LI), F(F) {} + /// depends - Tests for a dependence between the Src and Dst instructions. /// Returns NULL if no dependence; otherwise, returns a Dependence (or a /// FullDependence) with as much information as can be gleaned. @@ -336,6 +337,8 @@ namespace llvm { /// both loops. const SCEV *getSplitIteration(const Dependence &Dep, unsigned Level); + Function *getFunction() const { return F; } + private: AliasAnalysis *AA; ScalarEvolution *SE; @@ -919,22 +922,41 @@ namespace llvm { bool tryDelinearize(Instruction *Src, Instruction *Dst, SmallVectorImpl<Subscript> &Pair); + }; // class DependenceInfo + /// \brief AnalysisPass to compute dependence information in a function + class DependenceAnalysis : public AnalysisInfoMixin<DependenceAnalysis> { + public: + typedef DependenceInfo Result; + Result run(Function &F, FunctionAnalysisManager &FAM); + + private: + static char PassID; + friend struct AnalysisInfoMixin<DependenceAnalysis>; + }; // class DependenceAnalysis + + /// \brief Legacy pass manager pass to access dependence information + class DependenceAnalysisWrapperPass : public FunctionPass { public: static char ID; // Class identification, replacement for typeinfo - DependenceAnalysis() : FunctionPass(ID) { - initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry()); + DependenceAnalysisWrapperPass() : FunctionPass(ID) { + initializeDependenceAnalysisWrapperPassPass( + *PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; void releaseMemory() override; void getAnalysisUsage(AnalysisUsage &) const override; void print(raw_ostream &, const Module * = nullptr) const override; - }; // class DependenceAnalysis + DependenceInfo &getDI() const; + + private: + std::unique_ptr<DependenceInfo> info; + }; // class DependenceAnalysisWrapperPass /// createDependenceAnalysisPass - This creates an instance of the - /// DependenceAnalysis pass. - FunctionPass *createDependenceAnalysisPass(); + /// DependenceAnalysis wrapper pass. + FunctionPass *createDependenceAnalysisWrapperPass(); } // namespace llvm diff --git a/include/llvm/Analysis/DominanceFrontier.h b/include/llvm/Analysis/DominanceFrontier.h index fb730054a8e5..79672e4e4225 100644 --- a/include/llvm/Analysis/DominanceFrontier.h +++ b/include/llvm/Analysis/DominanceFrontier.h @@ -19,6 +19,7 @@ #define LLVM_ANALYSIS_DOMINANCEFRONTIER_H #include "llvm/IR/Dominators.h" +#include "llvm/IR/PassManager.h" #include <map> #include <set> @@ -133,63 +134,24 @@ public: const DomSetType &calculate(const DomTreeT &DT, const DomTreeNodeT *Node); }; -class DominanceFrontier : public FunctionPass { - ForwardDominanceFrontierBase<BasicBlock> Base; - +class DominanceFrontier : public ForwardDominanceFrontierBase<BasicBlock> { public: typedef DominatorTreeBase<BasicBlock> DomTreeT; typedef DomTreeNodeBase<BasicBlock> DomTreeNodeT; typedef DominanceFrontierBase<BasicBlock>::DomSetType DomSetType; typedef DominanceFrontierBase<BasicBlock>::iterator iterator; typedef DominanceFrontierBase<BasicBlock>::const_iterator const_iterator; +}; +class DominanceFrontierWrapperPass : public FunctionPass { + DominanceFrontier DF; +public: static char ID; // Pass ID, replacement for typeid - DominanceFrontier(); - - ForwardDominanceFrontierBase<BasicBlock> &getBase() { return Base; } - - inline const std::vector<BasicBlock *> &getRoots() const { - return Base.getRoots(); - } - - BasicBlock *getRoot() const { return Base.getRoot(); } - - bool isPostDominator() const { return Base.isPostDominator(); } - - iterator begin() { return Base.begin(); } + DominanceFrontierWrapperPass(); - const_iterator begin() const { return Base.begin(); } - - iterator end() { return Base.end(); } - - const_iterator end() const { return Base.end(); } - - iterator find(BasicBlock *B) { return Base.find(B); } - - const_iterator find(BasicBlock *B) const { return Base.find(B); } - - iterator addBasicBlock(BasicBlock *BB, const DomSetType &frontier) { - return Base.addBasicBlock(BB, frontier); - } - - void removeBlock(BasicBlock *BB) { return Base.removeBlock(BB); } - - void addToFrontier(iterator I, BasicBlock *Node) { - return Base.addToFrontier(I, Node); - } - - void removeFromFrontier(iterator I, BasicBlock *Node) { - return Base.removeFromFrontier(I, Node); - } - - bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const { - return Base.compareDomSet(DS1, DS2); - } - - bool compare(DominanceFrontierBase<BasicBlock> &Other) const { - return Base.compare(Other); - } + DominanceFrontier &getDominanceFrontier() { return DF; } + const DominanceFrontier &getDominanceFrontier() const { return DF; } void releaseMemory() override; @@ -205,6 +167,30 @@ public: extern template class DominanceFrontierBase<BasicBlock>; extern template class ForwardDominanceFrontierBase<BasicBlock>; +/// \brief Analysis pass which computes a \c DominanceFrontier. +class DominanceFrontierAnalysis + : public AnalysisInfoMixin<DominanceFrontierAnalysis> { + friend AnalysisInfoMixin<DominanceFrontierAnalysis>; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef DominanceFrontier Result; + + /// \brief Run the analysis pass over a function and produce a dominator tree. + DominanceFrontier run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for the \c DominanceFrontier. +class DominanceFrontierPrinterPass + : public PassInfoMixin<DominanceFrontierPrinterPass> { + raw_ostream &OS; + +public: + explicit DominanceFrontierPrinterPass(raw_ostream &OS); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + } // End llvm namespace #endif diff --git a/include/llvm/Analysis/EHPersonalities.h b/include/llvm/Analysis/EHPersonalities.h index 59e9672b88e5..a26c575cfe10 100644 --- a/include/llvm/Analysis/EHPersonalities.h +++ b/include/llvm/Analysis/EHPersonalities.h @@ -23,12 +23,15 @@ enum class EHPersonality { Unknown, GNU_Ada, GNU_C, + GNU_C_SjLj, GNU_CXX, + GNU_CXX_SjLj, GNU_ObjC, MSVC_X86SEH, MSVC_Win64SEH, MSVC_CXX, - CoreCLR + CoreCLR, + Rust }; /// \brief See if the given exception handling personality function is one diff --git a/include/llvm/Analysis/GlobalsModRef.h b/include/llvm/Analysis/GlobalsModRef.h index bcd102e7ded2..4c0a98949778 100644 --- a/include/llvm/Analysis/GlobalsModRef.h +++ b/include/llvm/Analysis/GlobalsModRef.h @@ -35,6 +35,7 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> { class FunctionInfo; const DataLayout &DL; + const TargetLibraryInfo &TLI; /// The globals that do not have their addresses taken. SmallPtrSet<const GlobalValue *, 8> NonAddressTakenGlobals; @@ -76,6 +77,7 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> { public: GlobalsAAResult(GlobalsAAResult &&Arg); + ~GlobalsAAResult(); static GlobalsAAResult analyzeModule(Module &M, const TargetLibraryInfo &TLI, CallGraph &CG); @@ -116,20 +118,14 @@ private: }; /// Analysis pass providing a never-invalidated alias analysis result. -class GlobalsAA { +class GlobalsAA : public AnalysisInfoMixin<GlobalsAA> { + friend AnalysisInfoMixin<GlobalsAA>; + static char PassID; + public: typedef GlobalsAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - GlobalsAAResult run(Module &M, AnalysisManager<Module> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "GlobalsAA"; } - -private: - static char PassID; + GlobalsAAResult run(Module &M, AnalysisManager<Module> &AM); }; /// Legacy wrapper pass to provide the GlobalsAAResult object. diff --git a/include/llvm/Analysis/IVUsers.h b/include/llvm/Analysis/IVUsers.h index 37d01490dac6..e68a77526b96 100644 --- a/include/llvm/Analysis/IVUsers.h +++ b/include/llvm/Analysis/IVUsers.h @@ -117,7 +117,7 @@ private: mutable ilist_node<IVStrideUse> Sentinel; }; -class IVUsers : public LoopPass { +class IVUsers { friend class IVStrideUse; Loop *L; AssumptionCache *AC; @@ -133,15 +133,9 @@ class IVUsers : public LoopPass { // Ephemeral values used by @llvm.assume in this function. SmallPtrSet<const Value *, 32> EphValues; - void getAnalysisUsage(AnalysisUsage &AU) const override; - - bool runOnLoop(Loop *L, LPPassManager &LPM) override; - - void releaseMemory() override; - public: - static char ID; // Pass ID, replacement for typeid - IVUsers(); + IVUsers(Loop *L, AssumptionCache *AC, LoopInfo *LI, DominatorTree *DT, + ScalarEvolution *SE); Loop *getLoop() const { return L; } @@ -173,16 +167,58 @@ public: return Processed.count(Inst); } - void print(raw_ostream &OS, const Module* = nullptr) const override; + void releaseMemory(); + + void print(raw_ostream &OS, const Module * = nullptr) const; /// dump - This method is used for debugging. void dump() const; + protected: bool AddUsersImpl(Instruction *I, SmallPtrSetImpl<Loop*> &SimpleLoopNests); }; Pass *createIVUsersPass(); +class IVUsersWrapperPass : public LoopPass { + std::unique_ptr<IVUsers> IU; + +public: + static char ID; + + IVUsersWrapperPass(); + + IVUsers &getIU() { return *IU; } + const IVUsers &getIU() const { return *IU; } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + bool runOnLoop(Loop *L, LPPassManager &LPM) override; + + void releaseMemory() override; + + void print(raw_ostream &OS, const Module * = nullptr) const override; +}; + +/// Analysis pass that exposes the \c IVUsers for a loop. +class IVUsersAnalysis : public AnalysisInfoMixin<IVUsersAnalysis> { + friend AnalysisInfoMixin<IVUsersAnalysis>; + static char PassID; + +public: + typedef IVUsers Result; + + IVUsers run(Loop &L, AnalysisManager<Loop> &AM); +}; + +/// Printer pass for the \c IVUsers for a loop. +class IVUsersPrinterPass : public PassInfoMixin<IVUsersPrinterPass> { + raw_ostream &OS; + +public: + explicit IVUsersPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; } #endif diff --git a/include/llvm/Analysis/IndirectCallPromotionAnalysis.h b/include/llvm/Analysis/IndirectCallPromotionAnalysis.h new file mode 100644 index 000000000000..007e4d8602fa --- /dev/null +++ b/include/llvm/Analysis/IndirectCallPromotionAnalysis.h @@ -0,0 +1,67 @@ +//===- IndirectCallPromotionAnalysis.h - Indirect call analysis -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Interface to identify indirect call promotion candidates. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H +#define LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H + +#include "llvm/ProfileData/InstrProf.h" + +namespace llvm { + +class Instruction; + +// Class for identifying profitable indirect call promotion candidates when +// the indirect-call value profile metadata is available. +class ICallPromotionAnalysis { +private: + // Allocate space to read the profile annotation. + std::unique_ptr<InstrProfValueData[]> ValueDataArray; + + // Count is the call count for the direct-call target and + // TotalCount is the call count for the indirect-call callsite. + // Return true we should promote this indirect-call target. + bool isPromotionProfitable(uint64_t Count, uint64_t TotalCount); + + // Returns the number of profitable candidates to promote for the + // current ValueDataArray and the given \p Inst. + uint32_t getProfitablePromotionCandidates(const Instruction *Inst, + uint32_t NumVals, + uint64_t TotalCount); + + // Noncopyable + ICallPromotionAnalysis(const ICallPromotionAnalysis &other) = delete; + ICallPromotionAnalysis & + operator=(const ICallPromotionAnalysis &other) = delete; + +public: + ICallPromotionAnalysis(); + + /// \brief Returns reference to array of InstrProfValueData for the given + /// instruction \p I. + /// + /// The \p NumVals, \p TotalCount and \p NumCandidates + /// are set to the number of values in the array, the total profile count + /// of the indirect call \p I, and the number of profitable candidates + /// in the given array (which is sorted in reverse order of profitability). + /// + /// The returned array space is owned by this class, and overwritten on + /// subsequent calls. + ArrayRef<InstrProfValueData> + getPromotionCandidatesForInstruction(const Instruction *I, uint32_t &NumVals, + uint64_t &TotalCount, + uint32_t &NumCandidates); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/IndirectCallSiteVisitor.h b/include/llvm/Analysis/IndirectCallSiteVisitor.h new file mode 100644 index 000000000000..71a8cb886321 --- /dev/null +++ b/include/llvm/Analysis/IndirectCallSiteVisitor.h @@ -0,0 +1,43 @@ +//===-- IndirectCallSiteVisitor.h - indirect call-sites visitor -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements defines a visitor class and a helper function that find +// all indirect call-sites in a function. + +#include "llvm/IR/InstVisitor.h" +#include <vector> + +namespace llvm { +// Visitor class that finds all indirect call sites. +struct PGOIndirectCallSiteVisitor + : public InstVisitor<PGOIndirectCallSiteVisitor> { + std::vector<Instruction *> IndirectCallInsts; + PGOIndirectCallSiteVisitor() {} + + void visitCallSite(CallSite CS) { + if (CS.getCalledFunction() || !CS.getCalledValue()) + return; + Instruction *I = CS.getInstruction(); + if (CallInst *CI = dyn_cast<CallInst>(I)) { + if (CI->isInlineAsm()) + return; + } + if (isa<Constant>(CS.getCalledValue())) + return; + IndirectCallInsts.push_back(I); + } +}; + +// Helper function that finds all indirect call sites. +static inline std::vector<Instruction *> findIndirectCallSites(Function &F) { + PGOIndirectCallSiteVisitor ICV; + ICV.visit(F); + return ICV.IndirectCallInsts; +} +} diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index 35f991cb3f67..2928d2be30e5 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -23,6 +23,7 @@ class AssumptionCacheTracker; class CallSite; class DataLayout; class Function; +class ProfileSummaryInfo; class TargetTransformInfo; namespace InlineConstants { @@ -101,25 +102,31 @@ public: /// \brief Get an InlineCost object representing the cost of inlining this /// callsite. /// -/// Note that threshold is passed into this function. Only costs below the -/// threshold are computed with any accuracy. The threshold can be used to -/// bound the computation necessary to determine whether the cost is +/// Note that a default threshold is passed into this function. This threshold +/// could be modified based on callsite's properties and only costs below this +/// new threshold are computed with any accuracy. The new threshold can be +/// used to bound the computation necessary to determine whether the cost is /// sufficiently low to warrant inlining. /// /// Also note that calling this function *dynamically* computes the cost of /// inlining the callsite. It is an expensive, heavyweight call. -InlineCost getInlineCost(CallSite CS, int Threshold, +InlineCost getInlineCost(CallSite CS, int DefaultThreshold, TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT); + AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); /// \brief Get an InlineCost with the callee explicitly specified. /// This allows you to calculate the cost of inlining a function via a /// pointer. This behaves exactly as the version with no explicit callee /// parameter in all other respects. // -InlineCost getInlineCost(CallSite CS, Function *Callee, int Threshold, +InlineCost getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold, TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT); + AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); + +int computeThresholdFromOptLevels(unsigned OptLevel, unsigned SizeOptLevel); + +/// \brief Return the default value of -inline-threshold. +int getDefaultInlineThreshold(); /// \brief Minimal filter to detect invalid constructs for inlining. bool isInlineViable(Function &Callee); diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index ed313dae9ab1..410fa4165a91 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -46,8 +46,7 @@ namespace llvm { class Type; class Value; - /// SimplifyAddInst - Given operands for an Add, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an Add, fold the result or return null. Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -55,8 +54,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifySubInst - Given operands for a Sub, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a Sub, fold the result or return null. Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -64,8 +62,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// Given operands for an FAdd, see if we can fold the result. If not, this - /// returns null. + /// Given operands for an FAdd, fold the result or return null. Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -73,8 +70,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// Given operands for an FSub, see if we can fold the result. If not, this - /// returns null. + /// Given operands for an FSub, fold the result or return null. Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -82,8 +78,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// Given operands for an FMul, see if we can fold the result. If not, this - /// returns null. + /// Given operands for an FMul, fold the result or return null. Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -91,32 +86,28 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyMulInst - Given operands for a Mul, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a Mul, fold the result or return null. Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifySDivInst - Given operands for an SDiv, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an SDiv, fold the result or return null. Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyUDivInst - Given operands for a UDiv, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a UDiv, fold the result or return null. Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyFDivInst - Given operands for an FDiv, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an FDiv, fold the result or return null. Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -124,24 +115,21 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifySRemInst - Given operands for an SRem, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an SRem, fold the result or return null. Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyURemInst - Given operands for a URem, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a URem, fold the result or return null. Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyFRemInst - Given operands for an FRem, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an FRem, fold the result or return null. Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -149,8 +137,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyShlInst - Given operands for a Shl, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a Shl, fold the result or return null. Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -158,8 +145,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyLShrInst - Given operands for a LShr, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a LShr, fold the result or return null. Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -167,8 +153,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyAShrInst - Given operands for a AShr, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a AShr, fold the result or return nulll. Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -176,32 +161,28 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyAndInst - Given operands for an And, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an And, fold the result or return null. Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyOrInst - Given operands for an Or, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an Or, fold the result or return null. Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyXorInst - Given operands for a Xor, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an Xor, fold the result or return null. Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyICmpInst - Given operands for an ICmpInst, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an ICmpInst, fold the result or return null. Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -209,8 +190,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can - /// fold the result. If not, this returns null. + /// Given operands for an FCmpInst, fold the result or return null. Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, FastMathFlags FMF, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -218,8 +198,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifySelectInst - Given operands for a SelectInst, see if we can fold - /// the result. If not, this returns null. + /// Given operands for a SelectInst, fold the result or return null. Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -227,16 +206,15 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can - /// fold the result. If not, this returns null. - Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL, + /// Given operands for a GetElementPtrInst, fold the result or return null. + Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops, + const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we - /// can fold the result. If not, this returns null. + /// Given operands for an InsertValueInst, fold the result or return null. Value *SimplifyInsertValueInst(Value *Agg, Value *Val, ArrayRef<unsigned> Idxs, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -244,8 +222,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// \brief Given operands for an ExtractValueInst, see if we can fold the - /// result. If not, this returns null. + /// Given operands for an ExtractValueInst, fold the result or return null. Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -253,8 +230,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// \brief Given operands for an ExtractElementInst, see if we can fold the - /// result. If not, this returns null. + /// Given operands for an ExtractElementInst, fold the result or return null. Value *SimplifyExtractElementInst(Value *Vec, Value *Idx, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -262,8 +238,7 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold - /// the result. If not, this returns null. + /// Given operands for an TruncInst, fold the result or return null. Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, @@ -273,8 +248,7 @@ namespace llvm { //=== Helper functions for higher up the class hierarchy. - /// SimplifyCmpInst - Given operands for a CmpInst, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a CmpInst, fold the result or return null. Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -282,16 +256,15 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyBinOp - Given operands for a BinaryOperator, see if we can - /// fold the result. If not, this returns null. + /// Given operands for a BinaryOperator, fold the result or return null. Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can - /// fold the result. If not, this returns null. + + /// Given operands for an FP BinaryOperator, fold the result or return null. /// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the /// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp. Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS, @@ -301,10 +274,8 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// \brief Given a function and iterators over arguments, see if we can fold - /// the result. - /// - /// If this call could not be simplified returns null. + /// Given a function and iterators over arguments, fold the result or return + /// null. Value *SimplifyCall(Value *V, User::op_iterator ArgBegin, User::op_iterator ArgEnd, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, @@ -312,25 +283,21 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// \brief Given a function and set of arguments, see if we can fold the - /// result. - /// - /// If this call could not be simplified returns null. + /// Given a function and set of arguments, fold the result or return null. Value *SimplifyCall(Value *V, ArrayRef<Value *> Args, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); - /// SimplifyInstruction - See if we can compute a simplified version of this - /// instruction. If not, this returns null. + /// See if we can compute a simplified version of this instruction. If not, + /// return null. Value *SimplifyInstruction(Instruction *I, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr); - /// \brief Replace all uses of 'I' with 'SimpleV' and simplify the uses - /// recursively. + /// Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively. /// /// This first performs a normal RAUW of I with SimpleV. It then recursively /// attempts to simplify those users updated by the operation. The 'I' @@ -342,7 +309,7 @@ namespace llvm { const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr); - /// \brief Recursively attempt to simplify an instruction. + /// Recursively attempt to simplify an instruction. /// /// This routine uses SimplifyInstruction to simplify 'I', and if successful /// replaces uses of 'I' with the simplified value. It then recurses on each diff --git a/include/llvm/Analysis/Interval.h b/include/llvm/Analysis/Interval.h index 01eba3f16c01..a904753adaab 100644 --- a/include/llvm/Analysis/Interval.h +++ b/include/llvm/Analysis/Interval.h @@ -67,8 +67,9 @@ public: /// contains - Find out if a basic block is in this interval inline bool contains(BasicBlock *BB) const { - for (unsigned i = 0; i < Nodes.size(); ++i) - if (Nodes[i] == BB) return true; + for (BasicBlock *Node : Nodes) + if (Node == BB) + return true; return false; // I don't want the dependency on <algorithm> //return find(Nodes.begin(), Nodes.end(), BB) != Nodes.end(); @@ -76,8 +77,9 @@ public: /// isSuccessor - find out if a basic block is a successor of this Interval inline bool isSuccessor(BasicBlock *BB) const { - for (unsigned i = 0; i < Successors.size(); ++i) - if (Successors[i] == BB) return true; + for (BasicBlock *Successor : Successors) + if (Successor == BB) + return true; return false; // I don't want the dependency on <algorithm> //return find(Successors.begin(), Successors.end(), BB) != Successors.end(); diff --git a/include/llvm/Analysis/IteratedDominanceFrontier.h b/include/llvm/Analysis/IteratedDominanceFrontier.h index a1ded2554d44..37da5617b913 100644 --- a/include/llvm/Analysis/IteratedDominanceFrontier.h +++ b/include/llvm/Analysis/IteratedDominanceFrontier.h @@ -24,18 +24,14 @@ #ifndef LLVM_ANALYSIS_IDF_H #define LLVM_ANALYSIS_IDF_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" namespace llvm { -class BasicBlock; -template <class T> class DomTreeNodeBase; -typedef DomTreeNodeBase<BasicBlock> DomTreeNode; -template <class T> class DominatorTreeBase; - /// \brief Determine the iterated dominance frontier, given a set of defining /// blocks, and optionally, a set of live-in blocks. /// @@ -44,6 +40,9 @@ template <class T> class DominatorTreeBase; /// This algorithm is a linear time computation of Iterated Dominance Frontiers, /// pruned using the live-in set. /// By default, liveness is not used to prune the IDF computation. +/// The template parameters should be either BasicBlock* or Inverse<BasicBlock +/// *>, depending on if you want the forward or reverse IDF. +template <class NodeTy> class IDFCalculator { public: @@ -92,5 +91,7 @@ private: const SmallPtrSetImpl<BasicBlock *> *DefBlocks; SmallVector<BasicBlock *, 32> PHIBlocks; }; +typedef IDFCalculator<BasicBlock *> ForwardIDFCalculator; +typedef IDFCalculator<Inverse<BasicBlock *>> ReverseIDFCalculator; } #endif diff --git a/include/llvm/Analysis/LazyBlockFrequencyInfo.h b/include/llvm/Analysis/LazyBlockFrequencyInfo.h new file mode 100644 index 000000000000..a2d24bb9eb88 --- /dev/null +++ b/include/llvm/Analysis/LazyBlockFrequencyInfo.h @@ -0,0 +1,125 @@ +//===- LazyBlockFrequencyInfo.h - Lazy Block Frequency Analysis -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is an alternative analysis pass to BlockFrequencyInfoWrapperPass. The +// difference is that with this pass the block frequencies are not computed when +// the analysis pass is executed but rather when the BFI results is explicitly +// requested by the analysis client. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H +#define LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H + +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Pass.h" + +namespace llvm { +class AnalysisUsage; +class BranchProbabilityInfo; +class Function; +class LoopInfo; + +/// \brief This is an alternative analysis pass to +/// BlockFrequencyInfoWrapperPass. The difference is that with this pass the +/// block frequencies are not computed when the analysis pass is executed but +/// rather when the BFI results is explicitly requested by the analysis client. +/// +/// There are some additional requirements for any client pass that wants to use +/// the analysis: +/// +/// 1. The pass needs to initialize dependent passes with: +/// +/// INITIALIZE_PASS_DEPENDENCY(LazyBFIPass) +/// +/// 2. Similarly, getAnalysisUsage should call: +/// +/// LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU) +/// +/// 3. The computed BFI should be requested with +/// getAnalysis<LazyBlockFrequencyInfoPass>().getBFI() before either LoopInfo +/// or BPI could be invalidated for example by changing the CFG. +/// +/// Note that it is expected that we wouldn't need this functionality for the +/// new PM since with the new PM, analyses are executed on demand. +class LazyBlockFrequencyInfoPass : public FunctionPass { + + /// Wraps a BFI to allow lazy computation of the block frequencies. + /// + /// A pass that only conditionally uses BFI can uncondtionally require the + /// analysis without paying for the overhead if BFI doesn't end up being used. + class LazyBlockFrequencyInfo { + public: + LazyBlockFrequencyInfo() + : Calculated(false), F(nullptr), BPI(nullptr), LI(nullptr) {} + + /// Set up the per-function input. + void setAnalysis(const Function *F, const BranchProbabilityInfo *BPI, + const LoopInfo *LI) { + this->F = F; + this->BPI = BPI; + this->LI = LI; + } + + /// Retrieve the BFI with the block frequencies computed. + BlockFrequencyInfo &getCalculated() { + if (!Calculated) { + assert(F && BPI && LI && "call setAnalysis"); + BFI.calculate(*F, *BPI, *LI); + Calculated = true; + } + return BFI; + } + + const BlockFrequencyInfo &getCalculated() const { + return const_cast<LazyBlockFrequencyInfo *>(this)->getCalculated(); + } + + void releaseMemory() { + BFI.releaseMemory(); + Calculated = false; + setAnalysis(nullptr, nullptr, nullptr); + } + + private: + BlockFrequencyInfo BFI; + bool Calculated; + const Function *F; + const BranchProbabilityInfo *BPI; + const LoopInfo *LI; + }; + + LazyBlockFrequencyInfo LBFI; + +public: + static char ID; + + LazyBlockFrequencyInfoPass(); + + /// \brief Compute and return the block frequencies. + BlockFrequencyInfo &getBFI() { return LBFI.getCalculated(); } + + /// \brief Compute and return the block frequencies. + const BlockFrequencyInfo &getBFI() const { return LBFI.getCalculated(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Helper for client passes to set up the analysis usage on behalf of this + /// pass. + static void getLazyBFIAnalysisUsage(AnalysisUsage &AU); + + bool runOnFunction(Function &F) override; + void releaseMemory() override; + void print(raw_ostream &OS, const Module *M) const override; +}; + +/// \brief Helper for client passes to initialize dependent passes for LBFI. +void initializeLazyBFIPassPass(PassRegistry &Registry); +} +#endif diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index e02f3ab2de1f..9f62eaa2e9f8 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -48,7 +48,9 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" #include <iterator> +#include <utility> namespace llvm { class PreservedAnalyses; @@ -104,9 +106,85 @@ class LazyCallGraph { public: class Node; class SCC; - class iterator; - typedef SmallVector<PointerUnion<Function *, Node *>, 4> NodeVectorT; - typedef SmallVectorImpl<PointerUnion<Function *, Node *>> NodeVectorImplT; + class RefSCC; + class edge_iterator; + class call_edge_iterator; + + /// A class used to represent edges in the call graph. + /// + /// The lazy call graph models both *call* edges and *reference* edges. Call + /// edges are much what you would expect, and exist when there is a 'call' or + /// 'invoke' instruction of some function. Reference edges are also tracked + /// along side these, and exist whenever any instruction (transitively + /// through its operands) references a function. All call edges are + /// inherently reference edges, and so the reference graph forms a superset + /// of the formal call graph. + /// + /// Furthermore, edges also may point to raw \c Function objects when those + /// functions have not been scanned and incorporated into the graph (yet). + /// This is one of the primary ways in which the graph can be lazy. When + /// functions are scanned and fully incorporated into the graph, all of the + /// edges referencing them are updated to point to the graph \c Node objects + /// instead of to the raw \c Function objects. This class even provides + /// methods to trigger this scan on-demand by attempting to get the target + /// node of the graph and providing a reference back to the graph in order to + /// lazily build it if necessary. + /// + /// All of these forms of edges are fundamentally represented as outgoing + /// edges. The edges are stored in the source node and point at the target + /// node. This allows the edge structure itself to be a very compact data + /// structure: essentially a tagged pointer. + class Edge { + public: + /// The kind of edge in the graph. + enum Kind : bool { Ref = false, Call = true }; + + Edge(); + explicit Edge(Function &F, Kind K); + explicit Edge(Node &N, Kind K); + + /// Test whether the edge is null. + /// + /// This happens when an edge has been deleted. We leave the edge objects + /// around but clear them. + operator bool() const; + + /// Test whether the edge represents a direct call to a function. + /// + /// This requires that the edge is not null. + bool isCall() const; + + /// Get the function referenced by this edge. + /// + /// This requires that the edge is not null, but will succeed whether we + /// have built a graph node for the function yet or not. + Function &getFunction() const; + + /// Get the call graph node referenced by this edge if one exists. + /// + /// This requires that the edge is not null. If we have built a graph node + /// for the function this edge points to, this will return that node, + /// otherwise it will return null. + Node *getNode() const; + + /// Get the call graph node for this edge, building it if necessary. + /// + /// This requires that the edge is not null. If we have not yet built + /// a graph node for the function this edge points to, this will first ask + /// the graph to build that node, inserting it into all the relevant + /// structures. + Node &getNode(LazyCallGraph &G); + + private: + friend class LazyCallGraph::Node; + + PointerIntPair<PointerUnion<Function *, Node *>, 1, Kind> Value; + + void setKind(Kind K) { Value.setInt(K); } + }; + + typedef SmallVector<Edge, 4> EdgeVectorT; + typedef SmallVectorImpl<Edge> EdgeVectorImplT; /// A node in the call graph. /// @@ -121,35 +199,65 @@ public: Function &F; // We provide for the DFS numbering and Tarjan walk lowlink numbers to be - // stored directly within the node. + // stored directly within the node. These are both '-1' when nodes are part + // of an SCC (or RefSCC), or '0' when not yet reached in a DFS walk. int DFSNumber; int LowLink; - mutable NodeVectorT Callees; - DenseMap<Function *, size_t> CalleeIndexMap; + mutable EdgeVectorT Edges; + DenseMap<Function *, int> EdgeIndexMap; - /// Basic constructor implements the scanning of F into Callees and - /// CalleeIndexMap. + /// Basic constructor implements the scanning of F into Edges and + /// EdgeIndexMap. Node(LazyCallGraph &G, Function &F); - /// Internal helper to insert a callee. - void insertEdgeInternal(Function &Callee); + /// Internal helper to insert an edge to a function. + void insertEdgeInternal(Function &ChildF, Edge::Kind EK); - /// Internal helper to insert a callee. - void insertEdgeInternal(Node &CalleeN); + /// Internal helper to insert an edge to a node. + void insertEdgeInternal(Node &ChildN, Edge::Kind EK); - /// Internal helper to remove a callee from this node. - void removeEdgeInternal(Function &Callee); + /// Internal helper to change an edge kind. + void setEdgeKind(Function &ChildF, Edge::Kind EK); + + /// Internal helper to remove the edge to the given function. + void removeEdgeInternal(Function &ChildF); + + /// Print the name of this node's function. + friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) { + return OS << N.F.getName(); + } + + /// Dump the name of this node's function to stderr. + void dump() const; public: - typedef LazyCallGraph::iterator iterator; + LazyCallGraph &getGraph() const { return *G; } Function &getFunction() const { return F; } - iterator begin() const { - return iterator(*G, Callees.begin(), Callees.end()); + edge_iterator begin() const { + return edge_iterator(Edges.begin(), Edges.end()); + } + edge_iterator end() const { return edge_iterator(Edges.end(), Edges.end()); } + + const Edge &operator[](int i) const { return Edges[i]; } + const Edge &operator[](Function &F) const { + assert(EdgeIndexMap.find(&F) != EdgeIndexMap.end() && "No such edge!"); + return Edges[EdgeIndexMap.find(&F)->second]; + } + const Edge &operator[](Node &N) const { return (*this)[N.getFunction()]; } + + call_edge_iterator call_begin() const { + return call_edge_iterator(Edges.begin(), Edges.end()); + } + call_edge_iterator call_end() const { + return call_edge_iterator(Edges.end(), Edges.end()); + } + + iterator_range<call_edge_iterator> calls() const { + return make_range(call_begin(), call_end()); } - iterator end() const { return iterator(*G, Callees.end(), Callees.end()); } /// Equality is defined as address equality. bool operator==(const Node &N) const { return this == &N; } @@ -162,101 +270,279 @@ public: /// be scanned for "calls" or uses of functions and its child information /// will be constructed. All of these results are accumulated and cached in /// the graph. - class iterator - : public iterator_adaptor_base<iterator, NodeVectorImplT::iterator, - std::forward_iterator_tag, Node> { + class edge_iterator + : public iterator_adaptor_base<edge_iterator, EdgeVectorImplT::iterator, + std::forward_iterator_tag> { friend class LazyCallGraph; friend class LazyCallGraph::Node; - LazyCallGraph *G; - NodeVectorImplT::iterator E; + EdgeVectorImplT::iterator E; - // Build the iterator for a specific position in a node list. - iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI, - NodeVectorImplT::iterator E) - : iterator_adaptor_base(NI), G(&G), E(E) { - while (I != E && I->isNull()) + // Build the iterator for a specific position in the edge list. + edge_iterator(EdgeVectorImplT::iterator BaseI, + EdgeVectorImplT::iterator E) + : iterator_adaptor_base(BaseI), E(E) { + while (I != E && !*I) ++I; } public: - iterator() {} + edge_iterator() {} using iterator_adaptor_base::operator++; - iterator &operator++() { + edge_iterator &operator++() { do { ++I; - } while (I != E && I->isNull()); + } while (I != E && !*I); return *this; } + }; - reference operator*() const { - if (I->is<Node *>()) - return *I->get<Node *>(); + /// A lazy iterator over specifically call edges. + /// + /// This has the same iteration properties as the \c edge_iterator, but + /// restricts itself to edges which represent actual calls. + class call_edge_iterator + : public iterator_adaptor_base<call_edge_iterator, + EdgeVectorImplT::iterator, + std::forward_iterator_tag> { + friend class LazyCallGraph; + friend class LazyCallGraph::Node; + + EdgeVectorImplT::iterator E; + + /// Advance the iterator to the next valid, call edge. + void advanceToNextEdge() { + while (I != E && (!*I || !I->isCall())) + ++I; + } + + // Build the iterator for a specific position in the edge list. + call_edge_iterator(EdgeVectorImplT::iterator BaseI, + EdgeVectorImplT::iterator E) + : iterator_adaptor_base(BaseI), E(E) { + advanceToNextEdge(); + } + + public: + call_edge_iterator() {} - Function *F = I->get<Function *>(); - Node &ChildN = G->get(*F); - *I = &ChildN; - return ChildN; + using iterator_adaptor_base::operator++; + call_edge_iterator &operator++() { + ++I; + advanceToNextEdge(); + return *this; } }; /// An SCC of the call graph. /// - /// This represents a Strongly Connected Component of the call graph as + /// This represents a Strongly Connected Component of the direct call graph + /// -- ignoring indirect calls and function references. It stores this as /// a collection of call graph nodes. While the order of nodes in the SCC is /// stable, it is not any particular order. + /// + /// The SCCs are nested within a \c RefSCC, see below for details about that + /// outer structure. SCCs do not support mutation of the call graph, that + /// must be done through the containing \c RefSCC in order to fully reason + /// about the ordering and connections of the graph. class SCC { friend class LazyCallGraph; friend class LazyCallGraph::Node; - LazyCallGraph *G; - SmallPtrSet<SCC *, 1> ParentSCCs; + RefSCC *OuterRefSCC; SmallVector<Node *, 1> Nodes; - SCC(LazyCallGraph &G) : G(&G) {} + template <typename NodeRangeT> + SCC(RefSCC &OuterRefSCC, NodeRangeT &&Nodes) + : OuterRefSCC(&OuterRefSCC), Nodes(std::forward<NodeRangeT>(Nodes)) {} + + void clear() { + OuterRefSCC = nullptr; + Nodes.clear(); + } + + /// Print a short descrtiption useful for debugging or logging. + /// + /// We print the function names in the SCC wrapped in '()'s and skipping + /// the middle functions if there are a large number. + // + // Note: this is defined inline to dodge issues with GCC's interpretation + // of enclosing namespaces for friend function declarations. + friend raw_ostream &operator<<(raw_ostream &OS, const SCC &C) { + OS << '('; + int i = 0; + for (LazyCallGraph::Node &N : C) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 8) { + OS << "..., " << *C.Nodes.back(); + break; + } + OS << N; + ++i; + } + OS << ')'; + return OS; + } - void insert(Node &N); + /// Dump a short description of this SCC to stderr. + void dump() const; - void - internalDFS(SmallVectorImpl<std::pair<Node *, Node::iterator>> &DFSStack, - SmallVectorImpl<Node *> &PendingSCCStack, Node *N, - SmallVectorImpl<SCC *> &ResultSCCs); +#ifndef NDEBUG + /// Verify invariants about the SCC. + /// + /// This will attempt to validate all of the basic invariants within an + /// SCC, but not that it is a strongly connected componet per-se. Primarily + /// useful while building and updating the graph to check that basic + /// properties are in place rather than having inexplicable crashes later. + void verify(); +#endif public: - typedef SmallVectorImpl<Node *>::const_iterator iterator; - typedef pointee_iterator<SmallPtrSet<SCC *, 1>::const_iterator> - parent_iterator; + typedef pointee_iterator<SmallVectorImpl<Node *>::const_iterator> iterator; iterator begin() const { return Nodes.begin(); } iterator end() const { return Nodes.end(); } - parent_iterator parent_begin() const { return ParentSCCs.begin(); } - parent_iterator parent_end() const { return ParentSCCs.end(); } + int size() const { return Nodes.size(); } + + RefSCC &getOuterRefSCC() const { return *OuterRefSCC; } + + /// Provide a short name by printing this SCC to a std::string. + /// + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. + std::string getName() const { + std::string Name; + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); + return Name; + } + }; + + /// A RefSCC of the call graph. + /// + /// This models a Strongly Connected Component of function reference edges in + /// the call graph. As opposed to actual SCCs, these can be used to scope + /// subgraphs of the module which are independent from other subgraphs of the + /// module because they do not reference it in any way. This is also the unit + /// where we do mutation of the graph in order to restrict mutations to those + /// which don't violate this independence. + /// + /// A RefSCC contains a DAG of actual SCCs. All the nodes within the RefSCC + /// are necessarily within some actual SCC that nests within it. Since + /// a direct call *is* a reference, there will always be at least one RefSCC + /// around any SCC. + class RefSCC { + friend class LazyCallGraph; + friend class LazyCallGraph::Node; + + LazyCallGraph *G; + SmallPtrSet<RefSCC *, 1> Parents; + + /// A postorder list of the inner SCCs. + SmallVector<SCC *, 4> SCCs; + + /// A map from SCC to index in the postorder list. + SmallDenseMap<SCC *, int, 4> SCCIndices; + + /// Fast-path constructor. RefSCCs should instead be constructed by calling + /// formRefSCCFast on the graph itself. + RefSCC(LazyCallGraph &G); + + /// Print a short description useful for debugging or logging. + /// + /// We print the SCCs wrapped in '[]'s and skipping the middle SCCs if + /// there are a large number. + // + // Note: this is defined inline to dodge issues with GCC's interpretation + // of enclosing namespaces for friend function declarations. + friend raw_ostream &operator<<(raw_ostream &OS, const RefSCC &RC) { + OS << '['; + int i = 0; + for (LazyCallGraph::SCC &C : RC) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 4) { + OS << "..., " << *RC.SCCs.back(); + break; + } + OS << C; + ++i; + } + OS << ']'; + return OS; + } + + /// Dump a short description of this RefSCC to stderr. + void dump() const; + +#ifndef NDEBUG + /// Verify invariants about the RefSCC and all its SCCs. + /// + /// This will attempt to validate all of the invariants *within* the + /// RefSCC, but not that it is a strongly connected component of the larger + /// graph. This makes it useful even when partially through an update. + /// + /// Invariants checked: + /// - SCCs and their indices match. + /// - The SCCs list is in fact in post-order. + void verify(); +#endif + + public: + typedef pointee_iterator<SmallVectorImpl<SCC *>::const_iterator> iterator; + typedef iterator_range<iterator> range; + typedef pointee_iterator<SmallPtrSetImpl<RefSCC *>::const_iterator> + parent_iterator; + + iterator begin() const { return SCCs.begin(); } + iterator end() const { return SCCs.end(); } + + ssize_t size() const { return SCCs.size(); } + + SCC &operator[](int Idx) { return *SCCs[Idx]; } + + iterator find(SCC &C) const { + return SCCs.begin() + SCCIndices.find(&C)->second; + } + + parent_iterator parent_begin() const { return Parents.begin(); } + parent_iterator parent_end() const { return Parents.end(); } iterator_range<parent_iterator> parents() const { return make_range(parent_begin(), parent_end()); } /// Test if this SCC is a parent of \a C. - bool isParentOf(const SCC &C) const { return C.isChildOf(*this); } + bool isParentOf(const RefSCC &C) const { return C.isChildOf(*this); } - /// Test if this SCC is an ancestor of \a C. - bool isAncestorOf(const SCC &C) const { return C.isDescendantOf(*this); } + /// Test if this RefSCC is an ancestor of \a C. + bool isAncestorOf(const RefSCC &C) const { return C.isDescendantOf(*this); } - /// Test if this SCC is a child of \a C. - bool isChildOf(const SCC &C) const { - return ParentSCCs.count(const_cast<SCC *>(&C)); + /// Test if this RefSCC is a child of \a C. + bool isChildOf(const RefSCC &C) const { + return Parents.count(const_cast<RefSCC *>(&C)); } - /// Test if this SCC is a descendant of \a C. - bool isDescendantOf(const SCC &C) const; + /// Test if this RefSCC is a descendant of \a C. + bool isDescendantOf(const RefSCC &C) const; - /// Short name useful for debugging or logging. + /// Provide a short name by printing this SCC to a std::string. /// - /// We use the name of the first function in the SCC to name the SCC for - /// the purposes of debugging and logging. - StringRef getName() const { return (*begin())->getFunction().getName(); } + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. + std::string getName() const { + std::string Name; + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); + return Name; + } ///@{ /// \name Mutation API @@ -267,80 +553,151 @@ public: /// Note that these methods sometimes have complex runtimes, so be careful /// how you call them. - /// Insert an edge from one node in this SCC to another in this SCC. + /// Make an existing internal ref edge into a call edge. + /// + /// This may form a larger cycle and thus collapse SCCs into TargetN's SCC. + /// If that happens, the deleted SCC pointers are returned. These SCCs are + /// not in a valid state any longer but the pointers will remain valid + /// until destruction of the parent graph instance for the purpose of + /// clearing cached information. /// - /// By the definition of an SCC, this does not change the nature or make-up - /// of any SCCs. - void insertIntraSCCEdge(Node &CallerN, Node &CalleeN); + /// After this operation, both SourceN's SCC and TargetN's SCC may move + /// position within this RefSCC's postorder list. Any SCCs merged are + /// merged into the TargetN's SCC in order to preserve reachability analyses + /// which took place on that SCC. + SmallVector<SCC *, 1> switchInternalEdgeToCall(Node &SourceN, + Node &TargetN); + + /// Make an existing internal call edge into a ref edge. + /// + /// If SourceN and TargetN are part of a single SCC, it may be split up due + /// to breaking a cycle in the call edges that formed it. If that happens, + /// then this routine will insert new SCCs into the postorder list *before* + /// the SCC of TargetN (previously the SCC of both). This preserves + /// postorder as the TargetN can reach all of the other nodes by definition + /// of previously being in a single SCC formed by the cycle from SourceN to + /// TargetN. The newly added nodes are added *immediately* and contiguously + /// prior to the TargetN SCC and so they may be iterated starting from + /// there. + void switchInternalEdgeToRef(Node &SourceN, Node &TargetN); + + /// Make an existing outgoing ref edge into a call edge. + /// + /// Note that this is trivial as there are no cyclic impacts and there + /// remains a reference edge. + void switchOutgoingEdgeToCall(Node &SourceN, Node &TargetN); - /// Insert an edge whose tail is in this SCC and head is in some child SCC. + /// Make an existing outgoing call edge into a ref edge. /// - /// There must be an existing path from the caller to the callee. This - /// operation is inexpensive and does not change the set of SCCs in the - /// graph. - void insertOutgoingEdge(Node &CallerN, Node &CalleeN); + /// This is trivial as there are no cyclic impacts and there remains + /// a reference edge. + void switchOutgoingEdgeToRef(Node &SourceN, Node &TargetN); - /// Insert an edge whose tail is in a descendant SCC and head is in this - /// SCC. + /// Insert a ref edge from one node in this RefSCC to another in this + /// RefSCC. + /// + /// This is always a trivial operation as it doesn't change any part of the + /// graph structure besides connecting the two nodes. + /// + /// Note that we don't support directly inserting internal *call* edges + /// because that could change the graph structure and requires returning + /// information about what became invalid. As a consequence, the pattern + /// should be to first insert the necessary ref edge, and then to switch it + /// to a call edge if needed and handle any invalidation that results. See + /// the \c switchInternalEdgeToCall routine for details. + void insertInternalRefEdge(Node &SourceN, Node &TargetN); + + /// Insert an edge whose parent is in this RefSCC and child is in some + /// child RefSCC. + /// + /// There must be an existing path from the \p SourceN to the \p TargetN. + /// This operation is inexpensive and does not change the set of SCCs and + /// RefSCCs in the graph. + void insertOutgoingEdge(Node &SourceN, Node &TargetN, Edge::Kind EK); + + /// Insert an edge whose source is in a descendant RefSCC and target is in + /// this RefSCC. + /// + /// There must be an existing path from the target to the source in this + /// case. + /// + /// NB! This is has the potential to be a very expensive function. It + /// inherently forms a cycle in the prior RefSCC DAG and we have to merge + /// RefSCCs to resolve that cycle. But finding all of the RefSCCs which + /// participate in the cycle can in the worst case require traversing every + /// RefSCC in the graph. Every attempt is made to avoid that, but passes + /// must still exercise caution calling this routine repeatedly. + /// + /// Also note that this can only insert ref edges. In order to insert + /// a call edge, first insert a ref edge and then switch it to a call edge. + /// These are intentionally kept as separate interfaces because each step + /// of the operation invalidates a different set of data structures. /// - /// There must be an existing path from the callee to the caller in this - /// case. NB! This is has the potential to be a very expensive function. It - /// inherently forms a cycle in the prior SCC DAG and we have to merge SCCs - /// to resolve that cycle. But finding all of the SCCs which participate in - /// the cycle can in the worst case require traversing every SCC in the - /// graph. Every attempt is made to avoid that, but passes must still - /// exercise caution calling this routine repeatedly. + /// This returns all the RefSCCs which were merged into the this RefSCC + /// (the target's). This allows callers to invalidate any cached + /// information. /// /// FIXME: We could possibly optimize this quite a bit for cases where the /// caller and callee are very nearby in the graph. See comments in the /// implementation for details, but that use case might impact users. - SmallVector<SCC *, 1> insertIncomingEdge(Node &CallerN, Node &CalleeN); + SmallVector<RefSCC *, 1> insertIncomingRefEdge(Node &SourceN, + Node &TargetN); - /// Remove an edge whose source is in this SCC and target is *not*. + /// Remove an edge whose source is in this RefSCC and target is *not*. /// - /// This removes an inter-SCC edge. All inter-SCC edges originating from - /// this SCC have been fully explored by any in-flight DFS SCC formation, - /// so this is always safe to call once you have the source SCC. + /// This removes an inter-RefSCC edge. All inter-RefSCC edges originating + /// from this SCC have been fully explored by any in-flight DFS graph + /// formation, so this is always safe to call once you have the source + /// RefSCC. /// - /// This operation does not change the set of SCCs or the members of the - /// SCCs and so is very inexpensive. It may change the connectivity graph - /// of the SCCs though, so be careful calling this while iterating over - /// them. - void removeInterSCCEdge(Node &CallerN, Node &CalleeN); + /// This operation does not change the cyclic structure of the graph and so + /// is very inexpensive. It may change the connectivity graph of the SCCs + /// though, so be careful calling this while iterating over them. + void removeOutgoingEdge(Node &SourceN, Node &TargetN); - /// Remove an edge which is entirely within this SCC. + /// Remove a ref edge which is entirely within this RefSCC. /// - /// Both the \a Caller and the \a Callee must be within this SCC. Removing - /// such an edge make break cycles that form this SCC and thus this - /// operation may change the SCC graph significantly. In particular, this - /// operation will re-form new SCCs based on the remaining connectivity of - /// the graph. The following invariants are guaranteed to hold after - /// calling this method: + /// Both the \a SourceN and the \a TargetN must be within this RefSCC. + /// Removing such an edge may break cycles that form this RefSCC and thus + /// this operation may change the RefSCC graph significantly. In + /// particular, this operation will re-form new RefSCCs based on the + /// remaining connectivity of the graph. The following invariants are + /// guaranteed to hold after calling this method: /// - /// 1) This SCC is still an SCC in the graph. - /// 2) This SCC will be the parent of any new SCCs. Thus, this SCC is - /// preserved as the root of any new SCC directed graph formed. - /// 3) No SCC other than this SCC has its member set changed (this is + /// 1) This RefSCC is still a RefSCC in the graph. + /// 2) This RefSCC will be the parent of any new RefSCCs. Thus, this RefSCC + /// is preserved as the root of any new RefSCC DAG formed. + /// 3) No RefSCC other than this RefSCC has its member set changed (this is /// inherent in the definition of removing such an edge). - /// 4) All of the parent links of the SCC graph will be updated to reflect - /// the new SCC structure. - /// 5) All SCCs formed out of this SCC, excluding this SCC, will be - /// returned in a vector. - /// 6) The order of the SCCs in the vector will be a valid postorder - /// traversal of the new SCCs. + /// 4) All of the parent links of the RefSCC graph will be updated to + /// reflect the new RefSCC structure. + /// 5) All RefSCCs formed out of this RefSCC, excluding this RefSCC, will + /// be returned in post-order. + /// 6) The order of the RefSCCs in the vector will be a valid postorder + /// traversal of the new RefSCCs. /// /// These invariants are very important to ensure that we can build - /// optimization pipeliens on top of the CGSCC pass manager which - /// intelligently update the SCC graph without invalidating other parts of - /// the SCC graph. + /// optimization pipelines on top of the CGSCC pass manager which + /// intelligently update the RefSCC graph without invalidating other parts + /// of the RefSCC graph. + /// + /// Note that we provide no routine to remove a *call* edge. Instead, you + /// must first switch it to a ref edge using \c switchInternalEdgeToRef. + /// This split API is intentional as each of these two steps can invalidate + /// a different aspect of the graph structure and needs to have the + /// invalidation handled independently. /// /// The runtime complexity of this method is, in the worst case, O(V+E) - /// where V is the number of nodes in this SCC and E is the number of edges - /// leaving the nodes in this SCC. Note that E includes both edges within - /// this SCC and edges from this SCC to child SCCs. Some effort has been - /// made to minimize the overhead of common cases such as self-edges and - /// edge removals which result in a spanning tree with no more cycles. - SmallVector<SCC *, 1> removeIntraSCCEdge(Node &CallerN, Node &CalleeN); + /// where V is the number of nodes in this RefSCC and E is the number of + /// edges leaving the nodes in this RefSCC. Note that E includes both edges + /// within this RefSCC and edges from this RefSCC to child RefSCCs. Some + /// effort has been made to minimize the overhead of common cases such as + /// self-edges and edge removals which result in a spanning tree with no + /// more cycles. There are also detailed comments within the implementation + /// on techniques which could substantially improve this routine's + /// efficiency. + SmallVector<RefSCC *, 1> removeInternalRefEdge(Node &SourceN, + Node &TargetN); ///@} }; @@ -351,9 +708,9 @@ public: /// the call graph, walking it lazily in depth-first post-order. That is, it /// always visits SCCs for a callee prior to visiting the SCC for a caller /// (when they are in different SCCs). - class postorder_scc_iterator - : public iterator_facade_base<postorder_scc_iterator, - std::forward_iterator_tag, SCC> { + class postorder_ref_scc_iterator + : public iterator_facade_base<postorder_ref_scc_iterator, + std::forward_iterator_tag, RefSCC> { friend class LazyCallGraph; friend class LazyCallGraph::Node; @@ -361,27 +718,27 @@ public: struct IsAtEndT {}; LazyCallGraph *G; - SCC *C; + RefSCC *C; // Build the begin iterator for a node. - postorder_scc_iterator(LazyCallGraph &G) : G(&G) { - C = G.getNextSCCInPostOrder(); + postorder_ref_scc_iterator(LazyCallGraph &G) : G(&G) { + C = G.getNextRefSCCInPostOrder(); } // Build the end iterator for a node. This is selected purely by overload. - postorder_scc_iterator(LazyCallGraph &G, IsAtEndT /*Nonce*/) + postorder_ref_scc_iterator(LazyCallGraph &G, IsAtEndT /*Nonce*/) : G(&G), C(nullptr) {} public: - bool operator==(const postorder_scc_iterator &Arg) const { + bool operator==(const postorder_ref_scc_iterator &Arg) const { return G == Arg.G && C == Arg.C; } reference operator*() const { return *C; } using iterator_facade_base::operator++; - postorder_scc_iterator &operator++() { - C = G->getNextSCCInPostOrder(); + postorder_ref_scc_iterator &operator++() { + C = G->getNextRefSCCInPostOrder(); return *this; } }; @@ -396,20 +753,23 @@ public: LazyCallGraph(LazyCallGraph &&G); LazyCallGraph &operator=(LazyCallGraph &&RHS); - iterator begin() { - return iterator(*this, EntryNodes.begin(), EntryNodes.end()); + edge_iterator begin() { + return edge_iterator(EntryEdges.begin(), EntryEdges.end()); + } + edge_iterator end() { + return edge_iterator(EntryEdges.end(), EntryEdges.end()); } - iterator end() { return iterator(*this, EntryNodes.end(), EntryNodes.end()); } - postorder_scc_iterator postorder_scc_begin() { - return postorder_scc_iterator(*this); + postorder_ref_scc_iterator postorder_ref_scc_begin() { + return postorder_ref_scc_iterator(*this); } - postorder_scc_iterator postorder_scc_end() { - return postorder_scc_iterator(*this, postorder_scc_iterator::IsAtEndT()); + postorder_ref_scc_iterator postorder_ref_scc_end() { + return postorder_ref_scc_iterator(*this, + postorder_ref_scc_iterator::IsAtEndT()); } - iterator_range<postorder_scc_iterator> postorder_sccs() { - return make_range(postorder_scc_begin(), postorder_scc_end()); + iterator_range<postorder_ref_scc_iterator> postorder_ref_sccs() { + return make_range(postorder_ref_scc_begin(), postorder_ref_scc_end()); } /// Lookup a function in the graph which has already been scanned and added. @@ -421,6 +781,17 @@ public: /// iterator walk. SCC *lookupSCC(Node &N) const { return SCCMap.lookup(&N); } + /// Lookup a function's RefSCC in the graph. + /// + /// \returns null if the function hasn't been assigned a RefSCC via the + /// RefSCC iterator walk. + RefSCC *lookupRefSCC(Node &N) const { + if (SCC *C = lookupSCC(N)) + return &C->getOuterRefSCC(); + + return nullptr; + } + /// Get a graph node for a given function, scanning it to populate the graph /// data as necessary. Node &get(Function &F) { @@ -442,11 +813,11 @@ public: /// mutation of the graph via the SCC methods. /// Update the call graph after inserting a new edge. - void insertEdge(Node &Caller, Function &Callee); + void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK); /// Update the call graph after inserting a new edge. - void insertEdge(Function &Caller, Function &Callee) { - return insertEdge(get(Caller), Callee); + void insertEdge(Function &Caller, Function &Callee, Edge::Kind EK) { + return insertEdge(get(Caller), Callee, EK); } /// Update the call graph after deleting an edge. @@ -460,6 +831,9 @@ public: ///@} private: + typedef SmallVectorImpl<Node *>::reverse_iterator node_stack_iterator; + typedef iterator_range<node_stack_iterator> node_stack_range; + /// Allocator that holds all the call graph nodes. SpecificBumpPtrAllocator<Node> BPA; @@ -470,10 +844,10 @@ private: /// /// These nodes are reachable through "external" means. Put another way, they /// escape at the module scope. - NodeVectorT EntryNodes; + EdgeVectorT EntryEdges; - /// Map of the entry nodes in the graph to their indices in \c EntryNodes. - DenseMap<Function *, size_t> EntryIndexMap; + /// Map of the entry nodes in the graph to their indices in \c EntryEdges. + DenseMap<Function *, int> EntryIndexMap; /// Allocator that holds all the call graph SCCs. SpecificBumpPtrAllocator<SCC> SCCBPA; @@ -481,19 +855,22 @@ private: /// Maps Function -> SCC for fast lookup. DenseMap<Node *, SCC *> SCCMap; - /// The leaf SCCs of the graph. + /// Allocator that holds all the call graph RefSCCs. + SpecificBumpPtrAllocator<RefSCC> RefSCCBPA; + + /// The leaf RefSCCs of the graph. /// - /// These are all of the SCCs which have no children. - SmallVector<SCC *, 4> LeafSCCs; + /// These are all of the RefSCCs which have no children. + SmallVector<RefSCC *, 4> LeafRefSCCs; /// Stack of nodes in the DFS walk. - SmallVector<std::pair<Node *, iterator>, 4> DFSStack; + SmallVector<std::pair<Node *, edge_iterator>, 4> DFSStack; - /// Set of entry nodes not-yet-processed into SCCs. - SmallVector<Function *, 4> SCCEntryNodes; + /// Set of entry nodes not-yet-processed into RefSCCs. + SmallVector<Function *, 4> RefSCCEntryNodes; /// Stack of nodes the DFS has walked but not yet put into a SCC. - SmallVector<Node *, 4> PendingSCCStack; + SmallVector<Node *, 4> PendingRefSCCStack; /// Counter for the next DFS number to assign. int NextDFSNumber; @@ -505,18 +882,79 @@ private: /// Helper to update pointers back to the graph object during moves. void updateGraphPtrs(); - /// Helper to form a new SCC out of the top of a DFSStack-like - /// structure. - SCC *formSCC(Node *RootN, SmallVectorImpl<Node *> &NodeStack); + /// Allocates an SCC and constructs it using the graph allocator. + /// + /// The arguments are forwarded to the constructor. + template <typename... Ts> SCC *createSCC(Ts &&... Args) { + return new (SCCBPA.Allocate()) SCC(std::forward<Ts>(Args)...); + } + + /// Allocates a RefSCC and constructs it using the graph allocator. + /// + /// The arguments are forwarded to the constructor. + template <typename... Ts> RefSCC *createRefSCC(Ts &&... Args) { + return new (RefSCCBPA.Allocate()) RefSCC(std::forward<Ts>(Args)...); + } + + /// Build the SCCs for a RefSCC out of a list of nodes. + void buildSCCs(RefSCC &RC, node_stack_range Nodes); - /// Retrieve the next node in the post-order SCC walk of the call graph. - SCC *getNextSCCInPostOrder(); + /// Connect a RefSCC into the larger graph. + /// + /// This walks the edges to connect the RefSCC to its children's parent set, + /// and updates the root leaf list. + void connectRefSCC(RefSCC &RC); + + /// Retrieve the next node in the post-order RefSCC walk of the call graph. + RefSCC *getNextRefSCCInPostOrder(); }; +inline LazyCallGraph::Edge::Edge() : Value() {} +inline LazyCallGraph::Edge::Edge(Function &F, Kind K) : Value(&F, K) {} +inline LazyCallGraph::Edge::Edge(Node &N, Kind K) : Value(&N, K) {} + +inline LazyCallGraph::Edge::operator bool() const { + return !Value.getPointer().isNull(); +} + +inline bool LazyCallGraph::Edge::isCall() const { + assert(*this && "Queried a null edge!"); + return Value.getInt() == Call; +} + +inline Function &LazyCallGraph::Edge::getFunction() const { + assert(*this && "Queried a null edge!"); + auto P = Value.getPointer(); + if (auto *F = P.dyn_cast<Function *>()) + return *F; + + return P.get<Node *>()->getFunction(); +} + +inline LazyCallGraph::Node *LazyCallGraph::Edge::getNode() const { + assert(*this && "Queried a null edge!"); + auto P = Value.getPointer(); + if (auto *N = P.dyn_cast<Node *>()) + return N; + + return nullptr; +} + +inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode(LazyCallGraph &G) { + assert(*this && "Queried a null edge!"); + auto P = Value.getPointer(); + if (auto *N = P.dyn_cast<Node *>()) + return *N; + + Node &N = G.get(*P.get<Function *>()); + Value.setPointer(&N); + return N; +} + // Provide GraphTraits specializations for call graphs. template <> struct GraphTraits<LazyCallGraph::Node *> { typedef LazyCallGraph::Node NodeType; - typedef LazyCallGraph::iterator ChildIteratorType; + typedef LazyCallGraph::edge_iterator ChildIteratorType; static NodeType *getEntryNode(NodeType *N) { return N; } static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } @@ -524,7 +962,7 @@ template <> struct GraphTraits<LazyCallGraph::Node *> { }; template <> struct GraphTraits<LazyCallGraph *> { typedef LazyCallGraph::Node NodeType; - typedef LazyCallGraph::iterator ChildIteratorType; + typedef LazyCallGraph::edge_iterator ChildIteratorType; static NodeType *getEntryNode(NodeType *N) { return N; } static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } @@ -532,39 +970,48 @@ template <> struct GraphTraits<LazyCallGraph *> { }; /// An analysis pass which computes the call graph for a module. -class LazyCallGraphAnalysis { +class LazyCallGraphAnalysis : public AnalysisInfoMixin<LazyCallGraphAnalysis> { + friend AnalysisInfoMixin<LazyCallGraphAnalysis>; + static char PassID; + public: /// Inform generic clients of the result type. typedef LazyCallGraph Result; - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "Lazy CallGraph Analysis"; } - /// Compute the \c LazyCallGraph for the module \c M. /// /// This just builds the set of entry points to the call graph. The rest is /// built lazily as it is walked. - LazyCallGraph run(Module &M) { return LazyCallGraph(M); } - -private: - static char PassID; + LazyCallGraph run(Module &M, ModuleAnalysisManager &) { + return LazyCallGraph(M); + } }; /// A pass which prints the call graph to a \c raw_ostream. /// /// This is primarily useful for testing the analysis. -class LazyCallGraphPrinterPass { +class LazyCallGraphPrinterPass + : public PassInfoMixin<LazyCallGraphPrinterPass> { raw_ostream &OS; public: explicit LazyCallGraphPrinterPass(raw_ostream &OS); - PreservedAnalyses run(Module &M, ModuleAnalysisManager *AM); - - static StringRef name() { return "LazyCallGraphPrinterPass"; } + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// A pass which prints the call graph as a DOT file to a \c raw_ostream. +/// +/// This is primarily useful for visualization purposes. +class LazyCallGraphDOTPrinterPass + : public PassInfoMixin<LazyCallGraphDOTPrinterPass> { + raw_ostream &OS; + +public: + explicit LazyCallGraphDOTPrinterPass(raw_ostream &OS); + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; } #endif diff --git a/include/llvm/Analysis/LazyValueInfo.h b/include/llvm/Analysis/LazyValueInfo.h index 42002062dca2..c85cf2c5da56 100644 --- a/include/llvm/Analysis/LazyValueInfo.h +++ b/include/llvm/Analysis/LazyValueInfo.h @@ -15,11 +15,13 @@ #ifndef LLVM_ANALYSIS_LAZYVALUEINFO_H #define LLVM_ANALYSIS_LAZYVALUEINFO_H +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" namespace llvm { class AssumptionCache; class Constant; + class ConstantRange; class DataLayout; class DominatorTree; class Instruction; @@ -27,19 +29,33 @@ namespace llvm { class Value; /// This pass computes, caches, and vends lazy value constraint information. -class LazyValueInfo : public FunctionPass { - AssumptionCache *AC; - class TargetLibraryInfo *TLI; - DominatorTree *DT; - void *PImpl; +class LazyValueInfo { + friend class LazyValueInfoWrapperPass; + AssumptionCache *AC = nullptr; + class TargetLibraryInfo *TLI = nullptr; + DominatorTree *DT = nullptr; + void *PImpl = nullptr; LazyValueInfo(const LazyValueInfo&) = delete; void operator=(const LazyValueInfo&) = delete; public: - static char ID; - LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) { - initializeLazyValueInfoPass(*PassRegistry::getPassRegistry()); + ~LazyValueInfo(); + LazyValueInfo() {} + LazyValueInfo(AssumptionCache *AC_, TargetLibraryInfo *TLI_, + DominatorTree *DT_) + : AC(AC_), TLI(TLI_), DT(DT_) {} + LazyValueInfo(LazyValueInfo &&Arg) + : AC(Arg.AC), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) { + Arg.PImpl = nullptr; + } + LazyValueInfo &operator=(LazyValueInfo &&Arg) { + releaseMemory(); + AC = Arg.AC; + TLI = Arg.TLI; + DT = Arg.DT; + PImpl = Arg.PImpl; + Arg.PImpl = nullptr; + return *this; } - ~LazyValueInfo() override { assert(!PImpl && "releaseMemory not called"); } /// This is used to return true/false/dunno results. enum Tristate { @@ -65,6 +81,11 @@ public: /// constant at the end of the specified block. Return null if not. Constant *getConstant(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr); + /// Return the ConstantRange constraint that is known to hold for the + /// specified value at the end of the specified block. This may only be called + /// on integer-typed Values. + ConstantRange getConstantRange(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr); + /// Determine whether the specified value is known to be a /// constant on the specified edge. Return null if not. Constant *getConstantOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB, @@ -77,11 +98,41 @@ public: /// Inform the analysis cache that we have erased a block. void eraseBlock(BasicBlock *BB); - // Implementation boilerplate. + // For old PM pass. Delete once LazyValueInfoWrapperPass is gone. + void releaseMemory(); +}; + +/// \brief Analysis to compute lazy value information. +class LazyValueAnalysis : public AnalysisInfoMixin<LazyValueAnalysis> { +public: + typedef LazyValueInfo Result; + Result run(Function &F, FunctionAnalysisManager &FAM); + +private: + static char PassID; + friend struct AnalysisInfoMixin<LazyValueAnalysis>; +}; + +/// Wrapper around LazyValueInfo. +class LazyValueInfoWrapperPass : public FunctionPass { + LazyValueInfoWrapperPass(const LazyValueInfoWrapperPass&) = delete; + void operator=(const LazyValueInfoWrapperPass&) = delete; +public: + static char ID; + LazyValueInfoWrapperPass() : FunctionPass(ID) { + initializeLazyValueInfoWrapperPassPass(*PassRegistry::getPassRegistry()); + } + ~LazyValueInfoWrapperPass() override { + assert(!Info.PImpl && "releaseMemory not called"); + } + + LazyValueInfo &getLVI(); void getAnalysisUsage(AnalysisUsage &AU) const override; void releaseMemory() override; bool runOnFunction(Function &F) override; +private: + LazyValueInfo Info; }; } // end namespace llvm diff --git a/include/llvm/Analysis/Loads.h b/include/llvm/Analysis/Loads.h index 939663b0def1..39f80f489e12 100644 --- a/include/llvm/Analysis/Loads.h +++ b/include/llvm/Analysis/Loads.h @@ -23,39 +23,74 @@ namespace llvm { class DataLayout; class MDNode; +/// isDereferenceablePointer - Return true if this is always a dereferenceable +/// pointer. If the context instruction is specified perform context-sensitive +/// analysis and return true if the pointer is dereferenceable at the +/// specified instruction. +bool isDereferenceablePointer(const Value *V, const DataLayout &DL, + const Instruction *CtxI = nullptr, + const DominatorTree *DT = nullptr); + +/// Returns true if V is always a dereferenceable pointer with alignment +/// greater or equal than requested. If the context instruction is specified +/// performs context-sensitive analysis and returns true if the pointer is +/// dereferenceable at the specified instruction. +bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, + const DataLayout &DL, + const Instruction *CtxI = nullptr, + const DominatorTree *DT = nullptr); + /// isSafeToLoadUnconditionally - Return true if we know that executing a load -/// from this value cannot trap. If it is not obviously safe to load from the -/// specified pointer, we do a quick local scan of the basic block containing -/// ScanFrom, to determine if the address is already accessed. -bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom, - unsigned Align); +/// from this value cannot trap. +/// +/// If DT and ScanFrom are specified this method performs context-sensitive +/// analysis and returns true if it is safe to load immediately before ScanFrom. +/// +/// If it is not obviously safe to load from the specified pointer, we do a +/// quick local scan of the basic block containing ScanFrom, to determine if +/// the address is already accessed. +bool isSafeToLoadUnconditionally(Value *V, unsigned Align, + const DataLayout &DL, + Instruction *ScanFrom = nullptr, + const DominatorTree *DT = nullptr); /// DefMaxInstsToScan - the default number of maximum instructions /// to scan in the block, used by FindAvailableLoadedValue(). extern cl::opt<unsigned> DefMaxInstsToScan; -/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at -/// the instruction before ScanFrom) checking to see if we have the value at -/// the memory address *Ptr locally available within a small number of -/// instructions. If the value is available, return it. +/// \brief Scan backwards to see if we have the value of the given load +/// available locally within a small number of instructions. +/// +/// You can use this function to scan across multiple blocks: after you call +/// this function, if ScanFrom points at the beginning of the block, it's safe +/// to continue scanning the predecessors. /// -/// If not, return the iterator for the last validated instruction that the -/// value would be live through. If we scanned the entire block and didn't -/// find something that invalidates *Ptr or provides it, ScanFrom would be -/// left at begin() and this returns null. ScanFrom could also be left +/// Note that performing load CSE requires special care to make sure the +/// metadata is set appropriately. In particular, aliasing metadata needs +/// to be merged. (This doesn't matter for store-to-load forwarding because +/// the only relevant load gets deleted.) /// -/// MaxInstsToScan specifies the maximum instructions to scan in the block. -/// If it is set to 0, it will scan the whole block. You can also optionally -/// specify an alias analysis implementation, which makes this more precise. +/// \param Load The load we want to replace. +/// \param ScanBB The basic block to scan. FIXME: This is redundant. +/// \param [in,out] ScanFrom The location to start scanning from. When this +/// function returns, it points at the last instruction scanned. +/// \param MaxInstsToScan The maximum number of instructions to scan. If this +/// is zero, the whole block will be scanned. +/// \param AA Optional pointer to alias analysis, to make the scan more +/// precise. +/// \param [out] AATags The aliasing metadata for the operation which produced +/// the value. FIXME: This is basically useless. +/// \param [out] IsLoadCSE Whether the returned value is a load from the same +/// location in memory, as opposed to the value operand of a store. /// -/// If AATags is non-null and a load or store is found, the AA tags from the -/// load or store are recorded there. If there are no AA tags or if no access -/// is found, it is left unmodified. -Value *FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB, +/// \returns The found value, or nullptr if no value is found. +Value *FindAvailableLoadedValue(LoadInst *Load, + BasicBlock *ScanBB, BasicBlock::iterator &ScanFrom, unsigned MaxInstsToScan = DefMaxInstsToScan, AliasAnalysis *AA = nullptr, - AAMDNodes *AATags = nullptr); + AAMDNodes *AATags = nullptr, + bool *IsLoadCSE = nullptr); } diff --git a/include/llvm/Analysis/LoopAccessAnalysis.h b/include/llvm/Analysis/LoopAccessAnalysis.h index 871d35e99b74..ceee1be5e1e7 100644 --- a/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/include/llvm/Analysis/LoopAccessAnalysis.h @@ -228,7 +228,7 @@ public: /// \brief The maximum number of bytes of a vector register we can vectorize /// the accesses safely with. - unsigned getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; } + uint64_t getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; } /// \brief In same cases when the dependency check fails we can still /// vectorize the loop with a dynamic array access check. @@ -284,7 +284,7 @@ private: unsigned AccessIdx; // We can access this many bytes in parallel safely. - unsigned MaxSafeDepDistBytes; + uint64_t MaxSafeDepDistBytes; /// \brief If we see a non-constant dependence distance we can still try to /// vectorize this loop with runtime checks. @@ -321,7 +321,10 @@ private: /// \brief Check whether the data dependence could prevent store-load /// forwarding. - bool couldPreventStoreLoadForward(unsigned Distance, unsigned TypeByteSize); + /// + /// \return false if we shouldn't vectorize at all or avoid larger + /// vectorization factors by limiting MaxSafeDepDistBytes. + bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize); }; /// \brief Holds information about the memory runtime legality checks to verify @@ -363,10 +366,10 @@ public: } /// Insert a pointer and calculate the start and end SCEVs. - /// \p We need Preds in order to compute the SCEV expression of the pointer + /// We need \p PSE in order to compute the SCEV expression of the pointer /// according to the assumptions that we've made during the analysis. /// The method might also version the pointer stride according to \p Strides, - /// and change \p Preds. + /// and add new predicates to \p PSE. void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId, unsigned ASId, const ValueToValueMap &Strides, PredicatedScalarEvolution &PSE); @@ -508,23 +511,53 @@ private: /// PSE must be emitted in order for the results of this analysis to be valid. class LoopAccessInfo { public: - LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL, - const TargetLibraryInfo *TLI, AliasAnalysis *AA, - DominatorTree *DT, LoopInfo *LI, - const ValueToValueMap &Strides); + LoopAccessInfo(Loop *L, ScalarEvolution *SE, const TargetLibraryInfo *TLI, + AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI); + + // FIXME: + // Hack for MSVC 2013 which sems like it can't synthesize this even + // with default keyword: + // LoopAccessInfo(LoopAccessInfo &&LAI) = default; + LoopAccessInfo(LoopAccessInfo &&LAI) + : PSE(std::move(LAI.PSE)), PtrRtChecking(std::move(LAI.PtrRtChecking)), + DepChecker(std::move(LAI.DepChecker)), TheLoop(LAI.TheLoop), + NumLoads(LAI.NumLoads), NumStores(LAI.NumStores), + MaxSafeDepDistBytes(LAI.MaxSafeDepDistBytes), CanVecMem(LAI.CanVecMem), + StoreToLoopInvariantAddress(LAI.StoreToLoopInvariantAddress), + Report(std::move(LAI.Report)), + SymbolicStrides(std::move(LAI.SymbolicStrides)), + StrideSet(std::move(LAI.StrideSet)) {} + // LoopAccessInfo &operator=(LoopAccessInfo &&LAI) = default; + LoopAccessInfo &operator=(LoopAccessInfo &&LAI) { + assert(this != &LAI); + + PSE = std::move(LAI.PSE); + PtrRtChecking = std::move(LAI.PtrRtChecking); + DepChecker = std::move(LAI.DepChecker); + TheLoop = LAI.TheLoop; + NumLoads = LAI.NumLoads; + NumStores = LAI.NumStores; + MaxSafeDepDistBytes = LAI.MaxSafeDepDistBytes; + CanVecMem = LAI.CanVecMem; + StoreToLoopInvariantAddress = LAI.StoreToLoopInvariantAddress; + Report = std::move(LAI.Report); + SymbolicStrides = std::move(LAI.SymbolicStrides); + StrideSet = std::move(LAI.StrideSet); + return *this; + } /// Return true we can analyze the memory accesses in the loop and there are /// no memory dependence cycles. bool canVectorizeMemory() const { return CanVecMem; } const RuntimePointerChecking *getRuntimePointerChecking() const { - return &PtrRtChecking; + return PtrRtChecking.get(); } /// \brief Number of memchecks required to prove independence of otherwise /// may-alias pointers. unsigned getNumRuntimePointerChecks() const { - return PtrRtChecking.getNumberOfChecks(); + return PtrRtChecking->getNumberOfChecks(); } /// Return true if the block BB needs to be predicated in order for the loop @@ -535,7 +568,7 @@ public: /// Returns true if the value V is uniform within the loop. bool isUniform(Value *V) const; - unsigned getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; } + uint64_t getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; } unsigned getNumStores() const { return NumStores; } unsigned getNumLoads() const { return NumLoads;} @@ -563,23 +596,25 @@ public: /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. - const MemoryDepChecker &getDepChecker() const { return DepChecker; } + const MemoryDepChecker &getDepChecker() const { return *DepChecker; } /// \brief Return the list of instructions that use \p Ptr to read or write /// memory. SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr, bool isWrite) const { - return DepChecker.getInstructionsForAccess(Ptr, isWrite); + return DepChecker->getInstructionsForAccess(Ptr, isWrite); } + /// \brief If an access has a symbolic strides, this maps the pointer value to + /// the stride symbol. + const ValueToValueMap &getSymbolicStrides() const { return SymbolicStrides; } + + /// \brief Pointer has a symbolic stride. + bool hasStride(Value *V) const { return StrideSet.count(V); } + /// \brief Print the information about the memory accesses in the loop. void print(raw_ostream &OS, unsigned Depth = 0) const; - /// \brief Used to ensure that if the analysis was run with speculating the - /// value of symbolic strides, the client queries it with the same assumption. - /// Only used in DEBUG build but we don't want NDEBUG-dependent ABI. - unsigned NumSymbolicStrides; - /// \brief Checks existence of store to invariant address inside loop. /// If the loop has any store to invariant address, then it returns true, /// else returns false. @@ -592,11 +627,12 @@ public: /// should be re-written (and therefore simplified) according to PSE. /// A user of LoopAccessAnalysis will need to emit the runtime checks /// associated with this predicate. - PredicatedScalarEvolution PSE; + const PredicatedScalarEvolution &getPSE() const { return *PSE; } private: - /// \brief Analyze the loop. Substitute symbolic strides using Strides. - void analyzeLoop(const ValueToValueMap &Strides); + /// \brief Analyze the loop. + void analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, + const TargetLibraryInfo *TLI, DominatorTree *DT); /// \brief Check if the structure of the loop allows it to be analyzed by this /// pass. @@ -604,25 +640,28 @@ private: void emitAnalysis(LoopAccessReport &Message); + /// \brief Collect memory access with loop invariant strides. + /// + /// Looks for accesses like "a[i * StrideA]" where "StrideA" is loop + /// invariant. + void collectStridedAccess(Value *LoadOrStoreInst); + + std::unique_ptr<PredicatedScalarEvolution> PSE; + /// We need to check that all of the pointers in this list are disjoint - /// at runtime. - RuntimePointerChecking PtrRtChecking; + /// at runtime. Using std::unique_ptr to make using move ctor simpler. + std::unique_ptr<RuntimePointerChecking> PtrRtChecking; /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. - MemoryDepChecker DepChecker; + std::unique_ptr<MemoryDepChecker> DepChecker; Loop *TheLoop; - const DataLayout &DL; - const TargetLibraryInfo *TLI; - AliasAnalysis *AA; - DominatorTree *DT; - LoopInfo *LI; unsigned NumLoads; unsigned NumStores; - unsigned MaxSafeDepDistBytes; + uint64_t MaxSafeDepDistBytes; /// \brief Cache the result of analyzeLoop. bool CanVecMem; @@ -634,15 +673,23 @@ private: /// \brief The diagnostics report generated for the analysis. E.g. why we /// couldn't analyze the loop. Optional<LoopAccessReport> Report; + + /// \brief If an access has a symbolic strides, this maps the pointer value to + /// the stride symbol. + ValueToValueMap SymbolicStrides; + + /// \brief Set of symbolic strides values. + SmallPtrSet<Value *, 8> StrideSet; }; Value *stripIntegerCast(Value *V); -///\brief Return the SCEV corresponding to a pointer with the symbolic stride -/// replaced with constant one, assuming \p Preds is true. +/// \brief Return the SCEV corresponding to a pointer with the symbolic stride +/// replaced with constant one, assuming the SCEV predicate associated with +/// \p PSE is true. /// /// If necessary this method will version the stride of the pointer according -/// to \p PtrToStride and therefore add a new predicate to \p Preds. +/// to \p PtrToStride and therefore add further predicates to \p PSE. /// /// If \p OrigPtr is not null, use it to look up the stride value instead of \p /// Ptr. \p PtrToStride provides the mapping between the pointer value and its @@ -651,13 +698,24 @@ const SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE, const ValueToValueMap &PtrToStride, Value *Ptr, Value *OrigPtr = nullptr); -/// \brief Check the stride of the pointer and ensure that it does not wrap in -/// the address space, assuming \p Preds is true. +/// \brief If the pointer has a constant stride return it in units of its +/// element size. Otherwise return zero. +/// +/// Ensure that it does not wrap in the address space, assuming the predicate +/// associated with \p PSE is true. /// /// If necessary this method will version the stride of the pointer according -/// to \p PtrToStride and therefore add a new predicate to \p Preds. -int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, - const ValueToValueMap &StridesMap); +/// to \p PtrToStride and therefore add further predicates to \p PSE. +/// The \p Assume parameter indicates if we are allowed to make additional +/// run-time assumptions. +int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, + const ValueToValueMap &StridesMap = ValueToValueMap(), + bool Assume = false); + +/// \brief Returns true if the memory operations \p A and \p B are consecutive. +/// This is a simple API that does not depend on the analysis pass. +bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL, + ScalarEvolution &SE, bool CheckType = true); /// \brief This analysis provides dependence information for the memory accesses /// of a loop. @@ -666,12 +724,12 @@ int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, /// querying the loop access info via LAA::getInfo. getInfo return a /// LoopAccessInfo object. See this class for the specifics of what information /// is provided. -class LoopAccessAnalysis : public FunctionPass { +class LoopAccessLegacyAnalysis : public FunctionPass { public: static char ID; - LoopAccessAnalysis() : FunctionPass(ID) { - initializeLoopAccessAnalysisPass(*PassRegistry::getPassRegistry()); + LoopAccessLegacyAnalysis() : FunctionPass(ID) { + initializeLoopAccessLegacyAnalysisPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; @@ -680,11 +738,8 @@ public: /// \brief Query the result of the loop access information for the loop \p L. /// - /// If the client speculates (and then issues run-time checks) for the values - /// of symbolic strides, \p Strides provides the mapping (see - /// replaceSymbolicStrideSCEV). If there is no cached result available run - /// the analysis. - const LoopAccessInfo &getInfo(Loop *L, const ValueToValueMap &Strides); + /// If there is no cached result available run the analysis. + const LoopAccessInfo &getInfo(Loop *L); void releaseMemory() override { // Invalidate the cache when the pass is freed. @@ -706,6 +761,34 @@ private: LoopInfo *LI; }; +/// \brief This analysis provides dependence information for the memory +/// accesses of a loop. +/// +/// It runs the analysis for a loop on demand. This can be initiated by +/// querying the loop access info via AM.getResult<LoopAccessAnalysis>. +/// getResult return a LoopAccessInfo object. See this class for the +/// specifics of what information is provided. +class LoopAccessAnalysis + : public AnalysisInfoMixin<LoopAccessAnalysis> { + friend AnalysisInfoMixin<LoopAccessAnalysis>; + static char PassID; + +public: + typedef LoopAccessInfo Result; + Result run(Loop &, AnalysisManager<Loop> &); + static StringRef name() { return "LoopAccessAnalysis"; } +}; + +/// \brief Printer pass for the \c LoopAccessInfo results. +class LoopAccessInfoPrinterPass + : public PassInfoMixin<LoopAccessInfoPrinterPass> { + raw_ostream &OS; + +public: + explicit LoopAccessInfoPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; + inline Instruction *MemoryDepChecker::Dependence::getSource( const LoopAccessInfo &LAI) const { return LAI.getDepChecker().getMemoryInstructions()[Source]; diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index 70e636ce1f3d..35dc6bcb6864 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -25,6 +25,12 @@ // * the loop depth // * etc... // +// Note that this analysis specifically identifies *Loops* not cycles or SCCs +// in the CFG. There can be strongly connected compontents in the CFG which +// this analysis will not recognize and that will not be represented by a Loop +// instance. In particular, a Loop might be inside such a non-loop SCC, or a +// non-loop SCC might contain a sub-SCC which is a Loop. +// //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_LOOPINFO_H @@ -38,16 +44,12 @@ #include "llvm/IR/CFG.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include <algorithm> namespace llvm { -// FIXME: Replace this brittle forward declaration with the include of the new -// PassManager.h when doing so doesn't break the PassManagerBuilder. -template <typename IRUnitT> class AnalysisManager; -class PreservedAnalyses; - class DominatorTree; class LoopInfo; class Loop; @@ -346,6 +348,9 @@ raw_ostream& operator<<(raw_ostream &OS, const LoopBase<BlockT, LoopT> &Loop) { // Implementation in LoopInfoImpl.h extern template class LoopBase<BasicBlock, Loop>; + +/// Represents a single loop in the control flow graph. Note that not all SCCs +/// in the CFG are neccessarily loops. class Loop : public LoopBase<BasicBlock, Loop> { public: Loop() {} @@ -452,21 +457,13 @@ public: /// location by looking at the preheader and header blocks. If it /// cannot find a terminating instruction with location information, /// it returns an unknown location. - DebugLoc getStartLoc() const { - BasicBlock *HeadBB; - - // Try the pre-header first. - if ((HeadBB = getLoopPreheader()) != nullptr) - if (DebugLoc DL = HeadBB->getTerminator()->getDebugLoc()) - return DL; + DebugLoc getStartLoc() const; - // If we have no pre-header or there are no instructions with debug - // info in it, try the header. - HeadBB = getHeader(); - if (HeadBB) - return HeadBB->getTerminator()->getDebugLoc(); - - return DebugLoc(); + StringRef getName() const { + if (BasicBlock *Header = getHeader()) + if (Header->hasName()) + return Header->getName(); + return "<unnamed loop>"; } private: @@ -775,30 +772,23 @@ template <> struct GraphTraits<Loop*> { }; /// \brief Analysis pass that exposes the \c LoopInfo for a function. -class LoopAnalysis { +class LoopAnalysis : public AnalysisInfoMixin<LoopAnalysis> { + friend AnalysisInfoMixin<LoopAnalysis>; static char PassID; public: typedef LoopInfo Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - /// \brief Provide a name for the analysis for debugging and logging. - static StringRef name() { return "LoopAnalysis"; } - - LoopInfo run(Function &F, AnalysisManager<Function> *AM); + LoopInfo run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Printer pass for the \c LoopAnalysis results. -class LoopPrinterPass { +class LoopPrinterPass : public PassInfoMixin<LoopPrinterPass> { raw_ostream &OS; public: explicit LoopPrinterPass(raw_ostream &OS) : OS(OS) {} - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); - - static StringRef name() { return "LoopPrinterPass"; } + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief The legacy pass manager's analysis pass to compute loop information. @@ -828,7 +818,7 @@ public: }; /// \brief Pass for printing a loop's contents as LLVM's text IR assembly. -class PrintLoopPass { +class PrintLoopPass : public PassInfoMixin<PrintLoopPass> { raw_ostream &OS; std::string Banner; @@ -836,8 +826,7 @@ public: PrintLoopPass(); PrintLoopPass(raw_ostream &OS, const std::string &Banner = ""); - PreservedAnalyses run(Loop &L); - static StringRef name() { return "PrintLoopPass"; } + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &); }; } // End llvm namespace diff --git a/include/llvm/Analysis/LoopInfoImpl.h b/include/llvm/Analysis/LoopInfoImpl.h index 824fc7e8f155..816a15452dae 100644 --- a/include/llvm/Analysis/LoopInfoImpl.h +++ b/include/llvm/Analysis/LoopInfoImpl.h @@ -277,7 +277,7 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const { } assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!"); assert(HasInsideLoopSuccs && "Loop block has no in-loop successors!"); - assert(BB != getHeader()->getParent()->begin() && + assert(BB != &getHeader()->getParent()->front() && "Loop contains function entry block!"); NumVisited++; diff --git a/include/llvm/Analysis/LoopPass.h b/include/llvm/Analysis/LoopPass.h index 2cf734e53bb4..89debec04e94 100644 --- a/include/llvm/Analysis/LoopPass.h +++ b/include/llvm/Analysis/LoopPass.h @@ -88,9 +88,10 @@ public: virtual void deleteAnalysisLoop(Loop *L) {} protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Loop *L) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipLoop(const Loop *L) const; }; class LPPassManager : public FunctionPass, public PMDataManager { diff --git a/include/llvm/Analysis/LoopPassManager.h b/include/llvm/Analysis/LoopPassManager.h new file mode 100644 index 000000000000..a89551851259 --- /dev/null +++ b/include/llvm/Analysis/LoopPassManager.h @@ -0,0 +1,142 @@ +//===- LoopPassManager.h - Loop pass management -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This header provides classes for managing passes over loops in LLVM IR. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LOOPPASSMANAGER_H +#define LLVM_ANALYSIS_LOOPPASSMANAGER_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +extern template class PassManager<Loop>; +/// \brief The loop pass manager. +/// +/// See the documentation for the PassManager template for details. It runs a +/// sequency of loop passes over each loop that the manager is run over. This +/// typedef serves as a convenient way to refer to this construct. +typedef PassManager<Loop> LoopPassManager; + +extern template class AnalysisManager<Loop>; +/// \brief The loop analysis manager. +/// +/// See the documentation for the AnalysisManager template for detail +/// documentation. This typedef serves as a convenient way to refer to this +/// construct in the adaptors and proxies used to integrate this into the larger +/// pass manager infrastructure. +typedef AnalysisManager<Loop> LoopAnalysisManager; + +extern template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>; +/// A proxy from a \c LoopAnalysisManager to a \c Function. +typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function> + LoopAnalysisManagerFunctionProxy; + +extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>; +/// A proxy from a \c FunctionAnalysisManager to a \c Loop. +typedef OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop> + FunctionAnalysisManagerLoopProxy; + +/// Returns the minimum set of Analyses that all loop passes must preserve. +PreservedAnalyses getLoopPassPreservedAnalyses(); + +/// \brief Adaptor that maps from a function to its loops. +/// +/// Designed to allow composition of a LoopPass(Manager) and a +/// FunctionPassManager. Note that if this pass is constructed with a \c +/// FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy +/// analysis prior to running the loop passes over the function to enable a \c +/// LoopAnalysisManager to be used within this run safely. +template <typename LoopPassT> +class FunctionToLoopPassAdaptor + : public PassInfoMixin<FunctionToLoopPassAdaptor<LoopPassT>> { +public: + explicit FunctionToLoopPassAdaptor(LoopPassT Pass) + : Pass(std::move(Pass)) {} + // We have to explicitly define all the special member functions because MSVC + // refuses to generate them. + FunctionToLoopPassAdaptor(const FunctionToLoopPassAdaptor &Arg) + : Pass(Arg.Pass) {} + FunctionToLoopPassAdaptor(FunctionToLoopPassAdaptor &&Arg) + : Pass(std::move(Arg.Pass)) {} + friend void swap(FunctionToLoopPassAdaptor &LHS, + FunctionToLoopPassAdaptor &RHS) { + using std::swap; + swap(LHS.Pass, RHS.Pass); + } + FunctionToLoopPassAdaptor &operator=(FunctionToLoopPassAdaptor RHS) { + swap(*this, RHS); + return *this; + } + + /// \brief Runs the loop passes across every loop in the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { + // Setup the loop analysis manager from its proxy. + LoopAnalysisManager &LAM = + AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager(); + // Get the loop structure for this function + LoopInfo &LI = AM.getResult<LoopAnalysis>(F); + + PreservedAnalyses PA = PreservedAnalyses::all(); + + // We want to visit the loops in reverse post-order. We'll build the stack + // of loops to visit in Loops by first walking the loops in pre-order. + SmallVector<Loop *, 2> Loops; + SmallVector<Loop *, 2> WorkList(LI.begin(), LI.end()); + while (!WorkList.empty()) { + Loop *L = WorkList.pop_back_val(); + WorkList.insert(WorkList.end(), L->begin(), L->end()); + Loops.push_back(L); + } + + // Now pop each element off of the stack to visit the loops in reverse + // post-order. + for (auto *L : reverse(Loops)) { + PreservedAnalyses PassPA = Pass.run(*L, LAM); + assert(PassPA.preserved(getLoopPassPreservedAnalyses()) && + "Loop passes must preserve all relevant analyses"); + + // We know that the loop pass couldn't have invalidated any other loop's + // analyses (that's the contract of a loop pass), so directly handle the + // loop analysis manager's invalidation here. Also, update the + // preserved analyses to reflect that once invalidated these can again + // be preserved. + PassPA = LAM.invalidate(*L, std::move(PassPA)); + + // Then intersect the preserved set so that invalidation of module + // analyses will eventually occur when the module pass completes. + PA.intersect(std::move(PassPA)); + } + + // By definition we preserve the proxy. This precludes *any* invalidation of + // loop analyses by the proxy, but that's OK because we've taken care to + // invalidate analyses in the loop analysis manager incrementally above. + PA.preserve<LoopAnalysisManagerFunctionProxy>(); + return PA; + } + +private: + LoopPassT Pass; +}; + +/// \brief A function to deduce a loop pass type and wrap it in the templated +/// adaptor. +template <typename LoopPassT> +FunctionToLoopPassAdaptor<LoopPassT> +createFunctionToLoopPassAdaptor(LoopPassT Pass) { + return FunctionToLoopPassAdaptor<LoopPassT>(std::move(Pass)); +} +} + +#endif // LLVM_ANALYSIS_LOOPPASSMANAGER_H diff --git a/include/llvm/Analysis/LoopUnrollAnalyzer.h b/include/llvm/Analysis/LoopUnrollAnalyzer.h new file mode 100644 index 000000000000..80f3e5fdcd43 --- /dev/null +++ b/include/llvm/Analysis/LoopUnrollAnalyzer.h @@ -0,0 +1,95 @@ +//===- llvm/Analysis/LoopUnrollAnalyzer.h - Loop Unroll Analyzer-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements UnrolledInstAnalyzer class. It's used for predicting +// potential effects that loop unrolling might have, such as enabling constant +// propagation and other optimizations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LOOPUNROLLANALYZER_H +#define LLVM_ANALYSIS_LOOPUNROLLANALYZER_H + +#include "llvm/Analysis/InstructionSimplify.h" +#include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/IR/InstVisitor.h" + +// This class is used to get an estimate of the optimization effects that we +// could get from complete loop unrolling. It comes from the fact that some +// loads might be replaced with concrete constant values and that could trigger +// a chain of instruction simplifications. +// +// E.g. we might have: +// int a[] = {0, 1, 0}; +// v = 0; +// for (i = 0; i < 3; i ++) +// v += b[i]*a[i]; +// If we completely unroll the loop, we would get: +// v = b[0]*a[0] + b[1]*a[1] + b[2]*a[2] +// Which then will be simplified to: +// v = b[0]* 0 + b[1]* 1 + b[2]* 0 +// And finally: +// v = b[1] +namespace llvm { +class UnrolledInstAnalyzer : private InstVisitor<UnrolledInstAnalyzer, bool> { + typedef InstVisitor<UnrolledInstAnalyzer, bool> Base; + friend class InstVisitor<UnrolledInstAnalyzer, bool>; + struct SimplifiedAddress { + Value *Base = nullptr; + ConstantInt *Offset = nullptr; + }; + +public: + UnrolledInstAnalyzer(unsigned Iteration, + DenseMap<Value *, Constant *> &SimplifiedValues, + ScalarEvolution &SE, const Loop *L) + : SimplifiedValues(SimplifiedValues), SE(SE), L(L) { + IterationNumber = SE.getConstant(APInt(64, Iteration)); + } + + // Allow access to the initial visit method. + using Base::visit; + +private: + /// \brief A cache of pointer bases and constant-folded offsets corresponding + /// to GEP (or derived from GEP) instructions. + /// + /// In order to find the base pointer one needs to perform non-trivial + /// traversal of the corresponding SCEV expression, so it's good to have the + /// results saved. + DenseMap<Value *, SimplifiedAddress> SimplifiedAddresses; + + /// \brief SCEV expression corresponding to number of currently simulated + /// iteration. + const SCEV *IterationNumber; + + /// \brief A Value->Constant map for keeping values that we managed to + /// constant-fold on the given iteration. + /// + /// While we walk the loop instructions, we build up and maintain a mapping + /// of simplified values specific to this iteration. The idea is to propagate + /// any special information we have about loads that can be replaced with + /// constants after complete unrolling, and account for likely simplifications + /// post-unrolling. + DenseMap<Value *, Constant *> &SimplifiedValues; + + ScalarEvolution &SE; + const Loop *L; + + bool simplifyInstWithSCEV(Instruction *I); + + bool visitInstruction(Instruction &I) { return simplifyInstWithSCEV(&I); } + bool visitBinaryOperator(BinaryOperator &I); + bool visitLoad(LoadInst &I); + bool visitCastInst(CastInst &I); + bool visitCmpInst(CmpInst &I); + bool visitPHINode(PHINode &PN); +}; +} +#endif diff --git a/include/llvm/Analysis/MemoryBuiltins.h b/include/llvm/Analysis/MemoryBuiltins.h index 493a99a4b11e..140b731c59de 100644 --- a/include/llvm/Analysis/MemoryBuiltins.h +++ b/include/llvm/Analysis/MemoryBuiltins.h @@ -32,6 +32,11 @@ class TargetLibraryInfo; class Type; class Value; +enum class ObjSizeMode { + Exact = 0, + Min = 1, + Max = 2 +}; /// \brief Tests if a value is a call or invoke to a library function that /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup @@ -130,8 +135,11 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) { /// underlying object pointed to by Ptr. /// If RoundToAlign is true, then Size is rounded up to the aligment of allocas, /// byval arguments, and global variables. +/// If Mode is Min or Max the size will be evaluated even if it depends on +/// a condition and corresponding value will be returned (min or max). bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, - const TargetLibraryInfo *TLI, bool RoundToAlign = false); + const TargetLibraryInfo *TLI, bool RoundToAlign = false, + ObjSizeMode Mode = ObjSizeMode::Exact); typedef std::pair<APInt, APInt> SizeOffsetType; @@ -143,6 +151,7 @@ class ObjectSizeOffsetVisitor const DataLayout &DL; const TargetLibraryInfo *TLI; bool RoundToAlign; + ObjSizeMode Mode; unsigned IntTyBits; APInt Zero; SmallPtrSet<Instruction *, 8> SeenInsts; @@ -155,19 +164,20 @@ class ObjectSizeOffsetVisitor public: ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, - LLVMContext &Context, bool RoundToAlign = false); + LLVMContext &Context, bool RoundToAlign = false, + ObjSizeMode Mode = ObjSizeMode::Exact); SizeOffsetType compute(Value *V); - bool knownSize(SizeOffsetType &SizeOffset) { + static bool knownSize(const SizeOffsetType &SizeOffset) { return SizeOffset.first.getBitWidth() > 1; } - bool knownOffset(SizeOffsetType &SizeOffset) { + static bool knownOffset(const SizeOffsetType &SizeOffset) { return SizeOffset.second.getBitWidth() > 1; } - bool bothKnown(SizeOffsetType &SizeOffset) { + static bool bothKnown(const SizeOffsetType &SizeOffset) { return knownSize(SizeOffset) && knownOffset(SizeOffset); } @@ -198,7 +208,7 @@ typedef std::pair<Value*, Value*> SizeOffsetEvalType; class ObjectSizeOffsetEvaluator : public InstVisitor<ObjectSizeOffsetEvaluator, SizeOffsetEvalType> { - typedef IRBuilder<true, TargetFolder> BuilderTy; + typedef IRBuilder<TargetFolder> BuilderTy; typedef std::pair<WeakVH, WeakVH> WeakEvalType; typedef DenseMap<const Value*, WeakEvalType> CacheMapTy; typedef SmallPtrSet<const Value*, 8> PtrSetTy; diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h index daa1ba91c071..b19dabbfc32e 100644 --- a/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -15,452 +15,493 @@ #define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerSumType.h" +#include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/PredIteratorCache.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" namespace llvm { - class Function; - class FunctionPass; - class Instruction; - class CallSite; - class AssumptionCache; - class MemoryDependenceAnalysis; - class PredIteratorCache; - class DominatorTree; - class PHITransAddr; - - /// MemDepResult - A memory dependence query can return one of three different - /// answers, described below. - class MemDepResult { - enum DepType { - /// Invalid - Clients of MemDep never see this. - Invalid = 0, - - /// Clobber - This is a dependence on the specified instruction which - /// clobbers the desired value. The pointer member of the MemDepResult - /// pair holds the instruction that clobbers the memory. For example, - /// this occurs when we see a may-aliased store to the memory location we - /// care about. - /// - /// There are several cases that may be interesting here: - /// 1. Loads are clobbered by may-alias stores. - /// 2. Loads are considered clobbered by partially-aliased loads. The - /// client may choose to analyze deeper into these cases. - Clobber, - - /// Def - This is a dependence on the specified instruction which - /// defines/produces the desired memory location. The pointer member of - /// the MemDepResult pair holds the instruction that defines the memory. - /// Cases of interest: - /// 1. This could be a load or store for dependence queries on - /// load/store. The value loaded or stored is the produced value. - /// Note that the pointer operand may be different than that of the - /// queried pointer due to must aliases and phi translation. Note - /// that the def may not be the same type as the query, the pointers - /// may just be must aliases. - /// 2. For loads and stores, this could be an allocation instruction. In - /// this case, the load is loading an undef value or a store is the - /// first store to (that part of) the allocation. - /// 3. Dependence queries on calls return Def only when they are - /// readonly calls or memory use intrinsics with identical callees - /// and no intervening clobbers. No validation is done that the - /// operands to the calls are the same. - Def, - - /// Other - This marker indicates that the query has no known dependency - /// in the specified block. More detailed state info is encoded in the - /// upper part of the pair (i.e. the Instruction*) - Other - }; - /// If DepType is "Other", the upper part of the pair - /// (i.e. the Instruction* part) is instead used to encode more detailed - /// type information as follows - enum OtherType { - /// NonLocal - This marker indicates that the query has no dependency in - /// the specified block. To find out more, the client should query other - /// predecessor blocks. - NonLocal = 0x4, - /// NonFuncLocal - This marker indicates that the query has no - /// dependency in the specified function. - NonFuncLocal = 0x8, - /// Unknown - This marker indicates that the query dependency - /// is unknown. - Unknown = 0xc - }; - - typedef PointerIntPair<Instruction*, 2, DepType> PairTy; - PairTy Value; - explicit MemDepResult(PairTy V) : Value(V) {} - - public: - MemDepResult() : Value(nullptr, Invalid) {} - - /// get methods: These are static ctor methods for creating various - /// MemDepResult kinds. - static MemDepResult getDef(Instruction *Inst) { - assert(Inst && "Def requires inst"); - return MemDepResult(PairTy(Inst, Def)); - } - static MemDepResult getClobber(Instruction *Inst) { - assert(Inst && "Clobber requires inst"); - return MemDepResult(PairTy(Inst, Clobber)); - } - static MemDepResult getNonLocal() { - return MemDepResult( - PairTy(reinterpret_cast<Instruction*>(NonLocal), Other)); - } - static MemDepResult getNonFuncLocal() { - return MemDepResult( - PairTy(reinterpret_cast<Instruction*>(NonFuncLocal), Other)); - } - static MemDepResult getUnknown() { - return MemDepResult( - PairTy(reinterpret_cast<Instruction*>(Unknown), Other)); - } - - /// isClobber - Return true if this MemDepResult represents a query that is - /// an instruction clobber dependency. - bool isClobber() const { return Value.getInt() == Clobber; } - - /// isDef - Return true if this MemDepResult represents a query that is - /// an instruction definition dependency. - bool isDef() const { return Value.getInt() == Def; } - - /// isNonLocal - Return true if this MemDepResult represents a query that - /// is transparent to the start of the block, but where a non-local hasn't - /// been done. - bool isNonLocal() const { - return Value.getInt() == Other - && Value.getPointer() == reinterpret_cast<Instruction*>(NonLocal); - } - - /// isNonFuncLocal - Return true if this MemDepResult represents a query - /// that is transparent to the start of the function. - bool isNonFuncLocal() const { - return Value.getInt() == Other - && Value.getPointer() == reinterpret_cast<Instruction*>(NonFuncLocal); - } - - /// isUnknown - Return true if this MemDepResult represents a query which - /// cannot and/or will not be computed. - bool isUnknown() const { - return Value.getInt() == Other - && Value.getPointer() == reinterpret_cast<Instruction*>(Unknown); - } - - /// getInst() - If this is a normal dependency, return the instruction that - /// is depended on. Otherwise, return null. - Instruction *getInst() const { - if (Value.getInt() == Other) return nullptr; - return Value.getPointer(); - } - - bool operator==(const MemDepResult &M) const { return Value == M.Value; } - bool operator!=(const MemDepResult &M) const { return Value != M.Value; } - bool operator<(const MemDepResult &M) const { return Value < M.Value; } - bool operator>(const MemDepResult &M) const { return Value > M.Value; } - - private: - friend class MemoryDependenceAnalysis; - /// Dirty - Entries with this marker occur in a LocalDeps map or - /// NonLocalDeps map when the instruction they previously referenced was - /// removed from MemDep. In either case, the entry may include an - /// instruction pointer. If so, the pointer is an instruction in the - /// block where scanning can start from, saving some work. +class Function; +class FunctionPass; +class Instruction; +class CallSite; +class AssumptionCache; +class MemoryDependenceResults; +class PredIteratorCache; +class DominatorTree; +class PHITransAddr; + +/// A memory dependence query can return one of three different answers. +class MemDepResult { + enum DepType { + /// Clients of MemDep never see this. /// - /// In a default-constructed MemDepResult object, the type will be Dirty - /// and the instruction pointer will be null. + /// Entries with this marker occur in a LocalDeps map or NonLocalDeps map + /// when the instruction they previously referenced was removed from + /// MemDep. In either case, the entry may include an instruction pointer. + /// If so, the pointer is an instruction in the block where scanning can + /// start from, saving some work. /// + /// In a default-constructed MemDepResult object, the type will be Invalid + /// and the instruction pointer will be null. + Invalid = 0, - /// isDirty - Return true if this is a MemDepResult in its dirty/invalid. - /// state. - bool isDirty() const { return Value.getInt() == Invalid; } - - static MemDepResult getDirty(Instruction *Inst) { - return MemDepResult(PairTy(Inst, Invalid)); - } + /// This is a dependence on the specified instruction which clobbers the + /// desired value. The pointer member of the MemDepResult pair holds the + /// instruction that clobbers the memory. For example, this occurs when we + /// see a may-aliased store to the memory location we care about. + /// + /// There are several cases that may be interesting here: + /// 1. Loads are clobbered by may-alias stores. + /// 2. Loads are considered clobbered by partially-aliased loads. The + /// client may choose to analyze deeper into these cases. + Clobber, + + /// This is a dependence on the specified instruction which defines or + /// produces the desired memory location. The pointer member of the + /// MemDepResult pair holds the instruction that defines the memory. + /// + /// Cases of interest: + /// 1. This could be a load or store for dependence queries on + /// load/store. The value loaded or stored is the produced value. + /// Note that the pointer operand may be different than that of the + /// queried pointer due to must aliases and phi translation. Note + /// that the def may not be the same type as the query, the pointers + /// may just be must aliases. + /// 2. For loads and stores, this could be an allocation instruction. In + /// this case, the load is loading an undef value or a store is the + /// first store to (that part of) the allocation. + /// 3. Dependence queries on calls return Def only when they are readonly + /// calls or memory use intrinsics with identical callees and no + /// intervening clobbers. No validation is done that the operands to + /// the calls are the same. + Def, + + /// This marker indicates that the query has no known dependency in the + /// specified block. + /// + /// More detailed state info is encoded in the upper part of the pair (i.e. + /// the Instruction*) + Other }; - /// NonLocalDepEntry - This is an entry in the NonLocalDepInfo cache. For - /// each BasicBlock (the BB entry) it keeps a MemDepResult. - class NonLocalDepEntry { - BasicBlock *BB; - MemDepResult Result; + /// If DepType is "Other", the upper part of the sum type is an encoding of + /// the following more detailed type information. + enum OtherType { + /// This marker indicates that the query has no dependency in the specified + /// block. + /// + /// To find out more, the client should query other predecessor blocks. + NonLocal = 1, + /// This marker indicates that the query has no dependency in the specified + /// function. + NonFuncLocal, + /// This marker indicates that the query dependency is unknown. + Unknown + }; - public: - NonLocalDepEntry(BasicBlock *bb, MemDepResult result) + typedef PointerSumType< + DepType, PointerSumTypeMember<Invalid, Instruction *>, + PointerSumTypeMember<Clobber, Instruction *>, + PointerSumTypeMember<Def, Instruction *>, + PointerSumTypeMember<Other, PointerEmbeddedInt<OtherType, 3>>> + ValueTy; + ValueTy Value; + explicit MemDepResult(ValueTy V) : Value(V) {} + +public: + MemDepResult() : Value() {} + + /// get methods: These are static ctor methods for creating various + /// MemDepResult kinds. + static MemDepResult getDef(Instruction *Inst) { + assert(Inst && "Def requires inst"); + return MemDepResult(ValueTy::create<Def>(Inst)); + } + static MemDepResult getClobber(Instruction *Inst) { + assert(Inst && "Clobber requires inst"); + return MemDepResult(ValueTy::create<Clobber>(Inst)); + } + static MemDepResult getNonLocal() { + return MemDepResult(ValueTy::create<Other>(NonLocal)); + } + static MemDepResult getNonFuncLocal() { + return MemDepResult(ValueTy::create<Other>(NonFuncLocal)); + } + static MemDepResult getUnknown() { + return MemDepResult(ValueTy::create<Other>(Unknown)); + } + + /// Tests if this MemDepResult represents a query that is an instruction + /// clobber dependency. + bool isClobber() const { return Value.is<Clobber>(); } + + /// Tests if this MemDepResult represents a query that is an instruction + /// definition dependency. + bool isDef() const { return Value.is<Def>(); } + + /// Tests if this MemDepResult represents a query that is transparent to the + /// start of the block, but where a non-local hasn't been done. + bool isNonLocal() const { + return Value.is<Other>() && Value.cast<Other>() == NonLocal; + } + + /// Tests if this MemDepResult represents a query that is transparent to the + /// start of the function. + bool isNonFuncLocal() const { + return Value.is<Other>() && Value.cast<Other>() == NonFuncLocal; + } + + /// Tests if this MemDepResult represents a query which cannot and/or will + /// not be computed. + bool isUnknown() const { + return Value.is<Other>() && Value.cast<Other>() == Unknown; + } + + /// If this is a normal dependency, returns the instruction that is depended + /// on. Otherwise, returns null. + Instruction *getInst() const { + switch (Value.getTag()) { + case Invalid: + return Value.cast<Invalid>(); + case Clobber: + return Value.cast<Clobber>(); + case Def: + return Value.cast<Def>(); + case Other: + return nullptr; + } + llvm_unreachable("Unknown discriminant!"); + } + + bool operator==(const MemDepResult &M) const { return Value == M.Value; } + bool operator!=(const MemDepResult &M) const { return Value != M.Value; } + bool operator<(const MemDepResult &M) const { return Value < M.Value; } + bool operator>(const MemDepResult &M) const { return Value > M.Value; } + +private: + friend class MemoryDependenceResults; + + /// Tests if this is a MemDepResult in its dirty/invalid. state. + bool isDirty() const { return Value.is<Invalid>(); } + + static MemDepResult getDirty(Instruction *Inst) { + return MemDepResult(ValueTy::create<Invalid>(Inst)); + } +}; + +/// This is an entry in the NonLocalDepInfo cache. +/// +/// For each BasicBlock (the BB entry) it keeps a MemDepResult. +class NonLocalDepEntry { + BasicBlock *BB; + MemDepResult Result; + +public: + NonLocalDepEntry(BasicBlock *bb, MemDepResult result) : BB(bb), Result(result) {} - // This is used for searches. - NonLocalDepEntry(BasicBlock *bb) : BB(bb) {} + // This is used for searches. + NonLocalDepEntry(BasicBlock *bb) : BB(bb) {} - // BB is the sort key, it can't be changed. - BasicBlock *getBB() const { return BB; } + // BB is the sort key, it can't be changed. + BasicBlock *getBB() const { return BB; } - void setResult(const MemDepResult &R) { Result = R; } + void setResult(const MemDepResult &R) { Result = R; } - const MemDepResult &getResult() const { return Result; } + const MemDepResult &getResult() const { return Result; } - bool operator<(const NonLocalDepEntry &RHS) const { - return BB < RHS.BB; - } - }; + bool operator<(const NonLocalDepEntry &RHS) const { return BB < RHS.BB; } +}; - /// NonLocalDepResult - This is a result from a NonLocal dependence query. - /// For each BasicBlock (the BB entry) it keeps a MemDepResult and the - /// (potentially phi translated) address that was live in the block. - class NonLocalDepResult { - NonLocalDepEntry Entry; - Value *Address; +/// This is a result from a NonLocal dependence query. +/// +/// For each BasicBlock (the BB entry) it keeps a MemDepResult and the +/// (potentially phi translated) address that was live in the block. +class NonLocalDepResult { + NonLocalDepEntry Entry; + Value *Address; - public: - NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address) +public: + NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address) : Entry(bb, result), Address(address) {} - // BB is the sort key, it can't be changed. - BasicBlock *getBB() const { return Entry.getBB(); } + // BB is the sort key, it can't be changed. + BasicBlock *getBB() const { return Entry.getBB(); } - void setResult(const MemDepResult &R, Value *Addr) { - Entry.setResult(R); - Address = Addr; - } + void setResult(const MemDepResult &R, Value *Addr) { + Entry.setResult(R); + Address = Addr; + } - const MemDepResult &getResult() const { return Entry.getResult(); } + const MemDepResult &getResult() const { return Entry.getResult(); } - /// getAddress - Return the address of this pointer in this block. This can - /// be different than the address queried for the non-local result because - /// of phi translation. This returns null if the address was not available - /// in a block (i.e. because phi translation failed) or if this is a cached - /// result and that address was deleted. + /// Returns the address of this pointer in this block. + /// + /// This can be different than the address queried for the non-local result + /// because of phi translation. This returns null if the address was not + /// available in a block (i.e. because phi translation failed) or if this is + /// a cached result and that address was deleted. + /// + /// The address is always null for a non-local 'call' dependence. + Value *getAddress() const { return Address; } +}; + +/// Provides a lazy, caching interface for making common memory aliasing +/// information queries, backed by LLVM's alias analysis passes. +/// +/// The dependency information returned is somewhat unusual, but is pragmatic. +/// If queried about a store or call that might modify memory, the analysis +/// will return the instruction[s] that may either load from that memory or +/// store to it. If queried with a load or call that can never modify memory, +/// the analysis will return calls and stores that might modify the pointer, +/// but generally does not return loads unless a) they are volatile, or +/// b) they load from *must-aliased* pointers. Returning a dependence on +/// must-alias'd pointers instead of all pointers interacts well with the +/// internal caching mechanism. +class MemoryDependenceResults { + // A map from instructions to their dependency. + typedef DenseMap<Instruction *, MemDepResult> LocalDepMapType; + LocalDepMapType LocalDeps; + +public: + typedef std::vector<NonLocalDepEntry> NonLocalDepInfo; + +private: + /// A pair<Value*, bool> where the bool is true if the dependence is a read + /// only dependence, false if read/write. + typedef PointerIntPair<const Value *, 1, bool> ValueIsLoadPair; + + /// This pair is used when caching information for a block. + /// + /// If the pointer is null, the cache value is not a full query that starts + /// at the specified block. If non-null, the bool indicates whether or not + /// the contents of the block was skipped. + typedef PointerIntPair<BasicBlock *, 1, bool> BBSkipFirstBlockPair; + + /// This record is the information kept for each (value, is load) pair. + struct NonLocalPointerInfo { + /// The pair of the block and the skip-first-block flag. + BBSkipFirstBlockPair Pair; + /// The results of the query for each relevant block. + NonLocalDepInfo NonLocalDeps; + /// The maximum size of the dereferences of the pointer. + /// + /// May be UnknownSize if the sizes are unknown. + uint64_t Size; + /// The AA tags associated with dereferences of the pointer. /// - /// The address is always null for a non-local 'call' dependence. - Value *getAddress() const { return Address; } + /// The members may be null if there are no tags or conflicting tags. + AAMDNodes AATags; + + NonLocalPointerInfo() : Size(MemoryLocation::UnknownSize) {} }; - /// MemoryDependenceAnalysis - This is an analysis that determines, for a - /// given memory operation, what preceding memory operations it depends on. - /// It builds on alias analysis information, and tries to provide a lazy, - /// caching interface to a common kind of alias information query. + /// This map stores the cached results of doing a pointer lookup at the + /// bottom of a block. /// - /// The dependency information returned is somewhat unusual, but is pragmatic. - /// If queried about a store or call that might modify memory, the analysis - /// will return the instruction[s] that may either load from that memory or - /// store to it. If queried with a load or call that can never modify memory, - /// the analysis will return calls and stores that might modify the pointer, - /// but generally does not return loads unless a) they are volatile, or - /// b) they load from *must-aliased* pointers. Returning a dependence on - /// must-alias'd pointers instead of all pointers interacts well with the - /// internal caching mechanism. + /// The key of this map is the pointer+isload bit, the value is a list of + /// <bb->result> mappings. + typedef DenseMap<ValueIsLoadPair, NonLocalPointerInfo> + CachedNonLocalPointerInfo; + CachedNonLocalPointerInfo NonLocalPointerDeps; + + // A map from instructions to their non-local pointer dependencies. + typedef DenseMap<Instruction *, SmallPtrSet<ValueIsLoadPair, 4>> + ReverseNonLocalPtrDepTy; + ReverseNonLocalPtrDepTy ReverseNonLocalPtrDeps; + + /// This is the instruction we keep for each cached access that we have for + /// an instruction. /// - class MemoryDependenceAnalysis : public FunctionPass { - // A map from instructions to their dependency. - typedef DenseMap<Instruction*, MemDepResult> LocalDepMapType; - LocalDepMapType LocalDeps; - - public: - typedef std::vector<NonLocalDepEntry> NonLocalDepInfo; - - private: - /// ValueIsLoadPair - This is a pair<Value*, bool> where the bool is true if - /// the dependence is a read only dependence, false if read/write. - typedef PointerIntPair<const Value*, 1, bool> ValueIsLoadPair; - - /// BBSkipFirstBlockPair - This pair is used when caching information for a - /// block. If the pointer is null, the cache value is not a full query that - /// starts at the specified block. If non-null, the bool indicates whether - /// or not the contents of the block was skipped. - typedef PointerIntPair<BasicBlock*, 1, bool> BBSkipFirstBlockPair; - - /// NonLocalPointerInfo - This record is the information kept for each - /// (value, is load) pair. - struct NonLocalPointerInfo { - /// Pair - The pair of the block and the skip-first-block flag. - BBSkipFirstBlockPair Pair; - /// NonLocalDeps - The results of the query for each relevant block. - NonLocalDepInfo NonLocalDeps; - /// Size - The maximum size of the dereferences of the - /// pointer. May be UnknownSize if the sizes are unknown. - uint64_t Size; - /// AATags - The AA tags associated with dereferences of the - /// pointer. The members may be null if there are no tags or - /// conflicting tags. - AAMDNodes AATags; - - NonLocalPointerInfo() : Size(MemoryLocation::UnknownSize) {} - }; - - /// CachedNonLocalPointerInfo - This map stores the cached results of doing - /// a pointer lookup at the bottom of a block. The key of this map is the - /// pointer+isload bit, the value is a list of <bb->result> mappings. - typedef DenseMap<ValueIsLoadPair, - NonLocalPointerInfo> CachedNonLocalPointerInfo; - CachedNonLocalPointerInfo NonLocalPointerDeps; - - // A map from instructions to their non-local pointer dependencies. - typedef DenseMap<Instruction*, - SmallPtrSet<ValueIsLoadPair, 4> > ReverseNonLocalPtrDepTy; - ReverseNonLocalPtrDepTy ReverseNonLocalPtrDeps; - - /// PerInstNLInfo - This is the instruction we keep for each cached access - /// that we have for an instruction. The pointer is an owning pointer and - /// the bool indicates whether we have any dirty bits in the set. - typedef std::pair<NonLocalDepInfo, bool> PerInstNLInfo; - - // A map from instructions to their non-local dependencies. - typedef DenseMap<Instruction*, PerInstNLInfo> NonLocalDepMapType; - - NonLocalDepMapType NonLocalDeps; - - // A reverse mapping from dependencies to the dependees. This is - // used when removing instructions to keep the cache coherent. - typedef DenseMap<Instruction*, - SmallPtrSet<Instruction*, 4> > ReverseDepMapType; - ReverseDepMapType ReverseLocalDeps; - - // A reverse mapping from dependencies to the non-local dependees. - ReverseDepMapType ReverseNonLocalDeps; - - /// Current AA implementation, just a cache. - AliasAnalysis *AA; - DominatorTree *DT; - AssumptionCache *AC; - const TargetLibraryInfo *TLI; - PredIteratorCache PredCache; - - public: - MemoryDependenceAnalysis(); - ~MemoryDependenceAnalysis() override; - static char ID; - - /// Pass Implementation stuff. This doesn't do any analysis eagerly. - bool runOnFunction(Function &) override; - - /// Clean up memory in between runs - void releaseMemory() override; - - /// getAnalysisUsage - Does not modify anything. It uses Value Numbering - /// and Alias Analysis. - /// - void getAnalysisUsage(AnalysisUsage &AU) const override; - - /// getDependency - Return the instruction on which a memory operation - /// depends. See the class comment for more details. It is illegal to call - /// this on non-memory instructions. - MemDepResult getDependency(Instruction *QueryInst); + /// The pointer is an owning pointer and the bool indicates whether we have + /// any dirty bits in the set. + typedef std::pair<NonLocalDepInfo, bool> PerInstNLInfo; + + // A map from instructions to their non-local dependencies. + typedef DenseMap<Instruction *, PerInstNLInfo> NonLocalDepMapType; + + NonLocalDepMapType NonLocalDeps; + + // A reverse mapping from dependencies to the dependees. This is + // used when removing instructions to keep the cache coherent. + typedef DenseMap<Instruction *, SmallPtrSet<Instruction *, 4>> + ReverseDepMapType; + ReverseDepMapType ReverseLocalDeps; + + // A reverse mapping from dependencies to the non-local dependees. + ReverseDepMapType ReverseNonLocalDeps; + + /// Current AA implementation, just a cache. + AliasAnalysis &AA; + AssumptionCache &AC; + const TargetLibraryInfo &TLI; + DominatorTree &DT; + PredIteratorCache PredCache; + +public: + MemoryDependenceResults(AliasAnalysis &AA, AssumptionCache &AC, + const TargetLibraryInfo &TLI, + DominatorTree &DT) + : AA(AA), AC(AC), TLI(TLI), DT(DT) {} + + /// Returns the instruction on which a memory operation depends. + /// + /// See the class comment for more details. It is illegal to call this on + /// non-memory instructions. + MemDepResult getDependency(Instruction *QueryInst); - /// getNonLocalCallDependency - Perform a full dependency query for the - /// specified call, returning the set of blocks that the value is - /// potentially live across. The returned set of results will include a - /// "NonLocal" result for all blocks where the value is live across. - /// - /// This method assumes the instruction returns a "NonLocal" dependency - /// within its own block. - /// - /// This returns a reference to an internal data structure that may be - /// invalidated on the next non-local query or when an instruction is - /// removed. Clients must copy this data if they want it around longer than - /// that. - const NonLocalDepInfo &getNonLocalCallDependency(CallSite QueryCS); - - /// getNonLocalPointerDependency - Perform a full dependency query for an - /// access to the QueryInst's specified memory location, returning the set - /// of instructions that either define or clobber the value. - /// - /// Warning: For a volatile query instruction, the dependencies will be - /// accurate, and thus usable for reordering, but it is never legal to - /// remove the query instruction. - /// - /// This method assumes the pointer has a "NonLocal" dependency within - /// QueryInst's parent basic block. - void getNonLocalPointerDependency(Instruction *QueryInst, + /// Perform a full dependency query for the specified call, returning the set + /// of blocks that the value is potentially live across. + /// + /// The returned set of results will include a "NonLocal" result for all + /// blocks where the value is live across. + /// + /// This method assumes the instruction returns a "NonLocal" dependency + /// within its own block. + /// + /// This returns a reference to an internal data structure that may be + /// invalidated on the next non-local query or when an instruction is + /// removed. Clients must copy this data if they want it around longer than + /// that. + const NonLocalDepInfo &getNonLocalCallDependency(CallSite QueryCS); + + /// Perform a full dependency query for an access to the QueryInst's + /// specified memory location, returning the set of instructions that either + /// define or clobber the value. + /// + /// Warning: For a volatile query instruction, the dependencies will be + /// accurate, and thus usable for reordering, but it is never legal to + /// remove the query instruction. + /// + /// This method assumes the pointer has a "NonLocal" dependency within + /// QueryInst's parent basic block. + void getNonLocalPointerDependency(Instruction *QueryInst, SmallVectorImpl<NonLocalDepResult> &Result); - /// removeInstruction - Remove an instruction from the dependence analysis, - /// updating the dependence of instructions that previously depended on it. - void removeInstruction(Instruction *InstToRemove); - - /// invalidateCachedPointerInfo - This method is used to invalidate cached - /// information about the specified pointer, because it may be too - /// conservative in memdep. This is an optional call that can be used when - /// the client detects an equivalence between the pointer and some other - /// value and replaces the other value with ptr. This can make Ptr available - /// in more places that cached info does not necessarily keep. - void invalidateCachedPointerInfo(Value *Ptr); - - /// invalidateCachedPredecessors - Clear the PredIteratorCache info. - /// This needs to be done when the CFG changes, e.g., due to splitting - /// critical edges. - void invalidateCachedPredecessors(); - - /// \brief Return the instruction on which a memory location depends. - /// If isLoad is true, this routine ignores may-aliases with read-only - /// operations. If isLoad is false, this routine ignores may-aliases - /// with reads from read-only locations. If possible, pass the query - /// instruction as well; this function may take advantage of the metadata - /// annotated to the query instruction to refine the result. - /// - /// Note that this is an uncached query, and thus may be inefficient. - /// - MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, - bool isLoad, - BasicBlock::iterator ScanIt, - BasicBlock *BB, - Instruction *QueryInst = nullptr); - - MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, - bool isLoad, - BasicBlock::iterator ScanIt, - BasicBlock *BB, - Instruction *QueryInst); - - /// This analysis looks for other loads and stores with invariant.group - /// metadata and the same pointer operand. Returns Unknown if it does not - /// find anything, and Def if it can be assumed that 2 instructions load or - /// store the same value. - /// FIXME: This analysis works only on single block because of restrictions - /// at the call site. - MemDepResult getInvariantGroupPointerDependency(LoadInst *LI, - BasicBlock *BB); - - /// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that - /// looks at a memory location for a load (specified by MemLocBase, Offs, - /// and Size) and compares it against a load. If the specified load could - /// be safely widened to a larger integer load that is 1) still efficient, - /// 2) safe for the target, and 3) would provide the specified memory - /// location value, then this function returns the size in bytes of the - /// load width to use. If not, this returns zero. - static unsigned getLoadLoadClobberFullWidthSize(const Value *MemLocBase, - int64_t MemLocOffs, - unsigned MemLocSize, - const LoadInst *LI); - - private: - MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall, - BasicBlock::iterator ScanIt, - BasicBlock *BB); - bool getNonLocalPointerDepFromBB(Instruction *QueryInst, - const PHITransAddr &Pointer, - const MemoryLocation &Loc, bool isLoad, - BasicBlock *BB, - SmallVectorImpl<NonLocalDepResult> &Result, - DenseMap<BasicBlock *, Value *> &Visited, - bool SkipFirstBlock = false); - MemDepResult GetNonLocalInfoForBlock(Instruction *QueryInst, - const MemoryLocation &Loc, bool isLoad, - BasicBlock *BB, NonLocalDepInfo *Cache, - unsigned NumSortedEntries); - - void RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P); - - /// verifyRemoved - Verify that the specified instruction does not occur - /// in our internal data structures. - void verifyRemoved(Instruction *Inst) const; - }; + /// Removes an instruction from the dependence analysis, updating the + /// dependence of instructions that previously depended on it. + void removeInstruction(Instruction *InstToRemove); + + /// Invalidates cached information about the specified pointer, because it + /// may be too conservative in memdep. + /// + /// This is an optional call that can be used when the client detects an + /// equivalence between the pointer and some other value and replaces the + /// other value with ptr. This can make Ptr available in more places that + /// cached info does not necessarily keep. + void invalidateCachedPointerInfo(Value *Ptr); + + /// Clears the PredIteratorCache info. + /// + /// This needs to be done when the CFG changes, e.g., due to splitting + /// critical edges. + void invalidateCachedPredecessors(); + + /// Returns the instruction on which a memory location depends. + /// + /// If isLoad is true, this routine ignores may-aliases with read-only + /// operations. If isLoad is false, this routine ignores may-aliases + /// with reads from read-only locations. If possible, pass the query + /// instruction as well; this function may take advantage of the metadata + /// annotated to the query instruction to refine the result. + /// + /// Note that this is an uncached query, and thus may be inefficient. + MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, bool isLoad, + BasicBlock::iterator ScanIt, + BasicBlock *BB, + Instruction *QueryInst = nullptr); + + MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, + bool isLoad, + BasicBlock::iterator ScanIt, + BasicBlock *BB, + Instruction *QueryInst); + + /// This analysis looks for other loads and stores with invariant.group + /// metadata and the same pointer operand. Returns Unknown if it does not + /// find anything, and Def if it can be assumed that 2 instructions load or + /// store the same value. + /// FIXME: This analysis works only on single block because of restrictions + /// at the call site. + MemDepResult getInvariantGroupPointerDependency(LoadInst *LI, BasicBlock *BB); + + /// Looks at a memory location for a load (specified by MemLocBase, Offs, and + /// Size) and compares it against a load. + /// + /// If the specified load could be safely widened to a larger integer load + /// that is 1) still efficient, 2) safe for the target, and 3) would provide + /// the specified memory location value, then this function returns the size + /// in bytes of the load width to use. If not, this returns zero. + static unsigned getLoadLoadClobberFullWidthSize(const Value *MemLocBase, + int64_t MemLocOffs, + unsigned MemLocSize, + const LoadInst *LI); + + /// Release memory in caches. + void releaseMemory(); + +private: + MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall, + BasicBlock::iterator ScanIt, + BasicBlock *BB); + bool getNonLocalPointerDepFromBB(Instruction *QueryInst, + const PHITransAddr &Pointer, + const MemoryLocation &Loc, bool isLoad, + BasicBlock *BB, + SmallVectorImpl<NonLocalDepResult> &Result, + DenseMap<BasicBlock *, Value *> &Visited, + bool SkipFirstBlock = false); + MemDepResult GetNonLocalInfoForBlock(Instruction *QueryInst, + const MemoryLocation &Loc, bool isLoad, + BasicBlock *BB, NonLocalDepInfo *Cache, + unsigned NumSortedEntries); + + void RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P); + + void verifyRemoved(Instruction *Inst) const; +}; + +/// An analysis that produces \c MemoryDependenceResults for a function. +/// +/// This is essentially a no-op because the results are computed entirely +/// lazily. +class MemoryDependenceAnalysis + : public AnalysisInfoMixin<MemoryDependenceAnalysis> { + friend AnalysisInfoMixin<MemoryDependenceAnalysis>; + static char PassID; + +public: + typedef MemoryDependenceResults Result; + + MemoryDependenceResults run(Function &F, AnalysisManager<Function> &AM); +}; + +/// A wrapper analysis pass for the legacy pass manager that exposes a \c +/// MemoryDepnedenceResults instance. +class MemoryDependenceWrapperPass : public FunctionPass { + Optional<MemoryDependenceResults> MemDep; +public: + MemoryDependenceWrapperPass(); + ~MemoryDependenceWrapperPass() override; + static char ID; + + /// Pass Implementation stuff. This doesn't do any analysis eagerly. + bool runOnFunction(Function &) override; + + /// Clean up memory in between runs + void releaseMemory() override; + + /// Does not modify anything. It uses Value Numbering and Alias Analysis. + void getAnalysisUsage(AnalysisUsage &AU) const override; + + MemoryDependenceResults &getMemDep() { return *MemDep; } +}; } // End llvm namespace diff --git a/include/llvm/Analysis/MemoryLocation.h b/include/llvm/Analysis/MemoryLocation.h index 426b49a3ecd7..f2cb2a123f2e 100644 --- a/include/llvm/Analysis/MemoryLocation.h +++ b/include/llvm/Analysis/MemoryLocation.h @@ -16,7 +16,7 @@ #ifndef LLVM_ANALYSIS_MEMORYLOCATION_H #define LLVM_ANALYSIS_MEMORYLOCATION_H -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Metadata.h" diff --git a/include/llvm/Analysis/ModuleSummaryAnalysis.h b/include/llvm/Analysis/ModuleSummaryAnalysis.h new file mode 100644 index 000000000000..9f03610ba5b1 --- /dev/null +++ b/include/llvm/Analysis/ModuleSummaryAnalysis.h @@ -0,0 +1,91 @@ +//===- ModuleSummaryAnalysis.h - Module summary index builder ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface to build a ModuleSummaryIndex for a module. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H +#define LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Pass.h" + +namespace llvm { + +class BlockFrequencyInfo; + +/// Class to build a module summary index for the given Module, possibly from +/// a Pass. +class ModuleSummaryIndexBuilder { + /// The index being built + std::unique_ptr<ModuleSummaryIndex> Index; + /// The module for which we are building an index + const Module *M; + +public: + /// Default constructor + ModuleSummaryIndexBuilder() = default; + + /// Constructor that builds an index for the given Module. An optional + /// callback can be supplied to obtain the frequency info for a function. + ModuleSummaryIndexBuilder( + const Module *M, + std::function<BlockFrequencyInfo *(const Function &F)> Ftor = nullptr); + + /// Get a reference to the index owned by builder + ModuleSummaryIndex &getIndex() const { return *Index; } + + /// Take ownership of the built index + std::unique_ptr<ModuleSummaryIndex> takeIndex() { return std::move(Index); } + +private: + /// Compute summary for given function with optional frequency information + void computeFunctionSummary(const Function &F, + BlockFrequencyInfo *BFI = nullptr); + + /// Compute summary for given variable with optional frequency information + void computeVariableSummary(const GlobalVariable &V); +}; + +/// Legacy wrapper pass to provide the ModuleSummaryIndex object. +class ModuleSummaryIndexWrapperPass : public ModulePass { + std::unique_ptr<ModuleSummaryIndexBuilder> IndexBuilder; + +public: + static char ID; + + ModuleSummaryIndexWrapperPass(); + + /// Get the index built by pass + ModuleSummaryIndex &getIndex() { return IndexBuilder->getIndex(); } + const ModuleSummaryIndex &getIndex() const { + return IndexBuilder->getIndex(); + } + + bool runOnModule(Module &M) override; + bool doFinalization(Module &M) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +//===--------------------------------------------------------------------===// +// +// createModuleSummaryIndexWrapperPass - This pass builds a ModuleSummaryIndex +// object for the module, to be written to bitcode or LLVM assembly. +// +ModulePass *createModuleSummaryIndexWrapperPass(); + +/// Returns true if \p M is eligible for ThinLTO promotion. +/// +/// Currently we check if it has any any InlineASM that uses an internal symbol. +bool moduleCanBeRenamedForThinLTO(const Module &M); +} + +#endif diff --git a/include/llvm/Analysis/ObjCARCAliasAnalysis.h b/include/llvm/Analysis/ObjCARCAliasAnalysis.h index ac01154bac6c..067a964bcce1 100644 --- a/include/llvm/Analysis/ObjCARCAliasAnalysis.h +++ b/include/llvm/Analysis/ObjCARCAliasAnalysis.h @@ -24,7 +24,6 @@ #define LLVM_ANALYSIS_OBJCARCALIASANALYSIS_H #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Pass.h" namespace llvm { @@ -42,8 +41,7 @@ class ObjCARCAAResult : public AAResultBase<ObjCARCAAResult> { const DataLayout &DL; public: - explicit ObjCARCAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI) - : AAResultBase(TLI), DL(DL) {} + explicit ObjCARCAAResult(const DataLayout &DL) : AAResultBase(), DL(DL) {} ObjCARCAAResult(ObjCARCAAResult &&Arg) : AAResultBase(std::move(Arg)), DL(Arg.DL) {} @@ -63,20 +61,14 @@ public: }; /// Analysis pass providing a never-invalidated alias analysis result. -class ObjCARCAA { +class ObjCARCAA : public AnalysisInfoMixin<ObjCARCAA> { + friend AnalysisInfoMixin<ObjCARCAA>; + static char PassID; + public: typedef ObjCARCAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - ObjCARCAAResult run(Function &F, AnalysisManager<Function> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "ObjCARCAA"; } - -private: - static char PassID; + ObjCARCAAResult run(Function &F, AnalysisManager<Function> &AM); }; /// Legacy wrapper pass to provide the ObjCARCAAResult object. diff --git a/include/llvm/Analysis/ObjCARCAnalysisUtils.h b/include/llvm/Analysis/ObjCARCAnalysisUtils.h index 29d99c9d316d..5f4d8ecbbfbb 100644 --- a/include/llvm/Analysis/ObjCARCAnalysisUtils.h +++ b/include/llvm/Analysis/ObjCARCAnalysisUtils.h @@ -54,6 +54,7 @@ inline bool ModuleHasARC(const Module &M) { M.getNamedValue("objc_release") || M.getNamedValue("objc_autorelease") || M.getNamedValue("objc_retainAutoreleasedReturnValue") || + M.getNamedValue("objc_unsafeClaimAutoreleasedReturnValue") || M.getNamedValue("objc_retainBlock") || M.getNamedValue("objc_autoreleaseReturnValue") || M.getNamedValue("objc_autoreleasePoolPush") || diff --git a/include/llvm/Analysis/ObjCARCInstKind.h b/include/llvm/Analysis/ObjCARCInstKind.h index 13efb4b160be..3b37ddf78f58 100644 --- a/include/llvm/Analysis/ObjCARCInstKind.h +++ b/include/llvm/Analysis/ObjCARCInstKind.h @@ -30,6 +30,7 @@ namespace objcarc { enum class ARCInstKind { Retain, ///< objc_retain RetainRV, ///< objc_retainAutoreleasedReturnValue + ClaimRV, ///< objc_unsafeClaimAutoreleasedReturnValue RetainBlock, ///< objc_retainBlock Release, ///< objc_release Autorelease, ///< objc_autorelease diff --git a/include/llvm/Analysis/OptimizationDiagnosticInfo.h b/include/llvm/Analysis/OptimizationDiagnosticInfo.h new file mode 100644 index 000000000000..b455a6527bf6 --- /dev/null +++ b/include/llvm/Analysis/OptimizationDiagnosticInfo.h @@ -0,0 +1,104 @@ +//===- OptimizationDiagnosticInfo.h - Optimization Diagnostic ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Optimization diagnostic interfaces. It's packaged as an analysis pass so +// that by using this service passes become dependent on BFI as well. BFI is +// used to compute the "hotness" of the diagnostic message. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H +#define LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H + +#include "llvm/ADT/Optional.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" + +namespace llvm { +class BlockFrequencyInfo; +class DebugLoc; +class Function; +class LLVMContext; +class Loop; +class Pass; +class Twine; +class Value; + +class OptimizationRemarkEmitter { +public: + OptimizationRemarkEmitter(Function *F, BlockFrequencyInfo *BFI) + : F(F), BFI(BFI) {} + + OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg) + : F(Arg.F), BFI(Arg.BFI) {} + + OptimizationRemarkEmitter &operator=(OptimizationRemarkEmitter &&RHS) { + F = RHS.F; + BFI = RHS.BFI; + return *this; + } + + /// Emit an optimization-missed message. + /// + /// \p PassName is the name of the pass emitting the message. If + /// -Rpass-missed= is given and the name 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 V is the IR Value that identifies the code region. \p Msg is + /// the message string to use. + void emitOptimizationRemarkMissed(const char *PassName, const DebugLoc &DLoc, + Value *V, const Twine &Msg); + + /// \brief Same as above but derives the IR Value for the code region and the + /// debug location from the Loop parameter \p L. + void emitOptimizationRemarkMissed(const char *PassName, Loop *L, + const Twine &Msg); + +private: + Function *F; + + BlockFrequencyInfo *BFI; + + Optional<uint64_t> computeHotness(Value *V); + + OptimizationRemarkEmitter(const OptimizationRemarkEmitter &) = delete; + void operator=(const OptimizationRemarkEmitter &) = delete; +}; + +class OptimizationRemarkEmitterWrapperPass : public FunctionPass { + std::unique_ptr<OptimizationRemarkEmitter> ORE; + +public: + OptimizationRemarkEmitterWrapperPass(); + + bool runOnFunction(Function &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + OptimizationRemarkEmitter &getORE() { + assert(ORE && "pass not run yet"); + return *ORE; + } + + static char ID; +}; + +class OptimizationRemarkEmitterAnalysis + : public AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis> { + friend AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis>; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef OptimizationRemarkEmitter Result; + + /// \brief Run the analysis pass over a function and produce BFI. + Result run(Function &F, AnalysisManager<Function> &AM); +}; +} +#endif // LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H diff --git a/include/llvm/Analysis/Passes.h b/include/llvm/Analysis/Passes.h index da17457d3446..6d8f14fa32f9 100644 --- a/include/llvm/Analysis/Passes.h +++ b/include/llvm/Analysis/Passes.h @@ -25,13 +25,6 @@ namespace llvm { //===--------------------------------------------------------------------===// // - // createAAEvalPass - This pass implements a simple N^2 alias analysis - // accuracy evaluator. - // - FunctionPass *createAAEvalPass(); - - //===--------------------------------------------------------------------===// - // // createObjCARCAAWrapperPass - This pass implements ObjC-ARC-based // alias analysis. // @@ -47,10 +40,10 @@ namespace llvm { //===--------------------------------------------------------------------===// // - // createDependenceAnalysisPass - This creates an instance of the - // DependenceAnalysis pass. + // createDependenceAnalysisWrapperPass - This creates an instance of the + // DependenceAnalysisWrapper pass. // - FunctionPass *createDependenceAnalysisPass(); + FunctionPass *createDependenceAnalysisWrapperPass(); //===--------------------------------------------------------------------===// // diff --git a/include/llvm/Analysis/PostDominators.h b/include/llvm/Analysis/PostDominators.h index 0f7e2b88d2d7..99240a40408e 100644 --- a/include/llvm/Analysis/PostDominators.h +++ b/include/llvm/Analysis/PostDominators.h @@ -15,78 +15,71 @@ #define LLVM_ANALYSIS_POSTDOMINATORS_H #include "llvm/IR/Dominators.h" +#include "llvm/IR/PassManager.h" namespace llvm { /// PostDominatorTree Class - Concrete subclass of DominatorTree that is used to /// compute the post-dominator tree. /// -struct PostDominatorTree : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - DominatorTreeBase<BasicBlock>* DT; - - PostDominatorTree() : FunctionPass(ID) { - initializePostDominatorTreePass(*PassRegistry::getPassRegistry()); - DT = new DominatorTreeBase<BasicBlock>(true); - } +struct PostDominatorTree : public DominatorTreeBase<BasicBlock> { + typedef DominatorTreeBase<BasicBlock> Base; - ~PostDominatorTree() override; + PostDominatorTree() : DominatorTreeBase<BasicBlock>(true) {} - bool runOnFunction(Function &F) override; - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } + PostDominatorTree(PostDominatorTree &&Arg) + : Base(std::move(static_cast<Base &>(Arg))) {} - inline const std::vector<BasicBlock*> &getRoots() const { - return DT->getRoots(); + PostDominatorTree &operator=(PostDominatorTree &&RHS) { + Base::operator=(std::move(static_cast<Base &>(RHS))); + return *this; } +}; - inline DomTreeNode *getRootNode() const { - return DT->getRootNode(); - } +/// \brief Analysis pass which computes a \c PostDominatorTree. +class PostDominatorTreeAnalysis + : public AnalysisInfoMixin<PostDominatorTreeAnalysis> { + friend AnalysisInfoMixin<PostDominatorTreeAnalysis>; + static char PassID; - inline DomTreeNode *operator[](BasicBlock *BB) const { - return DT->getNode(BB); - } +public: + /// \brief Provide the result typedef for this analysis pass. + typedef PostDominatorTree Result; - inline DomTreeNode *getNode(BasicBlock *BB) const { - return DT->getNode(BB); - } + /// \brief Run the analysis pass over a function and produce a post dominator + /// tree. + PostDominatorTree run(Function &F, FunctionAnalysisManager &); +}; - inline bool dominates(DomTreeNode* A, DomTreeNode* B) const { - return DT->dominates(A, B); - } +/// \brief Printer pass for the \c PostDominatorTree. +class PostDominatorTreePrinterPass + : public PassInfoMixin<PostDominatorTreePrinterPass> { + raw_ostream &OS; - inline bool dominates(const BasicBlock* A, const BasicBlock* B) const { - return DT->dominates(A, B); - } +public: + explicit PostDominatorTreePrinterPass(raw_ostream &OS); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; - inline bool properlyDominates(const DomTreeNode* A, DomTreeNode* B) const { - return DT->properlyDominates(A, B); - } +struct PostDominatorTreeWrapperPass : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + PostDominatorTree DT; - inline bool properlyDominates(BasicBlock* A, BasicBlock* B) const { - return DT->properlyDominates(A, B); + PostDominatorTreeWrapperPass() : FunctionPass(ID) { + initializePostDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry()); } - inline BasicBlock *findNearestCommonDominator(BasicBlock *A, BasicBlock *B) { - return DT->findNearestCommonDominator(A, B); - } + PostDominatorTree &getPostDomTree() { return DT; } + const PostDominatorTree &getPostDomTree() const { return DT; } - inline const BasicBlock *findNearestCommonDominator(const BasicBlock *A, - const BasicBlock *B) { - return DT->findNearestCommonDominator(A, B); - } + bool runOnFunction(Function &F) override; - /// Get all nodes post-dominated by R, including R itself. - void getDescendants(BasicBlock *R, - SmallVectorImpl<BasicBlock *> &Result) const { - DT->getDescendants(R, Result); + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); } void releaseMemory() override { - DT->releaseMemory(); + DT.releaseMemory(); } void print(raw_ostream &OS, const Module*) const override; diff --git a/include/llvm/Analysis/ProfileSummaryInfo.h b/include/llvm/Analysis/ProfileSummaryInfo.h new file mode 100644 index 000000000000..cd624c8404da --- /dev/null +++ b/include/llvm/Analysis/ProfileSummaryInfo.h @@ -0,0 +1,113 @@ +//===- llvm/Analysis/ProfileSummaryInfo.h - profile summary ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a pass that provides access to profile summary +// information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H +#define LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include <memory> + +namespace llvm { +class ProfileSummary; +/// \brief Analysis providing profile information. +/// +/// This is an immutable analysis pass that provides ability to query global +/// (program-level) profile information. The main APIs are isHotCount and +/// isColdCount that tells whether a given profile count is considered hot/cold +/// based on the profile summary. This also provides convenience methods to +/// check whether a function is hot or cold. + +// FIXME: Provide convenience methods to determine hotness/coldness of other IR +// units. This would require making this depend on BFI. +class ProfileSummaryInfo { +private: + Module &M; + std::unique_ptr<ProfileSummary> Summary; + void computeSummary(); + void computeThresholds(); + // Count thresholds to answer isHotCount and isColdCount queries. + Optional<uint64_t> HotCountThreshold, ColdCountThreshold; + +public: + ProfileSummaryInfo(Module &M) : M(M) {} + ProfileSummaryInfo(ProfileSummaryInfo &&Arg) + : M(Arg.M), Summary(std::move(Arg.Summary)) {} + /// \brief Returns true if \p F is a hot function. + bool isHotFunction(const Function *F); + /// \brief Returns true if \p F is a cold function. + bool isColdFunction(const Function *F); + /// \brief Returns true if count \p C is considered hot. + bool isHotCount(uint64_t C); + /// \brief Returns true if count \p C is considered cold. + bool isColdCount(uint64_t C); +}; + +/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo. +class ProfileSummaryInfoWrapperPass : public ImmutablePass { + std::unique_ptr<ProfileSummaryInfo> PSI; + +public: + static char ID; + ProfileSummaryInfoWrapperPass(); + + ProfileSummaryInfo *getPSI(Module &M); + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +/// An analysis pass based on the new PM to deliver ProfileSummaryInfo. +class ProfileSummaryAnalysis + : public AnalysisInfoMixin<ProfileSummaryAnalysis> { +public: + typedef ProfileSummaryInfo Result; + + ProfileSummaryAnalysis() {} + ProfileSummaryAnalysis(const ProfileSummaryAnalysis &Arg) {} + ProfileSummaryAnalysis(ProfileSummaryAnalysis &&Arg) {} + ProfileSummaryAnalysis &operator=(const ProfileSummaryAnalysis &RHS) { + return *this; + } + ProfileSummaryAnalysis &operator=(ProfileSummaryAnalysis &&RHS) { + return *this; + } + + Result run(Module &M, ModuleAnalysisManager &); + +private: + friend AnalysisInfoMixin<ProfileSummaryAnalysis>; + static char PassID; +}; + +/// \brief Printer pass that uses \c ProfileSummaryAnalysis. +class ProfileSummaryPrinterPass + : public PassInfoMixin<ProfileSummaryPrinterPass> { + raw_ostream &OS; + +public: + explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/RegionInfo.h b/include/llvm/Analysis/RegionInfo.h index 4988386fdc82..91bfd435f08c 100644 --- a/include/llvm/Analysis/RegionInfo.h +++ b/include/llvm/Analysis/RegionInfo.h @@ -41,6 +41,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/PassManager.h" #include <map> #include <memory> #include <set> @@ -676,6 +677,22 @@ class RegionInfoBase { RegionInfoBase(const RegionInfoBase &) = delete; const RegionInfoBase &operator=(const RegionInfoBase &) = delete; + RegionInfoBase(RegionInfoBase &&Arg) + : DT(std::move(Arg.DT)), PDT(std::move(Arg.PDT)), DF(std::move(Arg.DF)), + TopLevelRegion(std::move(Arg.TopLevelRegion)), + BBtoRegion(std::move(Arg.BBtoRegion)) { + Arg.wipe(); + } + RegionInfoBase &operator=(RegionInfoBase &&RHS) { + DT = std::move(RHS.DT); + PDT = std::move(RHS.PDT); + DF = std::move(RHS.DF); + TopLevelRegion = std::move(RHS.TopLevelRegion); + BBtoRegion = std::move(RHS.BBtoRegion); + RHS.wipe(); + return *this; + } + DomTreeT *DT; PostDomTreeT *PDT; DomFrontierT *DF; @@ -687,6 +704,18 @@ private: /// Map every BB to the smallest region, that contains BB. BBtoRegionMap BBtoRegion; + /// \brief Wipe this region tree's state without releasing any resources. + /// + /// This is essentially a post-move helper only. It leaves the object in an + /// assignable and destroyable state, but otherwise invalid. + void wipe() { + DT = nullptr; + PDT = nullptr; + DF = nullptr; + TopLevelRegion = nullptr; + BBtoRegion.clear(); + } + // Check whether the entries of BBtoRegion for the BBs of region // SR are correct. Triggers an assertion if not. Calls itself recursively for // subregions. @@ -836,10 +865,19 @@ public: class RegionInfo : public RegionInfoBase<RegionTraits<Function>> { public: + typedef RegionInfoBase<RegionTraits<Function>> Base; + explicit RegionInfo(); ~RegionInfo() override; + RegionInfo(RegionInfo &&Arg) + : Base(std::move(static_cast<Base &>(Arg))) {} + RegionInfo &operator=(RegionInfo &&RHS) { + Base::operator=(std::move(static_cast<Base &>(RHS))); + return *this; + } + // updateStatistics - Update statistic about created regions. void updateStatistics(Region *R) final; @@ -884,6 +922,31 @@ public: //@} }; +/// \brief Analysis pass that exposes the \c RegionInfo for a function. +class RegionInfoAnalysis : public AnalysisInfoMixin<RegionInfoAnalysis> { + friend AnalysisInfoMixin<RegionInfoAnalysis>; + static char PassID; + +public: + typedef RegionInfo Result; + + RegionInfo run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for the \c RegionInfo. +class RegionInfoPrinterPass : public PassInfoMixin<RegionInfoPrinterPass> { + raw_ostream &OS; + +public: + explicit RegionInfoPrinterPass(raw_ostream &OS); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Verifier pass for the \c RegionInfo. +struct RegionInfoVerifierPass : PassInfoMixin<RegionInfoVerifierPass> { + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + template <> template <> inline BasicBlock * diff --git a/include/llvm/Analysis/RegionInfoImpl.h b/include/llvm/Analysis/RegionInfoImpl.h index 134cd8f96fbe..15dd1a2000e6 100644 --- a/include/llvm/Analysis/RegionInfoImpl.h +++ b/include/llvm/Analysis/RegionInfoImpl.h @@ -18,7 +18,6 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/RegionInfo.h" #include "llvm/Analysis/RegionIterator.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> @@ -666,7 +665,7 @@ typename Tr::RegionT *RegionInfoBase<Tr>::createRegion(BlockT *entry, new RegionT(entry, exit, static_cast<RegionInfoT *>(this), DT); BBtoRegion.insert(std::make_pair(entry, region)); -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS region->verifyRegion(); #else DEBUG(region->verifyRegion()); @@ -765,7 +764,7 @@ void RegionInfoBase<Tr>::buildRegionsTree(DomTreeNodeT *N, RegionT *region) { } } -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS template <class Tr> bool RegionInfoBase<Tr>::VerifyRegionInfo = true; #else @@ -799,7 +798,7 @@ void RegionInfoBase<Tr>::releaseMemory() { template <class Tr> void RegionInfoBase<Tr>::verifyAnalysis() const { - // Do only verify regions if explicitely activated using XDEBUG or + // Do only verify regions if explicitely activated using EXPENSIVE_CHECKS or // -verify-region-info if (!RegionInfoBase<Tr>::VerifyRegionInfo) return; diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index ef9305788849..535b623d31ac 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -23,17 +23,17 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/ConstantRange.h" -#include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/IR/ValueMap.h" #include "llvm/Pass.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/DataTypes.h" -#include <map> namespace llvm { class APInt; @@ -53,6 +53,7 @@ namespace llvm { class SCEVExpander; class SCEVPredicate; class SCEVUnknown; + class Function; template <> struct FoldingSetTrait<SCEV>; template <> struct FoldingSetTrait<SCEVPredicate>; @@ -168,8 +169,8 @@ namespace llvm { static bool classof(const SCEV *S); }; - /// SCEVPredicate - This class represents an assumption made using SCEV - /// expressions which can be checked at run-time. + /// This class represents an assumption made using SCEV expressions which can + /// be checked at run-time. class SCEVPredicate : public FoldingSetNode { friend struct FoldingSetTrait<SCEVPredicate>; @@ -178,7 +179,7 @@ namespace llvm { FoldingSetNodeIDRef FastID; public: - enum SCEVPredicateKind { P_Union, P_Equal }; + enum SCEVPredicateKind { P_Union, P_Equal, P_Wrap }; protected: SCEVPredicateKind Kind; @@ -191,23 +192,23 @@ namespace llvm { SCEVPredicateKind getKind() const { return Kind; } - /// \brief Returns the estimated complexity of this predicate. - /// This is roughly measured in the number of run-time checks required. + /// Returns the estimated complexity of this predicate. This is roughly + /// measured in the number of run-time checks required. virtual unsigned getComplexity() const { return 1; } - /// \brief Returns true if the predicate is always true. This means that no + /// Returns true if the predicate is always true. This means that no /// assumptions were made and nothing needs to be checked at run-time. virtual bool isAlwaysTrue() const = 0; - /// \brief Returns true if this predicate implies \p N. + /// Returns true if this predicate implies \p N. virtual bool implies(const SCEVPredicate *N) const = 0; - /// \brief Prints a textual representation of this predicate with an - /// indentation of \p Depth. + /// Prints a textual representation of this predicate with an indentation of + /// \p Depth. virtual void print(raw_ostream &OS, unsigned Depth = 0) const = 0; - /// \brief Returns the SCEV to which this predicate applies, or nullptr - /// if this is a SCEVUnionPredicate. + /// Returns the SCEV to which this predicate applies, or nullptr if this is + /// a SCEVUnionPredicate. virtual const SCEV *getExpr() const = 0; }; @@ -236,10 +237,9 @@ namespace llvm { } }; - /// SCEVEqualPredicate - This class represents an assumption that two SCEV - /// expressions are equal, and this can be checked at run-time. We assume - /// that the left hand side is a SCEVUnknown and the right hand side a - /// constant. + /// This class represents an assumption that two SCEV expressions are equal, + /// and this can be checked at run-time. We assume that the left hand side is + /// a SCEVUnknown and the right hand side a constant. class SCEVEqualPredicate final : public SCEVPredicate { /// We assume that LHS == RHS, where LHS is a SCEVUnknown and RHS a /// constant. @@ -256,10 +256,10 @@ namespace llvm { bool isAlwaysTrue() const override; const SCEV *getExpr() const override; - /// \brief Returns the left hand side of the equality. + /// Returns the left hand side of the equality. const SCEVUnknown *getLHS() const { return LHS; } - /// \brief Returns the right hand side of the equality. + /// Returns the right hand side of the equality. const SCEVConstant *getRHS() const { return RHS; } /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -268,9 +268,107 @@ namespace llvm { } }; - /// SCEVUnionPredicate - This class represents a composition of other - /// SCEV predicates, and is the class that most clients will interact with. - /// This is equivalent to a logical "AND" of all the predicates in the union. + /// This class represents an assumption made on an AddRec expression. Given an + /// affine AddRec expression {a,+,b}, we assume that it has the nssw or nusw + /// flags (defined below) in the first X iterations of the loop, where X is a + /// SCEV expression returned by getPredicatedBackedgeTakenCount). + /// + /// Note that this does not imply that X is equal to the backedge taken + /// count. This means that if we have a nusw predicate for i32 {0,+,1} with a + /// predicated backedge taken count of X, we only guarantee that {0,+,1} has + /// nusw in the first X iterations. {0,+,1} may still wrap in the loop if we + /// have more than X iterations. + class SCEVWrapPredicate final : public SCEVPredicate { + public: + /// Similar to SCEV::NoWrapFlags, but with slightly different semantics + /// for FlagNUSW. The increment is considered to be signed, and a + b + /// (where b is the increment) is considered to wrap if: + /// zext(a + b) != zext(a) + sext(b) + /// + /// If Signed is a function that takes an n-bit tuple and maps to the + /// integer domain as the tuples value interpreted as twos complement, + /// and Unsigned a function that takes an n-bit tuple and maps to the + /// integer domain as as the base two value of input tuple, then a + b + /// has IncrementNUSW iff: + /// + /// 0 <= Unsigned(a) + Signed(b) < 2^n + /// + /// The IncrementNSSW flag has identical semantics with SCEV::FlagNSW. + /// + /// Note that the IncrementNUSW flag is not commutative: if base + inc + /// has IncrementNUSW, then inc + base doesn't neccessarily have this + /// property. The reason for this is that this is used for sign/zero + /// extending affine AddRec SCEV expressions when a SCEVWrapPredicate is + /// assumed. A {base,+,inc} expression is already non-commutative with + /// regards to base and inc, since it is interpreted as: + /// (((base + inc) + inc) + inc) ... + enum IncrementWrapFlags { + IncrementAnyWrap = 0, // No guarantee. + IncrementNUSW = (1 << 0), // No unsigned with signed increment wrap. + IncrementNSSW = (1 << 1), // No signed with signed increment wrap + // (equivalent with SCEV::NSW) + IncrementNoWrapMask = (1 << 2) - 1 + }; + + /// Convenient IncrementWrapFlags manipulation methods. + static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT + clearFlags(SCEVWrapPredicate::IncrementWrapFlags Flags, + SCEVWrapPredicate::IncrementWrapFlags OffFlags) { + assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!"); + assert((OffFlags & IncrementNoWrapMask) == OffFlags && + "Invalid flags value!"); + return (SCEVWrapPredicate::IncrementWrapFlags)(Flags & ~OffFlags); + } + + static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT + maskFlags(SCEVWrapPredicate::IncrementWrapFlags Flags, int Mask) { + assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!"); + assert((Mask & IncrementNoWrapMask) == Mask && "Invalid mask value!"); + + return (SCEVWrapPredicate::IncrementWrapFlags)(Flags & Mask); + } + + static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT + setFlags(SCEVWrapPredicate::IncrementWrapFlags Flags, + SCEVWrapPredicate::IncrementWrapFlags OnFlags) { + assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!"); + assert((OnFlags & IncrementNoWrapMask) == OnFlags && + "Invalid flags value!"); + + return (SCEVWrapPredicate::IncrementWrapFlags)(Flags | OnFlags); + } + + /// Returns the set of SCEVWrapPredicate no wrap flags implied by a + /// SCEVAddRecExpr. + static SCEVWrapPredicate::IncrementWrapFlags + getImpliedFlags(const SCEVAddRecExpr *AR, ScalarEvolution &SE); + + private: + const SCEVAddRecExpr *AR; + IncrementWrapFlags Flags; + + public: + explicit SCEVWrapPredicate(const FoldingSetNodeIDRef ID, + const SCEVAddRecExpr *AR, + IncrementWrapFlags Flags); + + /// Returns the set assumed no overflow flags. + IncrementWrapFlags getFlags() const { return Flags; } + /// Implementation of the SCEVPredicate interface + const SCEV *getExpr() const override; + bool implies(const SCEVPredicate *N) const override; + void print(raw_ostream &OS, unsigned Depth = 0) const override; + bool isAlwaysTrue() const override; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const SCEVPredicate *P) { + return P->getKind() == P_Wrap; + } + }; + + /// This class represents a composition of other SCEV predicates, and is the + /// class that most clients will interact with. This is equivalent to a + /// logical "AND" of all the predicates in the union. class SCEVUnionPredicate final : public SCEVPredicate { private: typedef DenseMap<const SCEV *, SmallVector<const SCEVPredicate *, 4>> @@ -288,11 +386,11 @@ namespace llvm { return Preds; } - /// \brief Adds a predicate to this union. + /// Adds a predicate to this union. void add(const SCEVPredicate *N); - /// \brief Returns a reference to a vector containing all predicates - /// which apply to \p Expr. + /// Returns a reference to a vector containing all predicates which apply to + /// \p Expr. ArrayRef<const SCEVPredicate *> getPredicatesForExpr(const SCEV *Expr); /// Implementation of the SCEVPredicate interface @@ -301,8 +399,8 @@ namespace llvm { void print(raw_ostream &OS, unsigned Depth) const override; const SCEV *getExpr() const override; - /// \brief We estimate the complexity of a union predicate as the size - /// number of predicates in the union. + /// We estimate the complexity of a union predicate as the size number of + /// predicates in the union. unsigned getComplexity() const override { return Preds.size(); } /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -364,6 +462,12 @@ namespace llvm { /// Function &F; + /// Does the module have any calls to the llvm.experimental.guard intrinsic + /// at all? If this is false, we avoid doing work that will only help if + /// thare are guards present in the IR. + /// + bool HasGuards; + /// The target library information for the target we are targeting. /// TargetLibraryInfo &TLI; @@ -382,6 +486,21 @@ namespace llvm { /// This SCEV is used to represent unknown trip counts and things. std::unique_ptr<SCEVCouldNotCompute> CouldNotCompute; + /// The typedef for HasRecMap. + /// + typedef DenseMap<const SCEV *, bool> HasRecMapType; + + /// This is a cache to record whether a SCEV contains any scAddRecExpr. + HasRecMapType HasRecMap; + + /// The typedef for ExprValueMap. + /// + typedef DenseMap<const SCEV *, SetVector<Value *>> ExprValueMapType; + + /// ExprValueMap -- This map records the original values from which + /// the SCEV expr is generated from. + ExprValueMapType ExprValueMap; + /// The typedef for ValueExprMap. /// typedef DenseMap<SCEVCallbackVH, const SCEV *, DenseMapInfo<Value *> > @@ -410,9 +529,14 @@ namespace llvm { const SCEV *Exact; const SCEV *Max; + /// A predicate union guard for this ExitLimit. The result is only + /// valid if this predicate evaluates to 'true' at run-time. + SCEVUnionPredicate Pred; + /*implicit*/ ExitLimit(const SCEV *E) : Exact(E), Max(E) {} - ExitLimit(const SCEV *E, const SCEV *M) : Exact(E), Max(M) { + ExitLimit(const SCEV *E, const SCEV *M, SCEVUnionPredicate &P) + : Exact(E), Max(M), Pred(P) { assert((isa<SCEVCouldNotCompute>(Exact) || !isa<SCEVCouldNotCompute>(Max)) && "Exact is not allowed to be less precise than Max"); @@ -424,30 +548,147 @@ namespace llvm { return !isa<SCEVCouldNotCompute>(Exact) || !isa<SCEVCouldNotCompute>(Max); } + + /// Test whether this ExitLimit contains all information. + bool hasFullInfo() const { return !isa<SCEVCouldNotCompute>(Exact); } }; + /// Forward declaration of ExitNotTakenExtras + struct ExitNotTakenExtras; + /// Information about the number of times a particular loop exit may be /// reached before exiting the loop. struct ExitNotTakenInfo { AssertingVH<BasicBlock> ExitingBlock; const SCEV *ExactNotTaken; - PointerIntPair<ExitNotTakenInfo*, 1> NextExit; - ExitNotTakenInfo() : ExitingBlock(nullptr), ExactNotTaken(nullptr) {} + ExitNotTakenExtras *ExtraInfo; + bool Complete; + + ExitNotTakenInfo() + : ExitingBlock(nullptr), ExactNotTaken(nullptr), ExtraInfo(nullptr), + Complete(true) {} + + ExitNotTakenInfo(BasicBlock *ExitBlock, const SCEV *Expr, + ExitNotTakenExtras *Ptr) + : ExitingBlock(ExitBlock), ExactNotTaken(Expr), ExtraInfo(Ptr), + Complete(true) {} /// Return true if all loop exits are computable. - bool isCompleteList() const { - return NextExit.getInt() == 0; + bool isCompleteList() const { return Complete; } + + /// Sets the incomplete property, indicating that one of the loop exits + /// doesn't have a corresponding ExitNotTakenInfo entry. + void setIncomplete() { Complete = false; } + + /// Returns a pointer to the predicate associated with this information, + /// or nullptr if this doesn't exist (meaning always true). + SCEVUnionPredicate *getPred() const { + if (ExtraInfo) + return &ExtraInfo->Pred; + + return nullptr; } - void setIncomplete() { NextExit.setInt(1); } + /// Return true if the SCEV predicate associated with this information + /// is always true. + bool hasAlwaysTruePred() const { + return !getPred() || getPred()->isAlwaysTrue(); + } - /// Return a pointer to the next exit's not-taken info. - ExitNotTakenInfo *getNextExit() const { - return NextExit.getPointer(); + /// Defines a simple forward iterator for ExitNotTakenInfo. + class ExitNotTakenInfoIterator + : public std::iterator<std::forward_iterator_tag, ExitNotTakenInfo> { + const ExitNotTakenInfo *Start; + unsigned Position; + + public: + ExitNotTakenInfoIterator(const ExitNotTakenInfo *Start, + unsigned Position) + : Start(Start), Position(Position) {} + + const ExitNotTakenInfo &operator*() const { + if (Position == 0) + return *Start; + + return Start->ExtraInfo->Exits[Position - 1]; + } + + const ExitNotTakenInfo *operator->() const { + if (Position == 0) + return Start; + + return &Start->ExtraInfo->Exits[Position - 1]; + } + + bool operator==(const ExitNotTakenInfoIterator &RHS) const { + return Start == RHS.Start && Position == RHS.Position; + } + + bool operator!=(const ExitNotTakenInfoIterator &RHS) const { + return Start != RHS.Start || Position != RHS.Position; + } + + ExitNotTakenInfoIterator &operator++() { // Preincrement + if (!Start) + return *this; + + unsigned Elements = + Start->ExtraInfo ? Start->ExtraInfo->Exits.size() + 1 : 1; + + ++Position; + + // We've run out of elements. + if (Position == Elements) { + Start = nullptr; + Position = 0; + } + + return *this; + } + ExitNotTakenInfoIterator operator++(int) { // Postincrement + ExitNotTakenInfoIterator Tmp = *this; + ++*this; + return Tmp; + } + }; + + /// Iterators + ExitNotTakenInfoIterator begin() const { + return ExitNotTakenInfoIterator(this, 0); + } + ExitNotTakenInfoIterator end() const { + return ExitNotTakenInfoIterator(nullptr, 0); } + }; - void setNextExit(ExitNotTakenInfo *ENT) { NextExit.setPointer(ENT); } + /// Describes the extra information that a ExitNotTakenInfo can have. + struct ExitNotTakenExtras { + /// The predicate associated with the ExitNotTakenInfo struct. + SCEVUnionPredicate Pred; + + /// The extra exits in the loop. Only the ExitNotTakenExtras structure + /// pointed to by the first ExitNotTakenInfo struct (associated with the + /// first loop exit) will populate this vector to prevent having + /// redundant information. + SmallVector<ExitNotTakenInfo, 4> Exits; + }; + + /// A struct containing the information attached to a backedge. + struct EdgeInfo { + EdgeInfo(BasicBlock *Block, const SCEV *Taken, SCEVUnionPredicate &P) : + ExitBlock(Block), Taken(Taken), Pred(std::move(P)) {} + + /// The exit basic block. + BasicBlock *ExitBlock; + + /// The (exact) number of time we take the edge back. + const SCEV *Taken; + + /// The SCEV predicated associated with Taken. If Pred doesn't evaluate + /// to true, the information in Taken is not valid (or equivalent with + /// a CouldNotCompute. + SCEVUnionPredicate Pred; }; /// Information about the backedge-taken count of a loop. This currently @@ -459,16 +700,16 @@ namespace llvm { ExitNotTakenInfo ExitNotTaken; /// An expression indicating the least maximum backedge-taken count of the - /// loop that is known, or a SCEVCouldNotCompute. + /// loop that is known, or a SCEVCouldNotCompute. This expression is only + /// valid if the predicates associated with all loop exits are true. const SCEV *Max; public: BackedgeTakenInfo() : Max(nullptr) {} /// Initialize BackedgeTakenInfo from a list of exact exit counts. - BackedgeTakenInfo( - SmallVectorImpl< std::pair<BasicBlock *, const SCEV *> > &ExitCounts, - bool Complete, const SCEV *MaxCount); + BackedgeTakenInfo(SmallVectorImpl<EdgeInfo> &ExitCounts, bool Complete, + const SCEV *MaxCount); /// Test whether this BackedgeTakenInfo contains any computed information, /// or whether it's all SCEVCouldNotCompute values. @@ -476,11 +717,27 @@ namespace llvm { return ExitNotTaken.ExitingBlock || !isa<SCEVCouldNotCompute>(Max); } + /// Test whether this BackedgeTakenInfo contains complete information. + bool hasFullInfo() const { return ExitNotTaken.isCompleteList(); } + /// Return an expression indicating the exact backedge-taken count of the - /// loop if it is known, or SCEVCouldNotCompute otherwise. This is the + /// loop if it is known or SCEVCouldNotCompute otherwise. This is the /// number of times the loop header can be guaranteed to execute, minus /// one. - const SCEV *getExact(ScalarEvolution *SE) const; + /// + /// If the SCEV predicate associated with the answer can be different + /// from AlwaysTrue, we must add a (non null) Predicates argument. + /// The SCEV predicate associated with the answer will be added to + /// Predicates. A run-time check needs to be emitted for the SCEV + /// predicate in order for the answer to be valid. + /// + /// Note that we should always know if we need to pass a predicate + /// argument or not from the way the ExitCounts vector was computed. + /// If we allowed SCEV predicates to be generated when populating this + /// vector, this information can contain them and therefore a + /// SCEVPredicate argument should be added to getExact. + const SCEV *getExact(ScalarEvolution *SE, + SCEVUnionPredicate *Predicates = nullptr) const; /// Return the number of times this loop exit may fall through to the back /// edge, or SCEVCouldNotCompute. The loop is guaranteed not to exit via @@ -501,7 +758,11 @@ namespace llvm { /// Cache the backedge-taken count of the loops for this function as they /// are computed. - DenseMap<const Loop*, BackedgeTakenInfo> BackedgeTakenCounts; + DenseMap<const Loop *, BackedgeTakenInfo> BackedgeTakenCounts; + + /// Cache the predicated backedge-taken count of the loops for this + /// function as they are computed. + DenseMap<const Loop *, BackedgeTakenInfo> PredicatedBackedgeTakenCounts; /// This map contains entries for all of the PHI instructions that we /// attempt to compute constant evolutions for. This allows us to avoid @@ -520,6 +781,16 @@ namespace llvm { SmallVector<PointerIntPair<const Loop *, 2, LoopDisposition>, 2>> LoopDispositions; + /// Cache for \c loopHasNoAbnormalExits. + DenseMap<const Loop *, bool> LoopHasNoAbnormalExits; + + /// Returns true if \p L contains no instruction that can abnormally exit + /// the loop (i.e. via throwing an exception, by terminating the thread + /// cleanly or by infinite looping in a called function). Strictly + /// speaking, the last one is not leaving the loop, but is identical to + /// leaving the loop for reasoning about undefined behavior. + bool loopHasNoAbnormalExits(const Loop *L); + /// Compute a LoopDisposition value. LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L); @@ -547,8 +818,7 @@ namespace llvm { DenseMap<const SCEV *, ConstantRange> &Cache = Hint == HINT_RANGE_UNSIGNED ? UnsignedRanges : SignedRanges; - std::pair<DenseMap<const SCEV *, ConstantRange>::iterator, bool> Pair = - Cache.insert(std::make_pair(S, CR)); + auto Pair = Cache.insert({S, CR}); if (!Pair.second) Pair.first->second = CR; return Pair.first->second; @@ -557,6 +827,19 @@ namespace llvm { /// Determine the range for a particular SCEV. ConstantRange getRange(const SCEV *S, RangeSignHint Hint); + /// Determines the range for the affine SCEVAddRecExpr {\p Start,+,\p Stop}. + /// Helper for \c getRange. + ConstantRange getRangeForAffineAR(const SCEV *Start, const SCEV *Stop, + const SCEV *MaxBECount, + unsigned BitWidth); + + /// Try to compute a range for the affine SCEVAddRecExpr {\p Start,+,\p + /// Stop} by "factoring out" a ternary expression from the add recurrence. + /// Helper called by \c getRange. + ConstantRange getRangeViaFactoring(const SCEV *Start, const SCEV *Stop, + const SCEV *MaxBECount, + unsigned BitWidth); + /// We know that there is no SCEV for the specified value. Analyze the /// expression. const SCEV *createSCEV(Value *V); @@ -588,36 +871,59 @@ namespace llvm { /// This looks up computed SCEV values for all instructions that depend on /// the given instruction and removes them from the ValueExprMap map if they /// reference SymName. This is used during PHI resolution. - void ForgetSymbolicName(Instruction *I, const SCEV *SymName); + void forgetSymbolicName(Instruction *I, const SCEV *SymName); /// Return the BackedgeTakenInfo for the given loop, lazily computing new - /// values if the loop hasn't been analyzed yet. + /// values if the loop hasn't been analyzed yet. The returned result is + /// guaranteed not to be predicated. const BackedgeTakenInfo &getBackedgeTakenInfo(const Loop *L); + /// Similar to getBackedgeTakenInfo, but will add predicates as required + /// with the purpose of returning complete information. + const BackedgeTakenInfo &getPredicatedBackedgeTakenInfo(const Loop *L); + /// Compute the number of times the specified loop will iterate. - BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L); + /// If AllowPredicates is set, we will create new SCEV predicates as + /// necessary in order to return an exact answer. + BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will - /// execute if it exits via the specified block. - ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock); + /// execute if it exits via the specified block. If AllowPredicates is set, + /// this call will try to use a minimal set of SCEV predicates in order to + /// return an exact answer. + ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a conditional branch of ExitCond, /// TBB, and FBB. + /// + /// \p ControlsExit is true if ExitCond directly controls the exit + /// branch. In this case, we can assume that the loop exits only if the + /// condition is true and can infer that failing to meet the condition prior + /// to integer wraparound results in undefined behavior. + /// + /// If \p AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. ExitLimit computeExitLimitFromCond(const Loop *L, Value *ExitCond, BasicBlock *TBB, BasicBlock *FBB, - bool IsSubExpr); + bool ControlsExit, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a conditional branch of the ICmpInst - /// ExitCond, TBB, and FBB. + /// ExitCond, TBB, and FBB. If AllowPredicates is set, this call will try + /// to use a minimal set of SCEV predicates in order to return an exact + /// answer. ExitLimit computeExitLimitFromICmp(const Loop *L, ICmpInst *ExitCond, BasicBlock *TBB, BasicBlock *FBB, - bool IsSubExpr); + bool IsSubExpr, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a switch with a single exiting case @@ -655,20 +961,35 @@ namespace llvm { /// Return the number of times an exit condition comparing the specified /// value to zero will execute. If not computable, return CouldNotCompute. - ExitLimit HowFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr); + /// If AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. + ExitLimit howFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr, + bool AllowPredicates = false); /// Return the number of times an exit condition checking the specified /// value for nonzero will execute. If not computable, return /// CouldNotCompute. - ExitLimit HowFarToNonZero(const SCEV *V, const Loop *L); + ExitLimit howFarToNonZero(const SCEV *V, const Loop *L); /// Return the number of times an exit condition containing the specified /// less-than comparison will execute. If not computable, return - /// CouldNotCompute. isSigned specifies whether the less-than is signed. - ExitLimit HowManyLessThans(const SCEV *LHS, const SCEV *RHS, - const Loop *L, bool isSigned, bool IsSubExpr); - ExitLimit HowManyGreaterThans(const SCEV *LHS, const SCEV *RHS, - const Loop *L, bool isSigned, bool IsSubExpr); + /// CouldNotCompute. + /// + /// \p isSigned specifies whether the less-than is signed. + /// + /// \p ControlsExit is true when the LHS < RHS condition directly controls + /// the branch (loops exits only if condition is true). In this case, we can + /// use NoWrapFlags to skip overflow checks. + /// + /// If \p AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. + ExitLimit howManyLessThans(const SCEV *LHS, const SCEV *RHS, const Loop *L, + bool isSigned, bool ControlsExit, + bool AllowPredicates = false); + + ExitLimit howManyGreaterThans(const SCEV *LHS, const SCEV *RHS, + const Loop *L, bool isSigned, bool IsSubExpr, + bool AllowPredicates = false); /// Return a predecessor of BB (which may not be an immediate predecessor) /// which has exactly one successor from which BB is reachable, or null if @@ -707,12 +1028,18 @@ namespace llvm { /// Test whether the condition described by Pred, LHS, and RHS is true /// whenever the condition described by Pred, FoundLHS, and FoundRHS is - /// true. Utility function used by isImpliedCondOperands. + /// true. Utility function used by isImpliedCondOperands. Tries to get + /// cases like "X `sgt` 0 => X - 1 `sgt` -1". bool isImpliedCondOperandsViaRanges(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, const SCEV *FoundLHS, const SCEV *FoundRHS); + /// Return true if the condition denoted by \p LHS \p Pred \p RHS is implied + /// by a call to \c @llvm.experimental.guard in \p BB. + bool isImpliedViaGuard(BasicBlock *BB, ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS); + /// Test whether the condition described by Pred, LHS, and RHS is true /// whenever the condition described by Pred, FoundLHS, and FoundRHS is /// true. @@ -733,8 +1060,8 @@ namespace llvm { /// Test if the given expression is known to satisfy the condition described /// by Pred and the known constant ranges of LHS and RHS. /// - bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred, - const SCEV *LHS, const SCEV *RHS); + bool isKnownPredicateViaConstantRanges(ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS); /// Try to prove the condition described by "LHS Pred RHS" by ruling out /// integer overflow. @@ -778,6 +1105,9 @@ namespace llvm { bool proveNoWrapByVaryingStart(const SCEV *Start, const SCEV *Step, const Loop *L); + /// Try to prove NSW or NUW on \p AR relying on ConstantRange manipulation. + SCEV::NoWrapFlags proveNoWrapViaConstantRanges(const SCEVAddRecExpr *AR); + bool isMonotonicPredicateImpl(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred, bool &Increasing); @@ -793,11 +1123,35 @@ namespace llvm { bool isMonotonicPredicate(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred, bool &Increasing); - // Return SCEV no-wrap flags that can be proven based on reasoning - // about how poison produced from no-wrap flags on this value - // (e.g. a nuw add) would trigger undefined behavior on overflow. + /// Return SCEV no-wrap flags that can be proven based on reasoning about + /// how poison produced from no-wrap flags on this value (e.g. a nuw add) + /// would trigger undefined behavior on overflow. SCEV::NoWrapFlags getNoWrapFlagsFromUB(const Value *V); + /// Return true if the SCEV corresponding to \p I is never poison. Proving + /// this is more complex than proving that just \p I is never poison, since + /// SCEV commons expressions across control flow, and you can have cases + /// like: + /// + /// idx0 = a + b; + /// ptr[idx0] = 100; + /// if (<condition>) { + /// idx1 = a +nsw b; + /// ptr[idx1] = 200; + /// } + /// + /// where the SCEV expression (+ a b) is guaranteed to not be poison (and + /// hence not sign-overflow) only if "<condition>" is true. Since both + /// `idx0` and `idx1` will be mapped to the same SCEV expression, (+ a b), + /// it is not okay to annotate (+ a b) with <nsw> in the above example. + bool isSCEVExprNeverPoison(const Instruction *I); + + /// This is like \c isSCEVExprNeverPoison but it specifically works for + /// instructions that will get mapped to SCEV add recurrences. Return true + /// if \p I will never generate poison under the assumption that \p I is an + /// add recurrence on the loop \p L. + bool isAddRecNeverPoison(const Instruction *I, const Loop *L); + public: ScalarEvolution(Function &F, TargetLibraryInfo &TLI, AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI); @@ -821,6 +1175,17 @@ namespace llvm { /// return true. For pointer types, this is the pointer-sized integer type. Type *getEffectiveSCEVType(Type *Ty) const; + /// Return true if the SCEV is a scAddRecExpr or it contains + /// scAddRecExpr. The result will be cached in HasRecMap. + /// + bool containsAddRecurrence(const SCEV *S); + + /// Return the Value set from which the SCEV expr is generated. + SetVector<Value *> *getSCEVValues(const SCEV *S); + + /// Erase Value from ValueExprMap and ExprValueMap. + void eraseValueFromMap(Value *V); + /// Return a SCEV expression for the full generality of the specified /// expression. const SCEV *getSCEV(Value *V); @@ -867,7 +1232,7 @@ namespace llvm { SmallVector<const SCEV *, 4> NewOp(Operands.begin(), Operands.end()); return getAddRecExpr(NewOp, L, Flags); } - /// \brief Returns an expression for a GEP + /// Returns an expression for a GEP /// /// \p PointeeType The type used as the basis for the pointer arithmetics /// \p BaseExpr The expression for the pointer operand. @@ -885,10 +1250,10 @@ namespace llvm { const SCEV *getUnknown(Value *V); const SCEV *getCouldNotCompute(); - /// \brief Return a SCEV for the constant 0 of a specific type. + /// Return a SCEV for the constant 0 of a specific type. const SCEV *getZero(Type *Ty) { return getConstant(Ty, 0); } - /// \brief Return a SCEV for the constant 1 of a specific type. + /// Return a SCEV for the constant 1 of a specific type. const SCEV *getOne(Type *Ty) { return getConstant(Ty, 1); } /// Return an expression for sizeof AllocTy that is type IntTy @@ -981,7 +1346,7 @@ namespace llvm { bool isLoopBackedgeGuardedByCond(const Loop *L, ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS); - /// \brief Returns the maximum trip count of the loop if it is a single-exit + /// Returns the maximum trip count of the loop if it is a single-exit /// loop and we can compute a small maximum for that loop. /// /// Implemented in terms of the \c getSmallConstantTripCount overload with @@ -997,7 +1362,7 @@ namespace llvm { /// prematurely via another branch. unsigned getSmallConstantTripCount(Loop *L, BasicBlock *ExitingBlock); - /// \brief Returns the largest constant divisor of the trip count of the + /// Returns the largest constant divisor of the trip count of the /// loop if it is a single-exit loop and we can compute a small maximum for /// that loop. /// @@ -1031,6 +1396,13 @@ namespace llvm { /// const SCEV *getBackedgeTakenCount(const Loop *L); + /// Similar to getBackedgeTakenCount, except it will add a set of + /// SCEV predicates to Predicates that are required to be true in order for + /// the answer to be correct. Predicates can be checked with run-time + /// checks and can be used to perform loop versioning. + const SCEV *getPredicatedBackedgeTakenCount(const Loop *L, + SCEVUnionPredicate &Predicates); + /// Similar to getBackedgeTakenCount, except return the least SCEV value /// that is known never to be less than the actual backedge taken count. const SCEV *getMaxBackedgeTakenCount(const Loop *L); @@ -1050,7 +1422,7 @@ namespace llvm { /// def-use chain linking it to a loop. void forgetValue(Value *V); - /// \brief Called when the client has changed the disposition of values in + /// Called when the client has changed the disposition of values in /// this loop. /// /// We don't have a way to invalidate per-loop dispositions. Clear and @@ -1154,7 +1526,8 @@ namespace llvm { const SCEV *getElementSize(Instruction *Inst); /// Compute the array dimensions Sizes from the set of Terms extracted from - /// the memory access function of this SCEVAddRecExpr. + /// the memory access function of this SCEVAddRecExpr (second step of + /// delinearization). void findArrayDimensions(SmallVectorImpl<const SCEV *> &Terms, SmallVectorImpl<const SCEV *> &Sizes, const SCEV *ElementSize) const; @@ -1162,13 +1535,15 @@ namespace llvm { void print(raw_ostream &OS) const; void verify() const; - /// Collect parametric terms occurring in step expressions. + /// Collect parametric terms occurring in step expressions (first step of + /// delinearization). void collectParametricTerms(const SCEV *Expr, SmallVectorImpl<const SCEV *> &Terms); - /// Return in Subscripts the access functions for each dimension in Sizes. + /// Return in Subscripts the access functions for each dimension in Sizes + /// (third step of delinearization). void computeAccessFunctions(const SCEV *Expr, SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<const SCEV *> &Sizes); @@ -1251,8 +1626,18 @@ namespace llvm { const SCEVPredicate *getEqualPredicate(const SCEVUnknown *LHS, const SCEVConstant *RHS); - /// Re-writes the SCEV according to the Predicates in \p Preds. - const SCEV *rewriteUsingPredicate(const SCEV *Scev, SCEVUnionPredicate &A); + const SCEVPredicate * + getWrapPredicate(const SCEVAddRecExpr *AR, + SCEVWrapPredicate::IncrementWrapFlags AddedFlags); + + /// Re-writes the SCEV according to the Predicates in \p A. + const SCEV *rewriteUsingPredicate(const SCEV *S, const Loop *L, + SCEVUnionPredicate &A); + /// Tries to convert the \p S expression to an AddRec expression, + /// adding additional predicates to \p Preds as required. + const SCEVAddRecExpr * + convertSCEVToAddRecWithPredicates(const SCEV *S, const Loop *L, + SCEVUnionPredicate &Preds); private: /// Compute the backedge taken count knowing the interval difference, the @@ -1283,31 +1668,26 @@ namespace llvm { SCEVUnknown *FirstUnknown; }; - /// \brief Analysis pass that exposes the \c ScalarEvolution for a function. - class ScalarEvolutionAnalysis { + /// Analysis pass that exposes the \c ScalarEvolution for a function. + class ScalarEvolutionAnalysis + : public AnalysisInfoMixin<ScalarEvolutionAnalysis> { + friend AnalysisInfoMixin<ScalarEvolutionAnalysis>; static char PassID; public: typedef ScalarEvolution Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - /// \brief Provide a name for the analysis for debugging and logging. - static StringRef name() { return "ScalarEvolutionAnalysis"; } - - ScalarEvolution run(Function &F, AnalysisManager<Function> *AM); + ScalarEvolution run(Function &F, AnalysisManager<Function> &AM); }; - /// \brief Printer pass for the \c ScalarEvolutionAnalysis results. - class ScalarEvolutionPrinterPass { + /// Printer pass for the \c ScalarEvolutionAnalysis results. + class ScalarEvolutionPrinterPass + : public PassInfoMixin<ScalarEvolutionPrinterPass> { raw_ostream &OS; public: explicit ScalarEvolutionPrinterPass(raw_ostream &OS) : OS(OS) {} - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); - - static StringRef name() { return "ScalarEvolutionPrinterPass"; } + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; class ScalarEvolutionWrapperPass : public FunctionPass { @@ -1343,42 +1723,81 @@ namespace llvm { /// - lowers the number of expression rewrites. class PredicatedScalarEvolution { public: - PredicatedScalarEvolution(ScalarEvolution &SE); + PredicatedScalarEvolution(ScalarEvolution &SE, Loop &L); const SCEVUnionPredicate &getUnionPredicate() const; - /// \brief Returns the SCEV expression of V, in the context of the current - /// SCEV predicate. - /// The order of transformations applied on the expression of V returned - /// by ScalarEvolution is guaranteed to be preserved, even when adding new - /// predicates. + + /// Returns the SCEV expression of V, in the context of the current SCEV + /// predicate. The order of transformations applied on the expression of V + /// returned by ScalarEvolution is guaranteed to be preserved, even when + /// adding new predicates. const SCEV *getSCEV(Value *V); - /// \brief Adds a new predicate. + + /// Get the (predicated) backedge count for the analyzed loop. + const SCEV *getBackedgeTakenCount(); + + /// Adds a new predicate. void addPredicate(const SCEVPredicate &Pred); - /// \brief Returns the ScalarEvolution analysis used. + + /// Attempts to produce an AddRecExpr for V by adding additional SCEV + /// predicates. If we can't transform the expression into an AddRecExpr we + /// return nullptr and not add additional SCEV predicates to the current + /// context. + const SCEVAddRecExpr *getAsAddRec(Value *V); + + /// Proves that V doesn't overflow by adding SCEV predicate. + void setNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags); + + /// Returns true if we've proved that V doesn't wrap by means of a SCEV + /// predicate. + bool hasNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags); + + /// Returns the ScalarEvolution analysis used. ScalarEvolution *getSE() const { return &SE; } + /// We need to explicitly define the copy constructor because of FlagsMap. + PredicatedScalarEvolution(const PredicatedScalarEvolution&); + + /// Print the SCEV mappings done by the Predicated Scalar Evolution. + /// The printed text is indented by \p Depth. + void print(raw_ostream &OS, unsigned Depth) const; + private: - /// \brief Increments the version number of the predicate. - /// This needs to be called every time the SCEV predicate changes. + /// Increments the version number of the predicate. This needs to be called + /// every time the SCEV predicate changes. void updateGeneration(); + /// Holds a SCEV and the version number of the SCEV predicate used to /// perform the rewrite of the expression. typedef std::pair<unsigned, const SCEV *> RewriteEntry; + /// Maps a SCEV to the rewrite result of that SCEV at a certain version /// number. If this number doesn't match the current Generation, we will /// need to do a rewrite. To preserve the transformation order of previous /// rewrites, we will rewrite the previous result instead of the original /// SCEV. DenseMap<const SCEV *, RewriteEntry> RewriteMap; + + /// Records what NoWrap flags we've added to a Value *. + ValueMap<Value *, SCEVWrapPredicate::IncrementWrapFlags> FlagsMap; + /// The ScalarEvolution analysis. ScalarEvolution &SE; + + /// The analyzed Loop. + const Loop &L; + /// The SCEVPredicate that forms our context. We will rewrite all /// expressions assuming that this predicate true. SCEVUnionPredicate Preds; + /// Marks the version of the SCEV predicate used. When rewriting a SCEV /// expression we mark it with the version of the predicate. We use this to /// figure out if the predicate has changed from the last rewrite of the /// SCEV. If so, we need to perform a new rewrite. unsigned Generation; + + /// The backedge taken count. + const SCEV *BackedgeCount; }; } diff --git a/include/llvm/Analysis/ScalarEvolutionAliasAnalysis.h b/include/llvm/Analysis/ScalarEvolutionAliasAnalysis.h index 7bbbf5562047..ac10370b4131 100644 --- a/include/llvm/Analysis/ScalarEvolutionAliasAnalysis.h +++ b/include/llvm/Analysis/ScalarEvolutionAliasAnalysis.h @@ -28,8 +28,7 @@ class SCEVAAResult : public AAResultBase<SCEVAAResult> { ScalarEvolution &SE; public: - explicit SCEVAAResult(const TargetLibraryInfo &TLI, ScalarEvolution &SE) - : AAResultBase(TLI), SE(SE) {} + explicit SCEVAAResult(ScalarEvolution &SE) : AAResultBase(), SE(SE) {} SCEVAAResult(SCEVAAResult &&Arg) : AAResultBase(std::move(Arg)), SE(Arg.SE) {} AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB); @@ -39,20 +38,14 @@ private: }; /// Analysis pass providing a never-invalidated alias analysis result. -class SCEVAA { +class SCEVAA : public AnalysisInfoMixin<SCEVAA> { + friend AnalysisInfoMixin<SCEVAA>; + static char PassID; + public: typedef SCEVAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - SCEVAAResult run(Function &F, AnalysisManager<Function> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "SCEVAA"; } - -private: - static char PassID; + SCEVAAResult run(Function &F, AnalysisManager<Function> &AM); }; /// Legacy wrapper pass to provide the SCEVAAResult object. diff --git a/include/llvm/Analysis/ScalarEvolutionExpander.h b/include/llvm/Analysis/ScalarEvolutionExpander.h index b9939168a99d..2fa856a32f7d 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpander.h +++ b/include/llvm/Analysis/ScalarEvolutionExpander.h @@ -80,9 +80,49 @@ namespace llvm { /// already in "expanded" form. bool LSRMode; - typedef IRBuilder<true, TargetFolder> BuilderType; + typedef IRBuilder<TargetFolder> BuilderType; BuilderType Builder; + // RAII object that stores the current insertion point and restores it when + // the object is destroyed. This includes the debug location. Duplicated + // from InsertPointGuard to add SetInsertPoint() which is used to updated + // InsertPointGuards stack when insert points are moved during SCEV + // expansion. + class SCEVInsertPointGuard { + IRBuilderBase &Builder; + AssertingVH<BasicBlock> Block; + BasicBlock::iterator Point; + DebugLoc DbgLoc; + SCEVExpander *SE; + + SCEVInsertPointGuard(const SCEVInsertPointGuard &) = delete; + SCEVInsertPointGuard &operator=(const SCEVInsertPointGuard &) = delete; + + public: + SCEVInsertPointGuard(IRBuilderBase &B, SCEVExpander *SE) + : Builder(B), Block(B.GetInsertBlock()), Point(B.GetInsertPoint()), + DbgLoc(B.getCurrentDebugLocation()), SE(SE) { + SE->InsertPointGuards.push_back(this); + } + + ~SCEVInsertPointGuard() { + // These guards should always created/destroyed in FIFO order since they + // are used to guard lexically scoped blocks of code in + // ScalarEvolutionExpander. + assert(SE->InsertPointGuards.back() == this); + SE->InsertPointGuards.pop_back(); + Builder.restoreIP(IRBuilderBase::InsertPoint(Block, Point)); + Builder.SetCurrentDebugLocation(DbgLoc); + } + + BasicBlock::iterator GetInsertPoint() const { return Point; } + void SetInsertPoint(BasicBlock::iterator I) { Point = I; } + }; + + /// Stack of pointers to saved insert points, used to keep insert points + /// consistent when instructions are moved. + SmallVector<SCEVInsertPointGuard *, 8> InsertPointGuards; + #ifndef NDEBUG const char *DebugType; #endif @@ -101,6 +141,11 @@ namespace llvm { #endif } + ~SCEVExpander() { + // Make sure the insert point guard stack is consistent. + assert(InsertPointGuards.empty()); + } + #ifndef NDEBUG void setDebugType(const char* s) { DebugType = s; } #endif @@ -162,6 +207,15 @@ namespace llvm { Value *expandEqualPredicate(const SCEVEqualPredicate *Pred, Instruction *Loc); + /// \brief Generates code that evaluates if the \p AR expression will + /// overflow. + Value *generateOverflowCheck(const SCEVAddRecExpr *AR, Instruction *Loc, + bool Signed); + + /// \brief A specialized variant of expandCodeForPredicate, handling the + /// case when we are expanding code for a SCEVWrapPredicate. + Value *expandWrapPredicate(const SCEVWrapPredicate *P, Instruction *Loc); + /// \brief A specialized variant of expandCodeForPredicate, handling the /// case when we are expanding code for a SCEVUnionPredicate. Value *expandUnionPredicate(const SCEVUnionPredicate *Pred, @@ -254,6 +308,9 @@ namespace llvm { const SCEV *const *op_end, PointerType *PTy, Type *Ty, Value *V); + /// \brief Find a previous Value in ExprValueMap for expand. + Value *FindValueInExprValueMap(const SCEV *S, const Instruction *InsertPt); + Value *expand(const SCEV *S); /// \brief Insert code to directly compute the specified SCEV expression @@ -306,6 +363,11 @@ namespace llvm { bool &InvertStep); Value *expandIVInc(PHINode *PN, Value *StepV, const Loop *L, Type *ExpandTy, Type *IntTy, bool useSubtract); + + void hoistBeforePos(DominatorTree *DT, Instruction *InstToHoist, + Instruction *Pos, PHINode *LoopPhi); + + void fixupInsertPoints(Instruction *I); }; } diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h index 16992680577c..ff24cafbe680 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h @@ -32,9 +32,7 @@ namespace llvm { scUnknown, scCouldNotCompute }; - //===--------------------------------------------------------------------===// - /// SCEVConstant - This class represents a constant integer value. - /// + /// This class represents a constant integer value. class SCEVConstant : public SCEV { friend class ScalarEvolution; @@ -53,9 +51,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVCastExpr - This is the base class for unary cast operator classes. - /// + /// This is the base class for unary cast operator classes. class SCEVCastExpr : public SCEV { protected: const SCEV *Op; @@ -76,10 +72,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVTruncateExpr - This class represents a truncation of an integer value - /// to a smaller integer value. - /// + /// This class represents a truncation of an integer value to a + /// smaller integer value. class SCEVTruncateExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -93,10 +87,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVZeroExtendExpr - This class represents a zero extension of a small - /// integer value to a larger integer value. - /// + /// This class represents a zero extension of a small integer value + /// to a larger integer value. class SCEVZeroExtendExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -110,10 +102,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVSignExtendExpr - This class represents a sign extension of a small - /// integer value to a larger integer value. - /// + /// This class represents a sign extension of a small integer value + /// to a larger integer value. class SCEVSignExtendExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -128,10 +118,8 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVNAryExpr - This node is a base class providing common - /// functionality for n'ary operators. - /// + /// This node is a base class providing common functionality for + /// n'ary operators. class SCEVNAryExpr : public SCEV { protected: // Since SCEVs are immutable, ScalarEvolution allocates operand @@ -166,6 +154,18 @@ namespace llvm { return (NoWrapFlags)(SubclassData & Mask); } + bool hasNoUnsignedWrap() const { + return getNoWrapFlags(FlagNUW) != FlagAnyWrap; + } + + bool hasNoSignedWrap() const { + return getNoWrapFlags(FlagNSW) != FlagAnyWrap; + } + + bool hasNoSelfWrap() const { + return getNoWrapFlags(FlagNW) != FlagAnyWrap; + } + /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEV *S) { return S->getSCEVType() == scAddExpr || @@ -176,10 +176,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVCommutativeExpr - This node is the base class for n'ary commutative - /// operators. - /// + /// This node is the base class for n'ary commutative operators. class SCEVCommutativeExpr : public SCEVNAryExpr { protected: SCEVCommutativeExpr(const FoldingSetNodeIDRef ID, @@ -202,9 +199,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVAddExpr - This node represents an addition of some number of SCEVs. - /// + /// This node represents an addition of some number of SCEVs. class SCEVAddExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -227,9 +222,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVMulExpr - This node represents multiplication of some number of SCEVs. - /// + + /// This node represents multiplication of some number of SCEVs. class SCEVMulExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -246,9 +240,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVUDivExpr - This class represents a binary unsigned division operation. - /// + /// This class represents a binary unsigned division operation. class SCEVUDivExpr : public SCEV { friend class ScalarEvolution; @@ -277,12 +269,11 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVAddRecExpr - This node represents a polynomial recurrence on the trip - /// count of the specified loop. This is the primary focus of the - /// ScalarEvolution framework; all the other SCEV subclasses are mostly just - /// supporting infrastructure to allow SCEVAddRecExpr expressions to be - /// created and analyzed. + /// This node represents a polynomial recurrence on the trip count + /// of the specified loop. This is the primary focus of the + /// ScalarEvolution framework; all the other SCEV subclasses are + /// mostly just supporting infrastructure to allow SCEVAddRecExpr + /// expressions to be created and analyzed. /// /// All operands of an AddRec are required to be loop invariant. /// @@ -299,10 +290,10 @@ namespace llvm { const SCEV *getStart() const { return Operands[0]; } const Loop *getLoop() const { return L; } - /// getStepRecurrence - This method constructs and returns the recurrence - /// indicating how much this expression steps by. If this is a polynomial - /// of degree N, it returns a chrec of degree N-1. - /// We cannot determine whether the step recurrence has self-wraparound. + /// Constructs and returns the recurrence indicating how much this + /// expression steps by. If this is a polynomial of degree N, it + /// returns a chrec of degree N-1. We cannot determine whether + /// the step recurrence has self-wraparound. const SCEV *getStepRecurrence(ScalarEvolution &SE) const { if (isAffine()) return getOperand(1); return SE.getAddRecExpr(SmallVector<const SCEV *, 3>(op_begin()+1, @@ -310,17 +301,17 @@ namespace llvm { getLoop(), FlagAnyWrap); } - /// isAffine - Return true if this represents an expression - /// A + B*x where A and B are loop invariant values. + /// Return true if this represents an expression A + B*x where A + /// and B are loop invariant values. bool isAffine() const { // We know that the start value is invariant. This expression is thus // affine iff the step is also invariant. return getNumOperands() == 2; } - /// isQuadratic - Return true if this represents an expression - /// A + B*x + C*x^2 where A, B and C are loop invariant values. - /// This corresponds to an addrec of the form {L,+,M,+,N} + /// Return true if this represents an expression A + B*x + C*x^2 + /// where A, B and C are loop invariant values. This corresponds + /// to an addrec of the form {L,+,M,+,N} bool isQuadratic() const { return getNumOperands() == 3; } @@ -334,21 +325,21 @@ namespace llvm { SubclassData |= Flags; } - /// evaluateAtIteration - Return the value of this chain of recurrences at - /// the specified iteration number. + /// Return the value of this chain of recurrences at the specified + /// iteration number. const SCEV *evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const; - /// getNumIterationsInRange - Return the number of iterations of this loop - /// that produce values in the specified constant range. Another way of - /// looking at this is that it returns the first iteration number where the - /// value is not in the condition, thus computing the exit count. If the - /// iteration count can't be computed, an instance of SCEVCouldNotCompute is - /// returned. - const SCEV *getNumIterationsInRange(ConstantRange Range, - ScalarEvolution &SE) const; - - /// getPostIncExpr - Return an expression representing the value of - /// this expression one iteration of the loop ahead. + /// Return the number of iterations of this loop that produce + /// values in the specified constant range. Another way of + /// looking at this is that it returns the first iteration number + /// where the value is not in the condition, thus computing the + /// exit count. If the iteration count can't be computed, an + /// instance of SCEVCouldNotCompute is returned. + const SCEV *getNumIterationsInRange(const ConstantRange &Range, + ScalarEvolution &SE) const; + + /// Return an expression representing the value of this expression + /// one iteration of the loop ahead. const SCEVAddRecExpr *getPostIncExpr(ScalarEvolution &SE) const { return cast<SCEVAddRecExpr>(SE.getAddExpr(this, getStepRecurrence(SE))); } @@ -359,9 +350,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVSMaxExpr - This class represents a signed maximum selection. - /// + /// This class represents a signed maximum selection. class SCEVSMaxExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -380,9 +369,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVUMaxExpr - This class represents an unsigned maximum selection. - /// + /// This class represents an unsigned maximum selection. class SCEVUMaxExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -400,11 +387,9 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVUnknown - This means that we are dealing with an entirely unknown SCEV - /// value, and only represent it as its LLVM Value. This is the "bottom" - /// value for the analysis. - /// + /// This means that we are dealing with an entirely unknown SCEV + /// value, and only represent it as its LLVM Value. This is the + /// "bottom" value for the analysis. class SCEVUnknown final : public SCEV, private CallbackVH { friend class ScalarEvolution; @@ -412,13 +397,13 @@ namespace llvm { void deleted() override; void allUsesReplacedWith(Value *New) override; - /// SE - The parent ScalarEvolution value. This is used to update - /// the parent's maps when the value associated with a SCEVUnknown - /// is deleted or RAUW'd. + /// The parent ScalarEvolution value. This is used to update the + /// parent's maps when the value associated with a SCEVUnknown is + /// deleted or RAUW'd. ScalarEvolution *SE; - /// Next - The next pointer in the linked list of all - /// SCEVUnknown instances owned by a ScalarEvolution. + /// The next pointer in the linked list of all SCEVUnknown + /// instances owned by a ScalarEvolution. SCEVUnknown *Next; SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V, @@ -428,15 +413,17 @@ namespace llvm { public: Value *getValue() const { return getValPtr(); } - /// isSizeOf, isAlignOf, isOffsetOf - Test whether this is a special - /// constant representing a type size, alignment, or field offset in - /// a target-independent manner, and hasn't happened to have been - /// folded with other operations into something unrecognizable. This - /// is mainly only useful for pretty-printing and other situations - /// where it isn't absolutely required for these to succeed. + /// @{ + /// Test whether this is a special constant representing a type + /// size, alignment, or field offset in a target-independent + /// manner, and hasn't happened to have been folded with other + /// operations into something unrecognizable. This is mainly only + /// useful for pretty-printing and other situations where it isn't + /// absolutely required for these to succeed. bool isSizeOf(Type *&AllocTy) const; bool isAlignOf(Type *&AllocTy) const; bool isOffsetOf(Type *&STy, Constant *&FieldNo) const; + /// @} Type *getType() const { return getValPtr()->getType(); } @@ -446,8 +433,8 @@ namespace llvm { } }; - /// SCEVVisitor - This class defines a simple visitor class that may be used - /// for various SCEV analysis purposes. + /// This class defines a simple visitor class that may be used for + /// various SCEV analysis purposes. template<typename SC, typename RetVal=void> struct SCEVVisitor { RetVal visit(const SCEV *S) { @@ -524,14 +511,10 @@ namespace llvm { case scMulExpr: case scSMaxExpr: case scUMaxExpr: - case scAddRecExpr: { - const SCEVNAryExpr *NAry = cast<SCEVNAryExpr>(S); - for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), - E = NAry->op_end(); I != E; ++I) { - push(*I); - } + case scAddRecExpr: + for (const auto *Op : cast<SCEVNAryExpr>(S)->operands()) + push(Op); break; - } case scUDivExpr: { const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(S); push(UDiv->getLHS()); @@ -697,13 +680,6 @@ namespace llvm { private: LoopToScevMapT ⤅ }; - -/// Applies the Map (Loop -> SCEV) to the given Scev. -static inline const SCEV *apply(const SCEV *Scev, LoopToScevMapT &Map, - ScalarEvolution &SE) { - return SCEVLoopAddRecRewriter::rewrite(Scev, Map, SE); -} - } #endif diff --git a/include/llvm/Analysis/ScopedNoAliasAA.h b/include/llvm/Analysis/ScopedNoAliasAA.h index 175561687157..87b85d4e6635 100644 --- a/include/llvm/Analysis/ScopedNoAliasAA.h +++ b/include/llvm/Analysis/ScopedNoAliasAA.h @@ -27,8 +27,7 @@ class ScopedNoAliasAAResult : public AAResultBase<ScopedNoAliasAAResult> { friend AAResultBase<ScopedNoAliasAAResult>; public: - explicit ScopedNoAliasAAResult(const TargetLibraryInfo &TLI) - : AAResultBase(TLI) {} + explicit ScopedNoAliasAAResult() : AAResultBase() {} ScopedNoAliasAAResult(ScopedNoAliasAAResult &&Arg) : AAResultBase(std::move(Arg)) {} @@ -48,20 +47,14 @@ private: }; /// Analysis pass providing a never-invalidated alias analysis result. -class ScopedNoAliasAA { +class ScopedNoAliasAA : public AnalysisInfoMixin<ScopedNoAliasAA> { + friend AnalysisInfoMixin<ScopedNoAliasAA>; + static char PassID; + public: typedef ScopedNoAliasAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - ScopedNoAliasAAResult run(Function &F, AnalysisManager<Function> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "ScopedNoAliasAA"; } - -private: - static char PassID; + ScopedNoAliasAAResult run(Function &F, AnalysisManager<Function> &AM); }; /// Legacy wrapper pass to provide the ScopedNoAliasAAResult object. diff --git a/include/llvm/Analysis/SparsePropagation.h b/include/llvm/Analysis/SparsePropagation.h index 2c7f5dd73547..d1a54171d8bd 100644 --- a/include/llvm/Analysis/SparsePropagation.h +++ b/include/llvm/Analysis/SparsePropagation.h @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/BasicBlock.h" #include <set> #include <vector> diff --git a/include/llvm/Analysis/TargetLibraryInfo.def b/include/llvm/Analysis/TargetLibraryInfo.def index 7798e3c88248..b2a593d67dca 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.def +++ b/include/llvm/Analysis/TargetLibraryInfo.def @@ -195,6 +195,11 @@ TLI_DEFINE_STRING_INTERNAL("__memmove_chk") /// void *__memset_chk(void *s, char v, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memset_chk) TLI_DEFINE_STRING_INTERNAL("__memset_chk") + +// int __nvvm_reflect(const char *) +TLI_DEFINE_ENUM_INTERNAL(nvvm_reflect) +TLI_DEFINE_STRING_INTERNAL("__nvvm_reflect") + /// double __sincospi_stret(double x); TLI_DEFINE_ENUM_INTERNAL(sincospi_stret) TLI_DEFINE_STRING_INTERNAL("__sincospi_stret") diff --git a/include/llvm/Analysis/TargetLibraryInfo.h b/include/llvm/Analysis/TargetLibraryInfo.h index 7becdf033dd2..7efa6f059707 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.h +++ b/include/llvm/Analysis/TargetLibraryInfo.h @@ -11,15 +11,17 @@ #define LLVM_ANALYSIS_TARGETLIBRARYINFO_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" namespace llvm { -/// VecDesc - Describes a possible vectorization of a function. +template <typename T> class ArrayRef; + +/// Describes a possible vectorization of a function. /// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized /// by a factor 'VectorizationFactor'. struct VecDesc { @@ -27,7 +29,6 @@ struct VecDesc { const char *VectorFnName; unsigned VectorizationFactor; }; -class PreservedAnalyses; namespace LibFunc { enum Func { @@ -38,7 +39,7 @@ class PreservedAnalyses; }; } -/// \brief Implementation of the target library information. +/// Implementation of the target library information. /// /// This class constructs tables that hold the target library information and /// make it available. However, it is somewhat expensive to compute and only @@ -70,8 +71,13 @@ class TargetLibraryInfoImpl { /// on VectorFnName rather than ScalarFnName. std::vector<VecDesc> ScalarDescs; + /// Return true if the function type FTy is valid for the library function + /// F, regardless of whether the function is available. + bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F, + const DataLayout *DL) const; + public: - /// \brief List of known vector-functions libraries. + /// List of known vector-functions libraries. /// /// The vector-functions library defines, which functions are vectorizable /// and with which factor. The library can be specified by either frontend, @@ -92,24 +98,31 @@ public: TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI); TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI); - /// \brief Searches for a particular function name. + /// Searches for a particular function name. /// /// If it is one of the known library functions, return true and set F to the /// corresponding value. bool getLibFunc(StringRef funcName, LibFunc::Func &F) const; - /// \brief Forces a function to be marked as unavailable. + /// Searches for a particular function name, also checking that its type is + /// valid for the library function matching that name. + /// + /// If it is one of the known library functions, return true and set F to the + /// corresponding value. + bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const; + + /// Forces a function to be marked as unavailable. void setUnavailable(LibFunc::Func F) { setState(F, Unavailable); } - /// \brief Forces a function to be marked as available. + /// Forces a function to be marked as available. void setAvailable(LibFunc::Func F) { setState(F, StandardName); } - /// \brief Forces a function to be marked as available and provide an - /// alternate name that must be used. + /// Forces a function to be marked as available and provide an alternate name + /// that must be used. void setAvailableWithName(LibFunc::Func F, StringRef Name) { if (StandardNames[F] != Name) { setState(F, CustomName); @@ -120,48 +133,47 @@ public: } } - /// \brief Disables all builtins. + /// Disables all builtins. /// /// This can be used for options like -fno-builtin. void disableAllFunctions(); - /// addVectorizableFunctions - Add a set of scalar -> vector mappings, - /// queryable via getVectorizedFunction and getScalarizedFunction. + /// Add a set of scalar -> vector mappings, queryable via + /// getVectorizedFunction and getScalarizedFunction. void addVectorizableFunctions(ArrayRef<VecDesc> Fns); /// Calls addVectorizableFunctions with a known preset of functions for the /// given vector library. void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib); - /// isFunctionVectorizable - Return true if the function F has a - /// vector equivalent with vectorization factor VF. + /// Return true if the function F has a vector equivalent with vectorization + /// factor VF. bool isFunctionVectorizable(StringRef F, unsigned VF) const { return !getVectorizedFunction(F, VF).empty(); } - /// isFunctionVectorizable - Return true if the function F has a - /// vector equivalent with any vectorization factor. + /// Return true if the function F has a vector equivalent with any + /// vectorization factor. bool isFunctionVectorizable(StringRef F) const; - /// getVectorizedFunction - Return the name of the equivalent of - /// F, vectorized with factor VF. If no such mapping exists, - /// return the empty string. + /// Return the name of the equivalent of F, vectorized with factor VF. If no + /// such mapping exists, return the empty string. StringRef getVectorizedFunction(StringRef F, unsigned VF) const; - /// isFunctionScalarizable - Return true if the function F has a - /// scalar equivalent, and set VF to be the vectorization factor. + /// Return true if the function F has a scalar equivalent, and set VF to be + /// the vectorization factor. bool isFunctionScalarizable(StringRef F, unsigned &VF) const { return !getScalarizedFunction(F, VF).empty(); } - /// getScalarizedFunction - Return the name of the equivalent of - /// F, scalarized. If no such mapping exists, return the empty string. + /// Return the name of the equivalent of F, scalarized. If no such mapping + /// exists, return the empty string. /// /// Set VF to the vectorization factor. StringRef getScalarizedFunction(StringRef F, unsigned &VF) const; }; -/// \brief Provides information about what library functions are available for +/// Provides information about what library functions are available for /// the current target. /// /// This both allows optimizations to handle them specially and frontends to @@ -187,7 +199,7 @@ public: return *this; } - /// \brief Searches for a particular function name. + /// Searches for a particular function name. /// /// If it is one of the known library functions, return true and set F to the /// corresponding value. @@ -195,7 +207,11 @@ public: return Impl->getLibFunc(funcName, F); } - /// \brief Tests whether a library function is available. + bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const { + return Impl->getLibFunc(FDecl, F); + } + + /// Tests whether a library function is available. bool has(LibFunc::Func F) const { return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable; } @@ -209,8 +225,8 @@ public: return Impl->getVectorizedFunction(F, VF); } - /// \brief Tests if the function is both available and a candidate for - /// optimized code generation. + /// Tests if the function is both available and a candidate for optimized code + /// generation. bool hasOptimizedCodeGen(LibFunc::Func F) const { if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable) return false; @@ -251,31 +267,28 @@ public: return Impl->CustomNames.find(F)->second; } - /// \brief Handle invalidation from the pass manager. + /// Handle invalidation from the pass manager. /// /// If we try to invalidate this info, just return false. It cannot become /// invalid even if the module changes. bool invalidate(Module &, const PreservedAnalyses &) { return false; } }; -/// \brief Analysis pass providing the \c TargetLibraryInfo. +/// Analysis pass providing the \c TargetLibraryInfo. /// /// Note that this pass's result cannot be invalidated, it is immutable for the /// life of the module. -class TargetLibraryAnalysis { +class TargetLibraryAnalysis : public AnalysisInfoMixin<TargetLibraryAnalysis> { public: typedef TargetLibraryInfo Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - /// \brief Default construct the library analysis. + /// Default construct the library analysis. /// /// This will use the module's triple to construct the library info for that /// module. TargetLibraryAnalysis() {} - /// \brief Construct a library analysis with preset info. + /// Construct a library analysis with preset info. /// /// This will directly copy the preset info into the result without /// consulting the module's triple. @@ -291,20 +304,18 @@ public: return *this; } - TargetLibraryInfo run(Module &M); - TargetLibraryInfo run(Function &F); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "TargetLibraryAnalysis"; } + TargetLibraryInfo run(Module &M, ModuleAnalysisManager &); + TargetLibraryInfo run(Function &F, FunctionAnalysisManager &); private: + friend AnalysisInfoMixin<TargetLibraryAnalysis>; static char PassID; Optional<TargetLibraryInfoImpl> PresetInfoImpl; StringMap<std::unique_ptr<TargetLibraryInfoImpl>> Impls; - TargetLibraryInfoImpl &lookupInfoImpl(Triple T); + TargetLibraryInfoImpl &lookupInfoImpl(const Triple &T); }; class TargetLibraryInfoWrapperPass : public ImmutablePass { diff --git a/include/llvm/Analysis/TargetTransformInfo.h b/include/llvm/Analysis/TargetTransformInfo.h index 3913cc3f107c..7570d22a803c 100644 --- a/include/llvm/Analysis/TargetTransformInfo.h +++ b/include/llvm/Analysis/TargetTransformInfo.h @@ -25,6 +25,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/DataTypes.h" #include <functional> @@ -34,7 +36,6 @@ namespace llvm { class Function; class GlobalValue; class Loop; -class PreservedAnalyses; class Type; class User; class Value; @@ -165,6 +166,14 @@ public: /// This overload allows specifying a set of candidate argument values. int getCallCost(const Function *F, ArrayRef<const Value *> Arguments) const; + /// \returns A value by which our inlining threshold should be multiplied. + /// This is primarily used to bump up the inlining threshold wholesale on + /// targets where calls are unusually expensive. + /// + /// TODO: This is a rather blunt instrument. Perhaps altering the costs of + /// individual classes of instructions would be better. + unsigned getInliningThresholdMultiplier() const; + /// \brief Estimate the cost of an intrinsic when lowered. /// /// Mirrors the \c getCallCost method but uses an intrinsic identifier. @@ -260,6 +269,10 @@ public: // (set to UINT_MAX to disable). This does not apply in cases where the // loop is being fully unrolled. unsigned MaxCount; + /// Set the maximum unrolling factor for full unrolling. Like MaxCount, but + /// applies even if full unrolling is selected. This allows a target to fall + /// back to Partial unrolling if full unrolling is above FullUnrollMaxCount. + unsigned FullUnrollMaxCount; /// Allow partial unrolling (unrolling of loops to expand the size of the /// loop body, not only to eliminate small constant-trip-count loops). bool Partial; @@ -267,9 +280,14 @@ public: /// loop body even when the number of loop iterations is not known at /// compile time). bool Runtime; + /// Allow generation of a loop remainder (extra iterations after unroll). + bool AllowRemainder; /// Allow emitting expensive instructions (such as divisions) when computing /// the trip count of a loop for runtime unrolling. bool AllowExpensiveTripCount; + /// Apply loop unroll on any kind of loop + /// (mainly to loops that fail runtime unrolling). + bool Force; }; /// \brief Get target-customized preferences for the generic loop unrolling @@ -313,8 +331,7 @@ public: unsigned AddrSpace = 0) const; /// \brief Return true if the target supports masked load/store - /// AVX2 and AVX-512 targets allow masks for consecutive load and store for - /// 32 and 64 bit elements. + /// AVX2 and AVX-512 targets allow masks for consecutive load and store bool isLegalMaskedStore(Type *DataType) const; bool isLegalMaskedLoad(Type *DataType) const; @@ -362,6 +379,20 @@ public: /// \brief Enable matching of interleaved access groups. bool enableInterleavedAccessVectorization() const; + /// \brief Indicate that it is potentially unsafe to automatically vectorize + /// floating-point operations because the semantics of vector and scalar + /// floating-point semantics may differ. For example, ARM NEON v7 SIMD math + /// does not support IEEE-754 denormal numbers, while depending on the + /// platform, scalar floating-point math does. + /// This applies to floating-point math operations and calls, not memory + /// operations, shuffles, or casts. + bool isFPVectorizationPotentiallyUnsafe() const; + + /// \brief Determine if the target supports unaligned memory accesses. + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace = 0, + unsigned Alignment = 1, + bool *Fast = nullptr) const; + /// \brief Return hardware support for population count. PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) const; @@ -383,6 +414,16 @@ public: Type *Ty) const; int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, Type *Ty) const; + + /// \brief Return the expected cost for the given integer when optimising + /// for size. This is different than the other integer immediate cost + /// functions in that it is subtarget agnostic. This is useful when you e.g. + /// target one ISA such as Aarch32 but smaller encodings could be possible + /// with another such as Thumb. This return value is used as a penalty when + /// the total costs for a constant is calculated (the bigger the cost, the + /// more beneficial constant hoisting is). + int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) const; /// @} /// \name Vector Target Information @@ -416,6 +457,27 @@ public: /// \return The width of the largest scalar or vector register type. unsigned getRegisterBitWidth(bool Vector) const; + /// \return The bitwidth of the largest vector type that should be used to + /// load/store in the given address space. + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const; + + /// \return The size of a cache line in bytes. + unsigned getCacheLineSize() const; + + /// \return How much before a load we should place the prefetch instruction. + /// This is currently measured in number of instructions. + unsigned getPrefetchDistance() const; + + /// \return Some HW prefetchers can handle accesses up to a certain constant + /// stride. This is the minimum stride in bytes where it makes sense to start + /// adding SW prefetches. The default is 1, i.e. prefetch with any stride. + unsigned getMinPrefetchStride() const; + + /// \return The maximum number of iterations to prefetch ahead. If the + /// required number of iterations is more than this number, no prefetching is + /// performed. + unsigned getMaxPrefetchIterationsAhead() const; + /// \return The maximum interleave factor that any transform should try to /// perform for this target. This number depends on the level of parallelism /// and the number of execution units in the CPU. @@ -438,6 +500,11 @@ public: /// zext, etc. int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) const; + /// \return The expected cost of a sign- or zero-extended vector extract. Use + /// -1 to indicate that there is no information about the index value. + int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, + unsigned Index = -1) const; + /// \return The expected cost of control-flow related instructions such as /// Phi, Ret, Br. int getCFInstrCost(unsigned Opcode) const; @@ -497,11 +564,11 @@ public: /// \returns The cost of Intrinsic instructions. Types analysis only. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys) const; + ArrayRef<Type *> Tys, FastMathFlags FMF) const; /// \returns The cost of Intrinsic instructions. Analyses the real arguments. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args) const; + ArrayRef<Value *> Args, FastMathFlags FMF) const; /// \returns The cost of Call instructions. int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) const; @@ -569,6 +636,7 @@ public: virtual int getCallCost(const Function *F, int NumArgs) = 0; virtual int getCallCost(const Function *F, ArrayRef<const Value *> Arguments) = 0; + virtual unsigned getInliningThresholdMultiplier() = 0; virtual int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef<Type *> ParamTys) = 0; virtual int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, @@ -599,9 +667,16 @@ public: virtual bool shouldBuildLookupTables() = 0; virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0; virtual bool enableInterleavedAccessVectorization() = 0; + virtual bool isFPVectorizationPotentiallyUnsafe() = 0; + virtual bool allowsMisalignedMemoryAccesses(unsigned BitWidth, + unsigned AddressSpace, + unsigned Alignment, + bool *Fast) = 0; virtual PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) = 0; virtual bool haveFastSqrt(Type *Ty) = 0; virtual int getFPOpCost(Type *Ty) = 0; + virtual int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) = 0; virtual int getIntImmCost(const APInt &Imm, Type *Ty) = 0; virtual int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, Type *Ty) = 0; @@ -609,6 +684,11 @@ public: Type *Ty) = 0; virtual unsigned getNumberOfRegisters(bool Vector) = 0; virtual unsigned getRegisterBitWidth(bool Vector) = 0; + virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) = 0; + virtual unsigned getCacheLineSize() = 0; + virtual unsigned getPrefetchDistance() = 0; + virtual unsigned getMinPrefetchStride() = 0; + virtual unsigned getMaxPrefetchIterationsAhead() = 0; virtual unsigned getMaxInterleaveFactor(unsigned VF) = 0; virtual unsigned getArithmeticInstrCost(unsigned Opcode, Type *Ty, OperandValueKind Opd1Info, @@ -618,6 +698,8 @@ public: virtual int getShuffleCost(ShuffleKind Kind, Type *Tp, int Index, Type *SubTp) = 0; virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) = 0; + virtual int getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) = 0; virtual int getCFInstrCost(unsigned Opcode) = 0; virtual int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) = 0; @@ -639,9 +721,11 @@ public: virtual int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys) = 0; + ArrayRef<Type *> Tys, + FastMathFlags FMF) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args) = 0; + ArrayRef<Value *> Args, + FastMathFlags FMF) = 0; virtual int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) = 0; virtual unsigned getNumberOfParts(Type *Tp) = 0; @@ -684,6 +768,9 @@ public: ArrayRef<const Value *> Arguments) override { return Impl.getCallCost(F, Arguments); } + unsigned getInliningThresholdMultiplier() override { + return Impl.getInliningThresholdMultiplier(); + } int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef<Type *> ParamTys) override { return Impl.getIntrinsicCost(IID, RetTy, ParamTys); @@ -751,6 +838,14 @@ public: bool enableInterleavedAccessVectorization() override { return Impl.enableInterleavedAccessVectorization(); } + bool isFPVectorizationPotentiallyUnsafe() override { + return Impl.isFPVectorizationPotentiallyUnsafe(); + } + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace, + unsigned Alignment, bool *Fast) override { + return Impl.allowsMisalignedMemoryAccesses(BitWidth, AddressSpace, + Alignment, Fast); + } PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) override { return Impl.getPopcntSupport(IntTyWidthInBit); } @@ -758,6 +853,10 @@ public: int getFPOpCost(Type *Ty) override { return Impl.getFPOpCost(Ty); } + int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) override { + return Impl.getIntImmCodeSizeCost(Opc, Idx, Imm, Ty); + } int getIntImmCost(const APInt &Imm, Type *Ty) override { return Impl.getIntImmCost(Imm, Ty); } @@ -775,6 +874,21 @@ public: unsigned getRegisterBitWidth(bool Vector) override { return Impl.getRegisterBitWidth(Vector); } + + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) override { + return Impl.getLoadStoreVecRegBitWidth(AddrSpace); + } + + unsigned getCacheLineSize() override { + return Impl.getCacheLineSize(); + } + unsigned getPrefetchDistance() override { return Impl.getPrefetchDistance(); } + unsigned getMinPrefetchStride() override { + return Impl.getMinPrefetchStride(); + } + unsigned getMaxPrefetchIterationsAhead() override { + return Impl.getMaxPrefetchIterationsAhead(); + } unsigned getMaxInterleaveFactor(unsigned VF) override { return Impl.getMaxInterleaveFactor(VF); } @@ -793,6 +907,10 @@ public: int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) override { return Impl.getCastInstrCost(Opcode, Dst, Src); } + int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, + unsigned Index) override { + return Impl.getExtractWithExtendCost(Opcode, Dst, VecTy, Index); + } int getCFInstrCost(unsigned Opcode) override { return Impl.getCFInstrCost(Opcode); } @@ -826,13 +944,14 @@ public: bool IsPairwiseForm) override { return Impl.getReductionCost(Opcode, Ty, IsPairwiseForm); } - int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Tys); + int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef<Type *> Tys, + FastMathFlags FMF) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF); } int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Args); + ArrayRef<Value *> Args, + FastMathFlags FMF) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF); } int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) override { @@ -876,16 +995,10 @@ TargetTransformInfo::TargetTransformInfo(T Impl) /// is done in a subtarget specific way and LLVM supports compiling different /// functions targeting different subtargets in order to support runtime /// dispatch according to the observed subtarget. -class TargetIRAnalysis { +class TargetIRAnalysis : public AnalysisInfoMixin<TargetIRAnalysis> { public: typedef TargetTransformInfo Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "TargetIRAnalysis"; } - /// \brief Default construct a target IR analysis. /// /// This will use the module's datalayout to construct a baseline @@ -912,9 +1025,10 @@ public: return *this; } - Result run(const Function &F); + Result run(const Function &F, AnalysisManager<Function> &); private: + friend AnalysisInfoMixin<TargetIRAnalysis>; static char PassID; /// \brief The callback used to produce a result. diff --git a/include/llvm/Analysis/TargetTransformInfoImpl.h b/include/llvm/Analysis/TargetTransformInfoImpl.h index 43815234051e..a97624bc2ab0 100644 --- a/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -102,8 +102,8 @@ public: } } - unsigned getGEPCost(Type *PointeeType, const Value *Ptr, - ArrayRef<const Value *> Operands) { + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef<const Value *> Operands) { // In the basic model, we just assume that all-constant GEPs will be folded // into their uses via addressing modes. for (unsigned Idx = 0, Size = Operands.size(); Idx != Size; ++Idx) @@ -128,6 +128,8 @@ public: return TTI::TCC_Basic * (NumArgs + 1); } + unsigned getInliningThresholdMultiplier() { return 1; } + unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef<Type *> ParamTys) { switch (IID) { @@ -240,6 +242,13 @@ public: bool enableInterleavedAccessVectorization() { return false; } + bool isFPVectorizationPotentiallyUnsafe() { return false; } + + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, + unsigned AddressSpace, + unsigned Alignment, + bool *Fast) { return false; } + TTI::PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) { return TTI::PSK_Software; } @@ -248,6 +257,11 @@ public: unsigned getFPOpCost(Type *Ty) { return TargetTransformInfo::TCC_Basic; } + int getIntImmCodeSizeCost(unsigned Opcode, unsigned Idx, const APInt &Imm, + Type *Ty) { + return 0; + } + unsigned getIntImmCost(const APInt &Imm, Type *Ty) { return TTI::TCC_Basic; } unsigned getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, @@ -264,6 +278,16 @@ public: unsigned getRegisterBitWidth(bool Vector) { return 32; } + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) { return 128; } + + unsigned getCacheLineSize() { return 0; } + + unsigned getPrefetchDistance() { return 0; } + + unsigned getMinPrefetchStride() { return 1; } + + unsigned getMaxPrefetchIterationsAhead() { return UINT_MAX; } + unsigned getMaxInterleaveFactor(unsigned VF) { return 1; } unsigned getArithmeticInstrCost(unsigned Opcode, Type *Ty, @@ -281,6 +305,11 @@ public: unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { return 1; } + unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) { + return 1; + } + unsigned getCFInstrCost(unsigned Opcode) { return 1; } unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) { @@ -316,11 +345,11 @@ public: } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys) { + ArrayRef<Type *> Tys, FastMathFlags FMF) { return 1; } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args) { + ArrayRef<Value *> Args, FastMathFlags FMF) { return 1; } @@ -404,8 +433,8 @@ public: using BaseT::getGEPCost; - unsigned getGEPCost(Type *PointeeType, const Value *Ptr, - ArrayRef<const Value *> Operands) { + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef<const Value *> Operands) { const GlobalValue *BaseGV = nullptr; if (Ptr != nullptr) { // TODO: will remove this when pointers have an opaque type. @@ -421,7 +450,7 @@ public: // Assumes the address space is 0 when Ptr is nullptr. unsigned AS = (Ptr == nullptr ? 0 : Ptr->getType()->getPointerAddressSpace()); - auto GTI = gep_type_begin(PointerType::get(PointeeType, AS), Operands); + auto GTI = gep_type_begin(PointeeType, AS, Operands); for (auto I = Operands.begin(); I != Operands.end(); ++I, ++GTI) { // We assume that the cost of Scalar GEP with constant index and the // cost of Vector GEP with splat constant index are the same. diff --git a/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/include/llvm/Analysis/TypeBasedAliasAnalysis.h index 7b44ac73f1fa..229b0f97b983 100644 --- a/include/llvm/Analysis/TypeBasedAliasAnalysis.h +++ b/include/llvm/Analysis/TypeBasedAliasAnalysis.h @@ -27,8 +27,7 @@ class TypeBasedAAResult : public AAResultBase<TypeBasedAAResult> { friend AAResultBase<TypeBasedAAResult>; public: - explicit TypeBasedAAResult(const TargetLibraryInfo &TLI) - : AAResultBase(TLI) {} + explicit TypeBasedAAResult() {} TypeBasedAAResult(TypeBasedAAResult &&Arg) : AAResultBase(std::move(Arg)) {} /// Handle invalidation events from the new pass manager. @@ -49,20 +48,14 @@ private: }; /// Analysis pass providing a never-invalidated alias analysis result. -class TypeBasedAA { +class TypeBasedAA : public AnalysisInfoMixin<TypeBasedAA> { + friend AnalysisInfoMixin<TypeBasedAA>; + static char PassID; + public: typedef TypeBasedAAResult Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - - TypeBasedAAResult run(Function &F, AnalysisManager<Function> *AM); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "TypeBasedAA"; } - -private: - static char PassID; + TypeBasedAAResult run(Function &F, AnalysisManager<Function> &AM); }; /// Legacy wrapper pass to provide the TypeBasedAAResult object. diff --git a/include/llvm/Analysis/TypeMetadataUtils.h b/include/llvm/Analysis/TypeMetadataUtils.h new file mode 100644 index 000000000000..c3f688f5d7f1 --- /dev/null +++ b/include/llvm/Analysis/TypeMetadataUtils.h @@ -0,0 +1,45 @@ +//===- TypeMetadataUtils.h - Utilities related to type metadata --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains functions that make it easier to manipulate type metadata +// for devirtualization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_TYPEMETADATAUTILS_H +#define LLVM_ANALYSIS_TYPEMETADATAUTILS_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/CallSite.h" + +namespace llvm { + +/// A call site that could be devirtualized. +struct DevirtCallSite { + /// The offset from the address point to the virtual function. + uint64_t Offset; + /// The call site itself. + CallSite CS; +}; + +/// Given a call to the intrinsic @llvm.type.test, find all devirtualizable +/// call sites based on the call and return them in DevirtCalls. +void findDevirtualizableCallsForTypeTest( + SmallVectorImpl<DevirtCallSite> &DevirtCalls, + SmallVectorImpl<CallInst *> &Assumes, CallInst *CI); + +/// Given a call to the intrinsic @llvm.type.checked.load, find all +/// devirtualizable call sites based on the call and return them in DevirtCalls. +void findDevirtualizableCallsForTypeCheckedLoad( + SmallVectorImpl<DevirtCallSite> &DevirtCalls, + SmallVectorImpl<Instruction *> &LoadedPtrs, + SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses, CallInst *CI); +} + +#endif diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h index 8e0291068472..2c6221d4933f 100644 --- a/include/llvm/Analysis/ValueTracking.h +++ b/include/llvm/Analysis/ValueTracking.h @@ -15,17 +15,20 @@ #ifndef LLVM_ANALYSIS_VALUETRACKING_H #define LLVM_ANALYSIS_VALUETRACKING_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/DataTypes.h" namespace llvm { +template <typename T> class ArrayRef; class APInt; class AddOperator; class AssumptionCache; class DataLayout; class DominatorTree; + class GEPOperator; class Instruction; class Loop; class LoopInfo; @@ -34,6 +37,10 @@ namespace llvm { class TargetLibraryInfo; class Value; + namespace Intrinsic { + enum ID : unsigned; + } + /// Determine which bits of V are known to be either zero or one and return /// them in the KnownZero/KnownOne bit sets. /// @@ -58,29 +65,29 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeSignBit - Determine whether the sign bit is known to be zero or - /// one. Convenience wrapper around computeKnownBits. + /// Determine whether the sign bit is known to be zero or one. Convenience + /// wrapper around computeKnownBits. void ComputeSignBit(Value *V, bool &KnownZero, bool &KnownOne, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownToBeAPowerOfTwo - Return true if the given value is known to have - /// exactly one bit set when defined. For vectors return true if every - /// element is known to be a power of two when defined. Supports values with - /// integer or pointer type and vectors of integers. If 'OrZero' is set then - /// return true if the given value is either a power of two or zero. + /// Return true if the given value is known to have exactly one bit set when + /// defined. For vectors return true if every element is known to be a power + /// of two when defined. Supports values with integer or pointer type and + /// vectors of integers. If 'OrZero' is set, then return true if the given + /// value is either a power of two or zero. bool isKnownToBeAPowerOfTwo(Value *V, const DataLayout &DL, bool OrZero = false, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownNonZero - Return true if the given value is known to be non-zero - /// when defined. For vectors return true if every element is known to be - /// non-zero when defined. Supports values with integer or pointer type and - /// vectors of integers. + /// Return true if the given value is known to be non-zero when defined. For + /// vectors, return true if every element is known to be non-zero when + /// defined. Supports values with integer or pointer type and vectors of + /// integers. bool isKnownNonZero(Value *V, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, @@ -92,16 +99,30 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownNonEqual - Return true if the given values are known to be - /// non-equal when defined. Supports scalar integer types only. + /// Returns true if the given value is known be positive (i.e. non-negative + /// and non-zero). + bool isKnownPositive(Value *V, const DataLayout &DL, unsigned Depth = 0, + AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, + const DominatorTree *DT = nullptr); + + /// Returns true if the given value is known be negative (i.e. non-positive + /// and non-zero). + bool isKnownNegative(Value *V, const DataLayout &DL, unsigned Depth = 0, + AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, + const DominatorTree *DT = nullptr); + + /// Return true if the given values are known to be non-equal when defined. + /// Supports scalar integer types only. bool isKnownNonEqual(Value *V1, Value *V2, const DataLayout &DL, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use - /// this predicate to simplify operations downstream. Mask is known to be - /// zero for bits that V cannot have. + /// Return true if 'V & Mask' is known to be zero. We use this predicate to + /// simplify operations downstream. Mask is known to be zero for bits that V + /// cannot have. /// /// This function is defined on values with integer type, values with pointer /// type, and vectors of integers. In the case @@ -113,48 +134,52 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeNumSignBits - Return the number of times the sign bit of the - /// register is replicated into the other bits. We know that at least 1 bit - /// is always equal to the sign bit (itself), but other cases can give us - /// information. For example, immediately after an "ashr X, 2", we know that - /// the top 3 bits are all equal to each other, so we return 3. - /// - /// 'Op' must have a scalar integer type. - /// + /// Return the number of times the sign bit of the register is replicated into + /// the other bits. We know that at least 1 bit is always equal to the sign + /// bit (itself), but other cases can give us information. For example, + /// immediately after an "ashr X, 2", we know that the top 3 bits are all + /// equal to each other, so we return 3. For vectors, return the number of + /// sign bits for the vector element with the mininum number of known sign + /// bits. unsigned ComputeNumSignBits(Value *Op, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeMultiple - This function computes the integer multiple of Base that - /// equals V. If successful, it returns true and returns the multiple in - /// Multiple. If unsuccessful, it returns false. Also, if V can be - /// simplified to an integer, then the simplified V is returned in Val. Look - /// through sext only if LookThroughSExt=true. + /// This function computes the integer multiple of Base that equals V. If + /// successful, it returns true and returns the multiple in Multiple. If + /// unsuccessful, it returns false. Also, if V can be simplified to an + /// integer, then the simplified V is returned in Val. Look through sext only + /// if LookThroughSExt=true. bool ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, bool LookThroughSExt = false, unsigned Depth = 0); - /// CannotBeNegativeZero - Return true if we can prove that the specified FP - /// value is never equal to -0.0. - /// - bool CannotBeNegativeZero(const Value *V, unsigned Depth = 0); - - /// CannotBeOrderedLessThanZero - Return true if we can prove that the - /// specified FP value is either a NaN or never less than 0.0. - /// - bool CannotBeOrderedLessThanZero(const Value *V, unsigned Depth = 0); - - /// isBytewiseValue - If the specified value can be set by repeating the same - /// byte in memory, return the i8 value that it is represented with. This is - /// true for all i8 values obviously, but is also true for i32 0, i32 -1, - /// i16 0xF0F0, double 0.0 etc. If the value can't be handled with a repeated - /// byte store (e.g. i16 0x1234), return null. + /// Map a call instruction to an intrinsic ID. Libcalls which have equivalent + /// intrinsics are treated as-if they were intrinsics. + Intrinsic::ID getIntrinsicForCallSite(ImmutableCallSite ICS, + const TargetLibraryInfo *TLI); + + /// Return true if we can prove that the specified FP value is never equal to + /// -0.0. + bool CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, + unsigned Depth = 0); + + /// Return true if we can prove that the specified FP value is either a NaN or + /// never less than 0.0. + bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI, + unsigned Depth = 0); + + /// If the specified value can be set by repeating the same byte in memory, + /// return the i8 value that it is represented with. This is true for all i8 + /// values obviously, but is also true for i32 0, i32 -1, i16 0xF0F0, double + /// 0.0 etc. If the value can't be handled with a repeated byte store (e.g. + /// i16 0x1234), return null. Value *isBytewiseValue(Value *V); - /// FindInsertedValue - Given an aggregrate and an sequence of indices, see if - /// the scalar value indexed is already around as a register, for example if - /// it were inserted directly into the aggregrate. + /// Given an aggregrate and an sequence of indices, see if the scalar value + /// indexed is already around as a register, for example if it were inserted + /// directly into the aggregrate. /// /// If InsertBefore is not null, this function will duplicate (modified) /// insertvalues when a part of a nested struct is extracted. @@ -162,9 +187,8 @@ namespace llvm { ArrayRef<unsigned> idx_range, Instruction *InsertBefore = nullptr); - /// GetPointerBaseWithConstantOffset - Analyze the specified pointer to see if - /// it can be expressed as a base pointer plus a constant offset. Return the - /// base and offset to the caller. + /// Analyze the specified pointer to see if it can be expressed as a base + /// pointer plus a constant offset. Return the base and offset to the caller. Value *GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL); static inline const Value * @@ -174,24 +198,28 @@ namespace llvm { DL); } - /// getConstantStringInfo - This function computes the length of a - /// null-terminated C string pointed to by V. If successful, it returns true - /// and returns the string in Str. If unsuccessful, it returns false. This - /// does not include the trailing nul character by default. If TrimAtNul is - /// set to false, then this returns any trailing nul characters as well as any - /// other characters that come after it. + /// Returns true if the GEP is based on a pointer to a string (array of i8), + /// and is indexing into this string. + bool isGEPBasedOnPointerToString(const GEPOperator *GEP); + + /// This function computes the length of a null-terminated C string pointed to + /// by V. If successful, it returns true and returns the string in Str. If + /// unsuccessful, it returns false. This does not include the trailing null + /// character by default. If TrimAtNul is set to false, then this returns any + /// trailing null characters as well as any other characters that come after + /// it. bool getConstantStringInfo(const Value *V, StringRef &Str, uint64_t Offset = 0, bool TrimAtNul = true); - /// GetStringLength - If we can compute the length of the string pointed to by - /// the specified pointer, return 'len+1'. If we can't, return 0. + /// If we can compute the length of the string pointed to by the specified + /// pointer, return 'len+1'. If we can't, return 0. uint64_t GetStringLength(Value *V); - /// GetUnderlyingObject - This method strips off any GEP address adjustments - /// and pointer casts from the specified value, returning the original object - /// being addressed. Note that the returned value has pointer type if the - /// specified value does. If the MaxLookup value is non-zero, it limits the - /// number of instructions to be stripped off. + /// This method strips off any GEP address adjustments and pointer casts from + /// the specified value, returning the original object being addressed. Note + /// that the returned value has pointer type if the specified value does. If + /// the MaxLookup value is non-zero, it limits the number of instructions to + /// be stripped off. Value *GetUnderlyingObject(Value *V, const DataLayout &DL, unsigned MaxLookup = 6); static inline const Value *GetUnderlyingObject(const Value *V, @@ -232,32 +260,11 @@ namespace llvm { const DataLayout &DL, LoopInfo *LI = nullptr, unsigned MaxLookup = 6); - /// onlyUsedByLifetimeMarkers - Return true if the only users of this pointer - /// are lifetime markers. + /// Return true if the only users of this pointer are lifetime markers. bool onlyUsedByLifetimeMarkers(const Value *V); - /// isDereferenceablePointer - Return true if this is always a dereferenceable - /// pointer. If the context instruction is specified perform context-sensitive - /// analysis and return true if the pointer is dereferenceable at the - /// specified instruction. - bool isDereferenceablePointer(const Value *V, const DataLayout &DL, - const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); - - /// Returns true if V is always a dereferenceable pointer with alignment - /// greater or equal than requested. If the context instruction is specified - /// performs context-sensitive analysis and returns true if the pointer is - /// dereferenceable at the specified instruction. - bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, - const DataLayout &DL, - const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); - - /// isSafeToSpeculativelyExecute - Return true if the instruction does not - /// have any effects besides calculating the result and does not have - /// undefined behavior. + /// Return true if the instruction does not have any effects besides + /// calculating the result and does not have undefined behavior. /// /// This method never returns true for an instruction that returns true for /// mayHaveSideEffects; however, this method also does some other checks in @@ -281,8 +288,7 @@ namespace llvm { /// for such instructions, moving them may change the resulting value. bool isSafeToSpeculativelyExecute(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// Returns true if the result or effects of the given instructions \p I /// depend on or influence global memory. @@ -294,19 +300,18 @@ namespace llvm { /// operands are not memory dependent. bool mayBeMemoryDependent(const Instruction &I); - /// isKnownNonNull - Return true if this pointer couldn't possibly be null by - /// its definition. This returns true for allocas, non-extern-weak globals - /// and byval arguments. - bool isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI = nullptr); + /// Return true if this pointer couldn't possibly be null by its definition. + /// This returns true for allocas, non-extern-weak globals, and byval + /// arguments. + bool isKnownNonNull(const Value *V); - /// isKnownNonNullAt - Return true if this pointer couldn't possibly be null. - /// If the context instruction is specified perform context-sensitive analysis - /// and return true if the pointer couldn't possibly be null at the specified + /// Return true if this pointer couldn't possibly be null. If the context + /// instruction is specified, perform context-sensitive analysis and return + /// true if the pointer couldn't possibly be null at the specified /// instruction. bool isKnownNonNullAt(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// Return true if it is valid to use the assumptions provided by an /// assume intrinsic, I, at the point in the control-flow identified by the @@ -337,6 +342,11 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); + /// Returns true if the arithmetic part of the \p II 's result is + /// used only along the paths control dependent on the computation + /// not overflowing, \p II being an <op>.with.overflow intrinsic. + bool isOverflowIntrinsicNoWrap(IntrinsicInst *II, DominatorTree &DT); + /// Return true if this function can prove that the instruction I will /// always transfer execution to one of its successors (including the next /// instruction that follows within a basic block). E.g. this is not @@ -441,18 +451,20 @@ namespace llvm { /// E.g. if RangeMD is !{i32 0, i32 10, i32 15, i32 20} then return [0, 20). ConstantRange getConstantRangeFromMetadata(MDNode &RangeMD); - /// Return true if RHS is known to be implied by LHS. A & B must be i1 - /// (boolean) values or a vector of such values. Note that the truth table for - /// implication is the same as <=u on i1 values (but not <=s!). The truth - /// table for both is: + /// Return true if RHS is known to be implied true by LHS. Return false if + /// RHS is known to be implied false by LHS. Otherwise, return None if no + /// implication can be made. + /// A & B must be i1 (boolean) values or a vector of such values. Note that + /// the truth table for implication is the same as <=u on i1 values (but not + /// <=s!). The truth table for both is: /// | T | F (B) /// T | T | F /// F | T | T /// (A) - bool isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL, - unsigned Depth = 0, AssumptionCache *AC = nullptr, - const Instruction *CxtI = nullptr, - const DominatorTree *DT = nullptr); + Optional<bool> isImpliedCondition( + Value *LHS, Value *RHS, const DataLayout &DL, bool InvertAPred = false, + unsigned Depth = 0, AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); } // end namespace llvm #endif diff --git a/include/llvm/Analysis/VectorUtils.h b/include/llvm/Analysis/VectorUtils.h index 531803adf5e4..eaa068b89c77 100644 --- a/include/llvm/Analysis/VectorUtils.h +++ b/include/llvm/Analysis/VectorUtils.h @@ -14,15 +14,13 @@ #ifndef LLVM_TRANSFORMS_UTILS_VECTORUTILS_H #define LLVM_TRANSFORMS_UTILS_VECTORUTILS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Intrinsics.h" namespace llvm { -struct DemandedBits; +template <typename T> class ArrayRef; +class DemandedBits; class GetElementPtrInst; class Loop; class ScalarEvolution; @@ -30,6 +28,10 @@ class TargetTransformInfo; class Type; class Value; +namespace Intrinsic { +enum ID : unsigned; +} + /// \brief Identify if the intrinsic is trivially vectorizable. /// This method returns true if the intrinsic's argument types are all /// scalars for the scalar form of the intrinsic and all vectors for @@ -40,26 +42,11 @@ bool isTriviallyVectorizable(Intrinsic::ID ID); /// ctlz,cttz and powi special intrinsics whose argument is scalar. bool hasVectorInstrinsicScalarOpd(Intrinsic::ID ID, unsigned ScalarOpdIdx); -/// \brief Identify if call has a unary float signature -/// It returns input intrinsic ID if call has a single argument, -/// argument type and call instruction type should be floating -/// point type and call should only reads memory. -/// else return not_intrinsic. -Intrinsic::ID checkUnaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID); - -/// \brief Identify if call has a binary float signature -/// It returns input intrinsic ID if call has two arguments, -/// arguments type and call instruction type should be floating -/// point type and call should only reads memory. -/// else return not_intrinsic. -Intrinsic::ID checkBinaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID); - /// \brief Returns intrinsic ID for call. /// For the input call instruction it finds mapping intrinsic and returns /// its intrinsic ID, in case it does not found it return not_intrinsic. -Intrinsic::ID getIntrinsicIDForCall(CallInst *CI, const TargetLibraryInfo *TLI); +Intrinsic::ID getVectorIntrinsicIDForCall(const CallInst *CI, + const TargetLibraryInfo *TLI); /// \brief Find the operand of the GEP that should be checked for consecutive /// stores. This ignores trailing indices that have no effect on the final @@ -126,7 +113,16 @@ MapVector<Instruction*, uint64_t> computeMinimumValueSizes(ArrayRef<BasicBlock*> Blocks, DemandedBits &DB, const TargetTransformInfo *TTI=nullptr); - + +/// Specifically, let Kinds = [MD_tbaa, MD_alias_scope, MD_noalias, MD_fpmath, +/// MD_nontemporal]. For K in Kinds, we get the MDNode for K from each of the +/// elements of VL, compute their "intersection" (i.e., the most generic +/// metadata value that covers all of the individual values), and set I's +/// metadata for M equal to the intersection value. +/// +/// This function always sets a (possibly null) value for each K in Kinds. +Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL); + } // llvm namespace #endif diff --git a/include/llvm/AsmParser/Parser.h b/include/llvm/AsmParser/Parser.h index 96a15c1ec45c..768b089b8a2a 100644 --- a/include/llvm/AsmParser/Parser.h +++ b/include/llvm/AsmParser/Parser.h @@ -23,6 +23,7 @@ class LLVMContext; class Module; struct SlotMapping; class SMDiagnostic; +class Type; /// This function is the main interface to the LLVM Assembly Parser. It parses /// an ASCII file that (presumably) contains LLVM Assembly code. It returns a @@ -91,6 +92,24 @@ bool parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err, Constant *parseConstantValue(StringRef Asm, SMDiagnostic &Err, const Module &M, const SlotMapping *Slots = nullptr); +/// Parse a type in the given string. +/// +/// \param Slots The optional slot mapping that will restore the parsing state +/// of the module. +/// \return null on error. +Type *parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, + const SlotMapping *Slots = nullptr); + +/// Parse a string \p Asm that starts with a type. +/// \p Read[out] gives the number of characters that have been read to parse +/// the type in \p Asm. +/// +/// \param Slots The optional slot mapping that will restore the parsing state +/// of the module. +/// \return null on error. +Type *parseTypeAtBeginning(StringRef Asm, unsigned &Read, SMDiagnostic &Err, + const Module &M, const SlotMapping *Slots = nullptr); + } // End llvm namespace #endif diff --git a/include/llvm/Bitcode/BitCodes.h b/include/llvm/Bitcode/BitCodes.h index 96c420151858..66400b697c5c 100644 --- a/include/llvm/Bitcode/BitCodes.h +++ b/include/llvm/Bitcode/BitCodes.h @@ -147,12 +147,8 @@ public: static char DecodeChar6(unsigned V) { assert((V & ~63) == 0 && "Not a Char6 encoded character!"); - if (V < 26) return V+'a'; - if (V < 26+26) return V-26+'A'; - if (V < 26+26+10) return V-26-26+'0'; - if (V == 62) return '.'; - if (V == 63) return '_'; - llvm_unreachable("Not a value Char6 character!"); + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._" + [V]; } }; diff --git a/include/llvm/Bitcode/BitcodeWriterPass.h b/include/llvm/Bitcode/BitcodeWriterPass.h index a1272cf156e5..946255b878a6 100644 --- a/include/llvm/Bitcode/BitcodeWriterPass.h +++ b/include/llvm/Bitcode/BitcodeWriterPass.h @@ -16,12 +16,12 @@ #define LLVM_BITCODE_BITCODEWRITERPASS_H #include "llvm/ADT/StringRef.h" +#include "llvm/IR/PassManager.h" namespace llvm { class Module; class ModulePass; class raw_ostream; -class PreservedAnalyses; /// \brief Create and return a pass that writes the module to the specified /// ostream. Note that this pass is designed for use with the legacy pass @@ -30,11 +30,15 @@ class PreservedAnalyses; /// If \c ShouldPreserveUseListOrder, encode use-list order so it can be /// reproduced when deserialized. /// -/// If \c EmitFunctionSummary, emit the function summary index (currently -/// for use in ThinLTO optimization). +/// If \c EmitSummaryIndex, emit the summary index (currently for use in ThinLTO +/// optimization). +/// +/// If \c EmitModuleHash, compute and emit the module hash in the bitcode +/// (currently for use in ThinLTO incremental build). ModulePass *createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder = false, - bool EmitFunctionSummary = false); + bool EmitSummaryIndex = false, + bool EmitModuleHash = false); /// \brief Pass for writing a module of IR out to a bitcode file. /// @@ -43,7 +47,8 @@ ModulePass *createBitcodeWriterPass(raw_ostream &Str, class BitcodeWriterPass { raw_ostream &OS; bool ShouldPreserveUseListOrder; - bool EmitFunctionSummary; + bool EmitSummaryIndex; + bool EmitModuleHash; public: /// \brief Construct a bitcode writer pass around a particular output stream. @@ -51,17 +56,18 @@ public: /// If \c ShouldPreserveUseListOrder, encode use-list order so it can be /// reproduced when deserialized. /// - /// If \c EmitFunctionSummary, emit the function summary index (currently + /// If \c EmitSummaryIndex, emit the summary index (currently /// for use in ThinLTO optimization). explicit BitcodeWriterPass(raw_ostream &OS, bool ShouldPreserveUseListOrder = false, - bool EmitFunctionSummary = false) + bool EmitSummaryIndex = false, + bool EmitModuleHash = false) : OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitFunctionSummary(EmitFunctionSummary) {} + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) {} /// \brief Run the bitcode writer pass, and output the module to the selected /// output stream. - PreservedAnalyses run(Module &M); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); static StringRef name() { return "BitcodeWriterPass"; } }; diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/BitstreamReader.h index c0cf6cde887f..b331ceea051c 100644 --- a/include/llvm/Bitcode/BitstreamReader.h +++ b/include/llvm/Bitcode/BitstreamReader.h @@ -17,6 +17,7 @@ #include "llvm/Bitcode/BitCodes.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/StreamingMemoryObject.h" #include <climits> #include <string> @@ -128,175 +129,64 @@ public: } }; -/// When advancing through a bitstream cursor, each advance can discover a few -/// different kinds of entries: -struct BitstreamEntry { - enum { - Error, // Malformed bitcode was found. - EndBlock, // We've reached the end of the current block, (or the end of the - // file, which is treated like a series of EndBlock records. - SubBlock, // This is the start of a new subblock of a specific ID. - Record // This is a record with a specific AbbrevID. - } Kind; - - unsigned ID; - - static BitstreamEntry getError() { - BitstreamEntry E; E.Kind = Error; return E; - } - static BitstreamEntry getEndBlock() { - BitstreamEntry E; E.Kind = EndBlock; return E; - } - static BitstreamEntry getSubBlock(unsigned ID) { - BitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E; - } - static BitstreamEntry getRecord(unsigned AbbrevID) { - BitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E; - } -}; - -/// This represents a position within a bitcode file. There may be multiple -/// independent cursors reading within one bitstream, each maintaining their own -/// local state. -/// -/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not -/// be passed by value. -class BitstreamCursor { - BitstreamReader *BitStream; - size_t NextChar; +/// This represents a position within a bitstream. There may be multiple +/// independent cursors reading within one bitstream, each maintaining their +/// own local state. +class SimpleBitstreamCursor { + BitstreamReader *R = nullptr; + size_t NextChar = 0; // The size of the bicode. 0 if we don't know it yet. - size_t Size; + size_t Size = 0; /// This is the current data we have pulled from the stream but have not /// returned to the client. This is specifically and intentionally defined to /// follow the word size of the host machine for efficiency. We use word_t in /// places that are aware of this to make it perfectly explicit what is going /// on. +public: typedef size_t word_t; - word_t CurWord; + +private: + word_t CurWord = 0; /// This is the number of bits in CurWord that are valid. This is always from /// [0...bits_of(size_t)-1] inclusive. - unsigned BitsInCurWord; - - // This is the declared size of code values used for the current block, in - // bits. - unsigned CurCodeSize; - - /// Abbrevs installed at in this block. - std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> CurAbbrevs; - - struct Block { - unsigned PrevCodeSize; - std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> PrevAbbrevs; - explicit Block(unsigned PCS) : PrevCodeSize(PCS) {} - }; - - /// This tracks the codesize of parent blocks. - SmallVector<Block, 8> BlockScope; - + unsigned BitsInCurWord = 0; public: static const size_t MaxChunkSize = sizeof(word_t) * 8; - BitstreamCursor() { init(nullptr); } - - explicit BitstreamCursor(BitstreamReader &R) { init(&R); } + SimpleBitstreamCursor() = default; - void init(BitstreamReader *R) { - freeState(); - - BitStream = R; - NextChar = 0; - Size = 0; - BitsInCurWord = 0; - CurCodeSize = 2; - } - - void freeState(); + explicit SimpleBitstreamCursor(BitstreamReader &R) : R(&R) {} + explicit SimpleBitstreamCursor(BitstreamReader *R) : R(R) {} bool canSkipToPos(size_t pos) const { // pos can be skipped to if it is a valid address or one byte past the end. - return pos == 0 || BitStream->getBitcodeBytes().isValidAddress( - static_cast<uint64_t>(pos - 1)); + return pos == 0 || + R->getBitcodeBytes().isValidAddress(static_cast<uint64_t>(pos - 1)); } bool AtEndOfStream() { if (BitsInCurWord != 0) return false; if (Size != 0) - return Size == NextChar; + return Size <= NextChar; fillCurWord(); return BitsInCurWord == 0; } - /// Return the number of bits used to encode an abbrev #. - unsigned getAbbrevIDWidth() const { return CurCodeSize; } - /// Return the bit # of the bit we are reading. uint64_t GetCurrentBitNo() const { return NextChar*CHAR_BIT - BitsInCurWord; } - BitstreamReader *getBitStreamReader() { - return BitStream; - } - const BitstreamReader *getBitStreamReader() const { - return BitStream; - } - - /// Flags that modify the behavior of advance(). - enum { - /// If this flag is used, the advance() method does not automatically pop - /// the block scope when the end of a block is reached. - AF_DontPopBlockAtEnd = 1, - - /// If this flag is used, abbrev entries are returned just like normal - /// records. - AF_DontAutoprocessAbbrevs = 2 - }; - - /// Advance the current bitstream, returning the next entry in the stream. - BitstreamEntry advance(unsigned Flags = 0) { - while (1) { - unsigned Code = ReadCode(); - if (Code == bitc::END_BLOCK) { - // Pop the end of the block unless Flags tells us not to. - if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd()) - return BitstreamEntry::getError(); - return BitstreamEntry::getEndBlock(); - } - - if (Code == bitc::ENTER_SUBBLOCK) - return BitstreamEntry::getSubBlock(ReadSubBlockID()); - - if (Code == bitc::DEFINE_ABBREV && - !(Flags & AF_DontAutoprocessAbbrevs)) { - // We read and accumulate abbrev's, the client can't do anything with - // them anyway. - ReadAbbrevRecord(); - continue; - } - - return BitstreamEntry::getRecord(Code); - } - } + // Return the byte # of the current bit. + uint64_t getCurrentByteNo() const { return GetCurrentBitNo() / 8; } - /// This is a convenience function for clients that don't expect any - /// subblocks. This just skips over them automatically. - BitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) { - while (1) { - // If we found a normal entry, return it. - BitstreamEntry Entry = advance(Flags); - if (Entry.Kind != BitstreamEntry::SubBlock) - return Entry; - - // If we found a sub-block, just skip over it and check the next entry. - if (SkipBlock()) - return BitstreamEntry::getError(); - } - } + BitstreamReader *getBitStreamReader() { return R; } + const BitstreamReader *getBitStreamReader() const { return R; } /// Reset the stream to the specified bit number. void JumpToBit(uint64_t BitNo) { @@ -313,6 +203,37 @@ public: Read(WordBitNo); } + /// Reset the stream to the bit pointed at by the specified pointer. + /// + /// The pointer must be a dereferenceable pointer into the bytes in the + /// underlying memory object. + void jumpToPointer(const uint8_t *Pointer) { + auto *Pointer0 = getPointerToByte(0, 1); + assert((intptr_t)Pointer0 <= (intptr_t)Pointer && + "Expected pointer into bitstream"); + + JumpToBit(8 * (Pointer - Pointer0)); + assert((intptr_t)getPointerToByte(getCurrentByteNo(), 1) == + (intptr_t)Pointer && + "Expected to reach pointer"); + } + void jumpToPointer(const char *Pointer) { + jumpToPointer((const uint8_t *)Pointer); + } + + /// Get a pointer into the bitstream at the specified byte offset. + const uint8_t *getPointerToByte(uint64_t ByteNo, uint64_t NumBytes) { + return R->getBitcodeBytes().getPointer(ByteNo, NumBytes); + } + + /// Get a pointer into the bitstream at the specified bit offset. + /// + /// The bit offset must be on a byte boundary. + const uint8_t *getPointerToBit(uint64_t BitNo, uint64_t NumBytes) { + assert(!(BitNo % 8) && "Expected bit on byte boundary"); + return getPointerToByte(BitNo / 8, NumBytes); + } + void fillCurWord() { if (Size != 0 && NextChar >= Size) report_fatal_error("Unexpected end of file"); @@ -321,7 +242,7 @@ public: uint8_t Array[sizeof(word_t)] = {0}; uint64_t BytesRead = - BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar); + R->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar); // If we run out of data, stop at the end of the stream. if (BytesRead == 0) { @@ -416,7 +337,6 @@ public: } } -private: void SkipToFourByteBoundary() { // If word_t is 64-bits and if we've read less than 32 bits, just dump // the bits we have up to the next 32-bit boundary. @@ -429,7 +349,166 @@ private: BitsInCurWord = 0; } + + /// Skip to the end of the file. + void skipToEnd() { NextChar = R->getBitcodeBytes().getExtent(); } + + /// Prevent the cursor from reading past a byte boundary. + /// + /// Prevent the cursor from requesting byte reads past \c Limit. This is + /// useful when working with a cursor on a StreamingMemoryObject, when it's + /// desirable to avoid invalidating the result of getPointerToByte(). + /// + /// If \c Limit is on a word boundary, AtEndOfStream() will return true if + /// the cursor position reaches or exceeds \c Limit, regardless of the true + /// number of available bytes. Otherwise, AtEndOfStream() returns true when + /// it reaches or exceeds the next word boundary. + void setArtificialByteLimit(uint64_t Limit) { + assert(getCurrentByteNo() < Limit && "Move cursor before lowering limit"); + + // Round to word boundary. + Limit = alignTo(Limit, sizeof(word_t)); + + // Only change size if the new one is lower. + if (!Size || Size > Limit) + Size = Limit; + } + + /// Return the Size, if known. + uint64_t getSizeIfKnown() const { return Size; } +}; + +/// When advancing through a bitstream cursor, each advance can discover a few +/// different kinds of entries: +struct BitstreamEntry { + enum { + Error, // Malformed bitcode was found. + EndBlock, // We've reached the end of the current block, (or the end of the + // file, which is treated like a series of EndBlock records. + SubBlock, // This is the start of a new subblock of a specific ID. + Record // This is a record with a specific AbbrevID. + } Kind; + + unsigned ID; + + static BitstreamEntry getError() { + BitstreamEntry E; E.Kind = Error; return E; + } + static BitstreamEntry getEndBlock() { + BitstreamEntry E; E.Kind = EndBlock; return E; + } + static BitstreamEntry getSubBlock(unsigned ID) { + BitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E; + } + static BitstreamEntry getRecord(unsigned AbbrevID) { + BitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E; + } +}; + +/// This represents a position within a bitcode file, implemented on top of a +/// SimpleBitstreamCursor. +/// +/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not +/// be passed by value. +class BitstreamCursor : SimpleBitstreamCursor { + // This is the declared size of code values used for the current block, in + // bits. + unsigned CurCodeSize = 2; + + /// Abbrevs installed at in this block. + std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> CurAbbrevs; + + struct Block { + unsigned PrevCodeSize; + std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> PrevAbbrevs; + explicit Block(unsigned PCS) : PrevCodeSize(PCS) {} + }; + + /// This tracks the codesize of parent blocks. + SmallVector<Block, 8> BlockScope; + + public: + static const size_t MaxChunkSize = sizeof(word_t) * 8; + + BitstreamCursor() = default; + + explicit BitstreamCursor(BitstreamReader &R) { init(&R); } + + void init(BitstreamReader *R) { + freeState(); + SimpleBitstreamCursor::operator=(SimpleBitstreamCursor(R)); + CurCodeSize = 2; + } + + void freeState(); + + using SimpleBitstreamCursor::canSkipToPos; + using SimpleBitstreamCursor::AtEndOfStream; + using SimpleBitstreamCursor::GetCurrentBitNo; + using SimpleBitstreamCursor::getCurrentByteNo; + using SimpleBitstreamCursor::getPointerToByte; + using SimpleBitstreamCursor::getBitStreamReader; + using SimpleBitstreamCursor::JumpToBit; + using SimpleBitstreamCursor::fillCurWord; + using SimpleBitstreamCursor::Read; + using SimpleBitstreamCursor::ReadVBR; + using SimpleBitstreamCursor::ReadVBR64; + + /// Return the number of bits used to encode an abbrev #. + unsigned getAbbrevIDWidth() const { return CurCodeSize; } + + /// Flags that modify the behavior of advance(). + enum { + /// If this flag is used, the advance() method does not automatically pop + /// the block scope when the end of a block is reached. + AF_DontPopBlockAtEnd = 1, + + /// If this flag is used, abbrev entries are returned just like normal + /// records. + AF_DontAutoprocessAbbrevs = 2 + }; + + /// Advance the current bitstream, returning the next entry in the stream. + BitstreamEntry advance(unsigned Flags = 0) { + while (1) { + unsigned Code = ReadCode(); + if (Code == bitc::END_BLOCK) { + // Pop the end of the block unless Flags tells us not to. + if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd()) + return BitstreamEntry::getError(); + return BitstreamEntry::getEndBlock(); + } + + if (Code == bitc::ENTER_SUBBLOCK) + return BitstreamEntry::getSubBlock(ReadSubBlockID()); + + if (Code == bitc::DEFINE_ABBREV && + !(Flags & AF_DontAutoprocessAbbrevs)) { + // We read and accumulate abbrev's, the client can't do anything with + // them anyway. + ReadAbbrevRecord(); + continue; + } + + return BitstreamEntry::getRecord(Code); + } + } + + /// This is a convenience function for clients that don't expect any + /// subblocks. This just skips over them automatically. + BitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) { + while (1) { + // If we found a normal entry, return it. + BitstreamEntry Entry = advance(Flags); + if (Entry.Kind != BitstreamEntry::SubBlock) + return Entry; + + // If we found a sub-block, just skip over it and check the next entry. + if (SkipBlock()) + return BitstreamEntry::getError(); + } + } unsigned ReadCode() { return Read(CurCodeSize); diff --git a/include/llvm/Bitcode/BitstreamWriter.h b/include/llvm/Bitcode/BitstreamWriter.h index 438f4a6fb69b..d613f5e18954 100644 --- a/include/llvm/Bitcode/BitstreamWriter.h +++ b/include/llvm/Bitcode/BitstreamWriter.h @@ -361,36 +361,17 @@ private: // If this record has blob data, emit it, otherwise we must have record // entries to encode this way. - // Emit a vbr6 to indicate the number of elements present. if (BlobData) { - EmitVBR(static_cast<uint32_t>(BlobLen), 6); assert(RecordIdx == Vals.size() && "Blob data and record entries specified for blob operand!"); - } else { - EmitVBR(static_cast<uint32_t>(Vals.size()-RecordIdx), 6); - } - - // Flush to a 32-bit alignment boundary. - FlushToWord(); - - // Emit each field as a literal byte. - if (BlobData) { - for (unsigned i = 0; i != BlobLen; ++i) - WriteByte((unsigned char)BlobData[i]); - // Know that blob data is consumed for assertion below. + assert(Blob.data() == BlobData && "BlobData got moved"); + assert(Blob.size() == BlobLen && "BlobLen got changed"); + emitBlob(Blob); BlobData = nullptr; } else { - for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx) { - assert(isUInt<8>(Vals[RecordIdx]) && - "Value too large to emit as blob"); - WriteByte((unsigned char)Vals[RecordIdx]); - } + emitBlob(Vals.slice(RecordIdx)); } - - // Align end to 32-bits. - while (GetBufferOffset() & 3) - WriteByte(0); } else { // Single scalar field. assert(RecordIdx < Vals.size() && "Invalid abbrev/record"); EmitAbbreviatedField(Op, Vals[RecordIdx]); @@ -403,6 +384,30 @@ private: } public: + /// Emit a blob, including flushing before and tail-padding. + template <class UIntTy> + void emitBlob(ArrayRef<UIntTy> Bytes, bool ShouldEmitSize = true) { + // Emit a vbr6 to indicate the number of elements present. + if (ShouldEmitSize) + EmitVBR(static_cast<uint32_t>(Bytes.size()), 6); + + // Flush to a 32-bit alignment boundary. + FlushToWord(); + + // Emit literal bytes. + for (const auto &B : Bytes) { + assert(isUInt<8>(B) && "Value too large to emit as byte"); + WriteByte((unsigned char)B); + } + + // Align end to 32-bits. + while (GetBufferOffset() & 3) + WriteByte(0); + } + void emitBlob(StringRef Bytes, bool ShouldEmitSize = true) { + emitBlob(makeArrayRef((const uint8_t *)Bytes.data(), Bytes.size()), + ShouldEmitSize); + } /// EmitRecord - Emit the specified record to the stream, using an abbrev if /// we have one to compress the output. diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index bcc84bedbed0..52d4f01b7985 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -22,7 +22,7 @@ namespace llvm { namespace bitc { - // The only top-level block type defined is for a module. +// The only top-level block type defined is for a module. enum BlockIDs { // Blocks MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID, @@ -48,7 +48,7 @@ enum BlockIDs { USELIST_BLOCK_ID, MODULE_STRTAB_BLOCK_ID, - FUNCTION_SUMMARY_BLOCK_ID, + GLOBALVAL_SUMMARY_BLOCK_ID, OPERAND_BUNDLE_TAGS_BLOCK_ID, @@ -70,431 +70,468 @@ enum IdentificationCodes { /// also accepts N-1. enum { BITCODE_CURRENT_EPOCH = 0 }; - /// MODULE blocks have a number of optional fields and subblocks. - enum ModuleCodes { - MODULE_CODE_VERSION = 1, // VERSION: [version#] - MODULE_CODE_TRIPLE = 2, // TRIPLE: [strchr x N] - MODULE_CODE_DATALAYOUT = 3, // DATALAYOUT: [strchr x N] - MODULE_CODE_ASM = 4, // ASM: [strchr x N] - MODULE_CODE_SECTIONNAME = 5, // SECTIONNAME: [strchr x N] - - // FIXME: Remove DEPLIB in 4.0. - MODULE_CODE_DEPLIB = 6, // DEPLIB: [strchr x N] - - // GLOBALVAR: [pointer type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal] - MODULE_CODE_GLOBALVAR = 7, - - // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, - // section, visibility, gc, unnamed_addr] - MODULE_CODE_FUNCTION = 8, - - // ALIAS: [alias type, aliasee val#, linkage, visibility] - MODULE_CODE_ALIAS_OLD = 9, - - // MODULE_CODE_PURGEVALS: [numvals] - MODULE_CODE_PURGEVALS = 10, - - MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N] - MODULE_CODE_COMDAT = 12, // COMDAT: [selection_kind, name] - - MODULE_CODE_VSTOFFSET = 13, // VSTOFFSET: [offset] - - // ALIAS: [alias value type, addrspace, aliasee val#, linkage, visibility] - MODULE_CODE_ALIAS = 14, - - // METADATA_VALUES: [numvals] - MODULE_CODE_METADATA_VALUES = 15, - }; - - /// PARAMATTR blocks have code for defining a parameter attribute set. - enum AttributeCodes { - // FIXME: Remove `PARAMATTR_CODE_ENTRY_OLD' in 4.0 - PARAMATTR_CODE_ENTRY_OLD = 1, // ENTRY: [paramidx0, attr0, - // paramidx1, attr1...] - PARAMATTR_CODE_ENTRY = 2, // ENTRY: [paramidx0, attrgrp0, - // paramidx1, attrgrp1, ...] - PARAMATTR_GRP_CODE_ENTRY = 3 // ENTRY: [id, attr0, att1, ...] - }; - - /// TYPE blocks have codes for each type primitive they use. - enum TypeCodes { - TYPE_CODE_NUMENTRY = 1, // NUMENTRY: [numentries] - - // Type Codes - TYPE_CODE_VOID = 2, // VOID - TYPE_CODE_FLOAT = 3, // FLOAT - TYPE_CODE_DOUBLE = 4, // DOUBLE - TYPE_CODE_LABEL = 5, // LABEL - TYPE_CODE_OPAQUE = 6, // OPAQUE - TYPE_CODE_INTEGER = 7, // INTEGER: [width] - TYPE_CODE_POINTER = 8, // POINTER: [pointee type] - - TYPE_CODE_FUNCTION_OLD = 9, // FUNCTION: [vararg, attrid, retty, - // paramty x N] - - TYPE_CODE_HALF = 10, // HALF - - TYPE_CODE_ARRAY = 11, // ARRAY: [numelts, eltty] - TYPE_CODE_VECTOR = 12, // VECTOR: [numelts, eltty] - - // These are not with the other floating point types because they're - // a late addition, and putting them in the right place breaks - // binary compatibility. - TYPE_CODE_X86_FP80 = 13, // X86 LONG DOUBLE - TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) - TYPE_CODE_PPC_FP128= 15, // PPC LONG DOUBLE (2 doubles) - - TYPE_CODE_METADATA = 16, // METADATA - - TYPE_CODE_X86_MMX = 17, // X86 MMX - - TYPE_CODE_STRUCT_ANON = 18, // STRUCT_ANON: [ispacked, eltty x N] - TYPE_CODE_STRUCT_NAME = 19, // STRUCT_NAME: [strchr x N] - TYPE_CODE_STRUCT_NAMED = 20,// STRUCT_NAMED: [ispacked, eltty x N] - - TYPE_CODE_FUNCTION = 21, // FUNCTION: [vararg, retty, paramty x N] - - TYPE_CODE_TOKEN = 22 // TOKEN - }; - - enum OperandBundleTagCode { - OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N] - }; - - // The type symbol table only has one code (TST_ENTRY_CODE). - enum TypeSymtabCodes { - TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N] - }; - - // Value symbol table codes. - enum ValueSymtabCodes { - VST_CODE_ENTRY = 1, // VST_ENTRY: [valueid, namechar x N] - VST_CODE_BBENTRY = 2, // VST_BBENTRY: [bbid, namechar x N] - VST_CODE_FNENTRY = 3, // VST_FNENTRY: [valueid, offset, namechar x N] - // VST_COMBINED_FNENTRY: [offset, namechar x N] - VST_CODE_COMBINED_FNENTRY = 4 - }; - - // The module path symbol table only has one code (MST_CODE_ENTRY). - enum ModulePathSymtabCodes { - MST_CODE_ENTRY = 1, // MST_ENTRY: [modid, namechar x N] - }; - - // The function summary section uses different codes in the per-module - // and combined index cases. - enum FunctionSummarySymtabCodes { - FS_CODE_PERMODULE_ENTRY = 1, // FS_ENTRY: [valueid, islocal, instcount] - FS_CODE_COMBINED_ENTRY = 2, // FS_ENTRY: [modid, instcount] - }; - - enum MetadataCodes { - METADATA_STRING = 1, // MDSTRING: [values] - METADATA_VALUE = 2, // VALUE: [type num, value num] - METADATA_NODE = 3, // NODE: [n x md num] - METADATA_NAME = 4, // STRING: [values] - METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] - METADATA_KIND = 6, // [n x [id, name]] - METADATA_LOCATION = 7, // [distinct, line, col, scope, inlined-at?] - METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] - METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)] - METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes] - METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]] - METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num] - METADATA_SUBRANGE = 13, // [distinct, count, lo] - METADATA_ENUMERATOR = 14, // [distinct, value, name] - METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] - METADATA_FILE = 16, // [distinct, filename, directory] - METADATA_DERIVED_TYPE = 17, // [distinct, ...] - METADATA_COMPOSITE_TYPE= 18, // [distinct, ...] - METADATA_SUBROUTINE_TYPE=19, // [distinct, flags, types] - METADATA_COMPILE_UNIT = 20, // [distinct, ...] - METADATA_SUBPROGRAM = 21, // [distinct, ...] - METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column] - METADATA_LEXICAL_BLOCK_FILE=23,//[distinct, scope, file, discriminator] - METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line] - METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] - METADATA_TEMPLATE_VALUE= 26, // [distinct, scope, name, type, value, ...] - METADATA_GLOBAL_VAR = 27, // [distinct, ...] - METADATA_LOCAL_VAR = 28, // [distinct, ...] - METADATA_EXPRESSION = 29, // [distinct, n x element] - METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] - METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name] - METADATA_MODULE = 32, // [distinct, scope, name, ...] - METADATA_MACRO = 33, // [distinct, macinfo, line, name, value] - METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] - }; - - // The constants block (CONSTANTS_BLOCK_ID) describes emission for each - // constant and maintains an implicit current type value. - enum ConstantsCodes { - CST_CODE_SETTYPE = 1, // SETTYPE: [typeid] - CST_CODE_NULL = 2, // NULL - CST_CODE_UNDEF = 3, // UNDEF - CST_CODE_INTEGER = 4, // INTEGER: [intval] - CST_CODE_WIDE_INTEGER = 5, // WIDE_INTEGER: [n x intval] - CST_CODE_FLOAT = 6, // FLOAT: [fpval] - CST_CODE_AGGREGATE = 7, // AGGREGATE: [n x value number] - CST_CODE_STRING = 8, // STRING: [values] - CST_CODE_CSTRING = 9, // CSTRING: [values] - CST_CODE_CE_BINOP = 10, // CE_BINOP: [opcode, opval, opval] - CST_CODE_CE_CAST = 11, // CE_CAST: [opcode, opty, opval] - CST_CODE_CE_GEP = 12, // CE_GEP: [n x operands] - CST_CODE_CE_SELECT = 13, // CE_SELECT: [opval, opval, opval] - CST_CODE_CE_EXTRACTELT = 14, // CE_EXTRACTELT: [opty, opval, opval] - CST_CODE_CE_INSERTELT = 15, // CE_INSERTELT: [opval, opval, opval] - CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval] - CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred] - CST_CODE_INLINEASM_OLD = 18, // INLINEASM: [sideeffect|alignstack, - // asmstr,conststr] - CST_CODE_CE_SHUFVEC_EX = 19, // SHUFVEC_EX: [opty, opval, opval, opval] - CST_CODE_CE_INBOUNDS_GEP = 20,// INBOUNDS_GEP: [n x operands] - CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval, bb#] - CST_CODE_DATA = 22, // DATA: [n x elements] - CST_CODE_INLINEASM = 23 // INLINEASM: [sideeffect|alignstack| - // asmdialect,asmstr,conststr] - }; - - /// CastOpcodes - These are values used in the bitcode files to encode which - /// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums - /// have no fixed relation to the LLVM IR enum values. Changing these will - /// break compatibility with old files. - enum CastOpcodes { - CAST_TRUNC = 0, - CAST_ZEXT = 1, - CAST_SEXT = 2, - CAST_FPTOUI = 3, - CAST_FPTOSI = 4, - CAST_UITOFP = 5, - CAST_SITOFP = 6, - CAST_FPTRUNC = 7, - CAST_FPEXT = 8, - CAST_PTRTOINT = 9, - CAST_INTTOPTR = 10, - CAST_BITCAST = 11, - CAST_ADDRSPACECAST = 12 - }; - - /// BinaryOpcodes - These are values used in the bitcode files to encode which - /// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums - /// have no fixed relation to the LLVM IR enum values. Changing these will - /// break compatibility with old files. - enum BinaryOpcodes { - BINOP_ADD = 0, - BINOP_SUB = 1, - BINOP_MUL = 2, - BINOP_UDIV = 3, - BINOP_SDIV = 4, // overloaded for FP - BINOP_UREM = 5, - BINOP_SREM = 6, // overloaded for FP - BINOP_SHL = 7, - BINOP_LSHR = 8, - BINOP_ASHR = 9, - BINOP_AND = 10, - BINOP_OR = 11, - BINOP_XOR = 12 - }; - - /// These are values used in the bitcode files to encode AtomicRMW operations. - /// The values of these enums have no fixed relation to the LLVM IR enum - /// values. Changing these will break compatibility with old files. - enum RMWOperations { - RMW_XCHG = 0, - RMW_ADD = 1, - RMW_SUB = 2, - RMW_AND = 3, - RMW_NAND = 4, - RMW_OR = 5, - RMW_XOR = 6, - RMW_MAX = 7, - RMW_MIN = 8, - RMW_UMAX = 9, - RMW_UMIN = 10 - }; - - /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing - /// OverflowingBinaryOperator's SubclassOptionalData contents. - enum OverflowingBinaryOperatorOptionalFlags { - OBO_NO_UNSIGNED_WRAP = 0, - OBO_NO_SIGNED_WRAP = 1 - }; - - /// PossiblyExactOperatorOptionalFlags - Flags for serializing - /// PossiblyExactOperator's SubclassOptionalData contents. - enum PossiblyExactOperatorOptionalFlags { - PEO_EXACT = 0 - }; - - /// Encoded AtomicOrdering values. - enum AtomicOrderingCodes { - ORDERING_NOTATOMIC = 0, - ORDERING_UNORDERED = 1, - ORDERING_MONOTONIC = 2, - ORDERING_ACQUIRE = 3, - ORDERING_RELEASE = 4, - ORDERING_ACQREL = 5, - ORDERING_SEQCST = 6 - }; - - /// Encoded SynchronizationScope values. - enum AtomicSynchScopeCodes { - SYNCHSCOPE_SINGLETHREAD = 0, - SYNCHSCOPE_CROSSTHREAD = 1 - }; - - /// Markers and flags for call instruction. - enum CallMarkersFlags { - CALL_TAIL = 0, - CALL_CCONV = 1, - CALL_MUSTTAIL = 14, - CALL_EXPLICIT_TYPE = 15, - CALL_NOTAIL = 16, - CALL_FMF = 17 // Call has optional fast-math-flags. - }; - - // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It - // can contain a constant block (CONSTANTS_BLOCK_ID). - enum FunctionCodes { - FUNC_CODE_DECLAREBLOCKS = 1, // DECLAREBLOCKS: [n] - - FUNC_CODE_INST_BINOP = 2, // BINOP: [opcode, ty, opval, opval] - FUNC_CODE_INST_CAST = 3, // CAST: [opcode, ty, opty, opval] - FUNC_CODE_INST_GEP_OLD = 4, // GEP: [n x operands] - FUNC_CODE_INST_SELECT = 5, // SELECT: [ty, opval, opval, opval] - FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opty, opval, opval] - FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [ty, opval, opval, opval] - FUNC_CODE_INST_SHUFFLEVEC = 8, // SHUFFLEVEC: [ty, opval, opval, opval] - FUNC_CODE_INST_CMP = 9, // CMP: [opty, opval, opval, pred] - - FUNC_CODE_INST_RET = 10, // RET: [opty,opval<both optional>] - FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] - FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...] - FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] - // 14 is unused. - FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE - - FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...] - // 17 is unused. - // 18 is unused. - FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [instty, opty, op, align] - FUNC_CODE_INST_LOAD = 20, // LOAD: [opty, op, align, vol] - // 21 is unused. - // 22 is unused. - FUNC_CODE_INST_VAARG = 23, // VAARG: [valistty, valist, instty] - // This store code encodes the pointer type, rather than the value type - // this is so information only available in the pointer type (e.g. address - // spaces) is retained. - FUNC_CODE_INST_STORE_OLD = 24, // STORE: [ptrty,ptr,val, align, vol] - // 25 is unused. - FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands] - FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands] - // fcmp/icmp returning Int1TY or vector of Int1Ty. Same as CMP, exists to - // support legacy vicmp/vfcmp instructions. - FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] - // new select on i1 or [N x i1] - FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] - FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, // INBOUNDS_GEP: [n x operands] - FUNC_CODE_INST_INDIRECTBR = 31, // INDIRECTBR: [opty, op0, op1, ...] - // 32 is unused. - FUNC_CODE_DEBUG_LOC_AGAIN = 33, // DEBUG_LOC_AGAIN - - FUNC_CODE_INST_CALL = 34, // CALL: [attr, cc, fnty, fnid, args...] - - FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] - FUNC_CODE_INST_FENCE = 36, // FENCE: [ordering, synchscope] - FUNC_CODE_INST_CMPXCHG_OLD = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol, - // ordering, synchscope] - FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation, - // align, vol, - // ordering, synchscope] - FUNC_CODE_INST_RESUME = 39, // RESUME: [opval] - FUNC_CODE_INST_LANDINGPAD_OLD = 40, // LANDINGPAD: [ty,val,val,num,id0,val0...] - FUNC_CODE_INST_LOADATOMIC = 41, // LOAD: [opty, op, align, vol, - // ordering, synchscope] - FUNC_CODE_INST_STOREATOMIC_OLD = 42, // STORE: [ptrty,ptr,val, align, vol - // ordering, synchscope] - FUNC_CODE_INST_GEP = 43, // GEP: [inbounds, n x operands] - FUNC_CODE_INST_STORE = 44, // STORE: [ptrty,ptr,valty,val, align, vol] - FUNC_CODE_INST_STOREATOMIC = 45, // STORE: [ptrty,ptr,val, align, vol - FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align, - // vol,ordering,synchscope] - FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...] - FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#] - FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#] - FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...] - FUNC_CODE_INST_CLEANUPPAD = 51, // CLEANUPPAD: [num,args...] - FUNC_CODE_INST_CATCHSWITCH = 52, // CATCHSWITCH: [num,args...] or [num,args...,bb] - // 53 is unused. - // 54 is unused. - FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] - }; - - enum UseListCodes { - USELIST_CODE_DEFAULT = 1, // DEFAULT: [index..., value-id] - USELIST_CODE_BB = 2 // BB: [index..., bb-id] - }; - - enum AttributeKindCodes { - // = 0 is unused - ATTR_KIND_ALIGNMENT = 1, - ATTR_KIND_ALWAYS_INLINE = 2, - ATTR_KIND_BY_VAL = 3, - ATTR_KIND_INLINE_HINT = 4, - ATTR_KIND_IN_REG = 5, - ATTR_KIND_MIN_SIZE = 6, - ATTR_KIND_NAKED = 7, - ATTR_KIND_NEST = 8, - ATTR_KIND_NO_ALIAS = 9, - ATTR_KIND_NO_BUILTIN = 10, - ATTR_KIND_NO_CAPTURE = 11, - ATTR_KIND_NO_DUPLICATE = 12, - ATTR_KIND_NO_IMPLICIT_FLOAT = 13, - ATTR_KIND_NO_INLINE = 14, - ATTR_KIND_NON_LAZY_BIND = 15, - ATTR_KIND_NO_RED_ZONE = 16, - ATTR_KIND_NO_RETURN = 17, - ATTR_KIND_NO_UNWIND = 18, - ATTR_KIND_OPTIMIZE_FOR_SIZE = 19, - ATTR_KIND_READ_NONE = 20, - ATTR_KIND_READ_ONLY = 21, - ATTR_KIND_RETURNED = 22, - ATTR_KIND_RETURNS_TWICE = 23, - ATTR_KIND_S_EXT = 24, - ATTR_KIND_STACK_ALIGNMENT = 25, - ATTR_KIND_STACK_PROTECT = 26, - ATTR_KIND_STACK_PROTECT_REQ = 27, - ATTR_KIND_STACK_PROTECT_STRONG = 28, - ATTR_KIND_STRUCT_RET = 29, - ATTR_KIND_SANITIZE_ADDRESS = 30, - ATTR_KIND_SANITIZE_THREAD = 31, - ATTR_KIND_SANITIZE_MEMORY = 32, - ATTR_KIND_UW_TABLE = 33, - ATTR_KIND_Z_EXT = 34, - ATTR_KIND_BUILTIN = 35, - ATTR_KIND_COLD = 36, - ATTR_KIND_OPTIMIZE_NONE = 37, - ATTR_KIND_IN_ALLOCA = 38, - ATTR_KIND_NON_NULL = 39, - ATTR_KIND_JUMP_TABLE = 40, - ATTR_KIND_DEREFERENCEABLE = 41, - ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42, - ATTR_KIND_CONVERGENT = 43, - ATTR_KIND_SAFESTACK = 44, - ATTR_KIND_ARGMEMONLY = 45, - ATTR_KIND_SWIFT_SELF = 46, - ATTR_KIND_SWIFT_ERROR = 47, - ATTR_KIND_NO_RECURSE = 48, - ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, - ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50 - }; - - enum ComdatSelectionKindCodes { - COMDAT_SELECTION_KIND_ANY = 1, - COMDAT_SELECTION_KIND_EXACT_MATCH = 2, - COMDAT_SELECTION_KIND_LARGEST = 3, - COMDAT_SELECTION_KIND_NO_DUPLICATES = 4, - COMDAT_SELECTION_KIND_SAME_SIZE = 5, - }; +/// MODULE blocks have a number of optional fields and subblocks. +enum ModuleCodes { + MODULE_CODE_VERSION = 1, // VERSION: [version#] + MODULE_CODE_TRIPLE = 2, // TRIPLE: [strchr x N] + MODULE_CODE_DATALAYOUT = 3, // DATALAYOUT: [strchr x N] + MODULE_CODE_ASM = 4, // ASM: [strchr x N] + MODULE_CODE_SECTIONNAME = 5, // SECTIONNAME: [strchr x N] + + // FIXME: Remove DEPLIB in 4.0. + MODULE_CODE_DEPLIB = 6, // DEPLIB: [strchr x N] + + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal] + MODULE_CODE_GLOBALVAR = 7, + + // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, + // section, visibility, gc, unnamed_addr] + MODULE_CODE_FUNCTION = 8, + + // ALIAS: [alias type, aliasee val#, linkage, visibility] + MODULE_CODE_ALIAS_OLD = 9, + + // MODULE_CODE_PURGEVALS: [numvals] + MODULE_CODE_PURGEVALS = 10, + + MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N] + MODULE_CODE_COMDAT = 12, // COMDAT: [selection_kind, name] + + MODULE_CODE_VSTOFFSET = 13, // VSTOFFSET: [offset] + + // ALIAS: [alias value type, addrspace, aliasee val#, linkage, visibility] + MODULE_CODE_ALIAS = 14, + + MODULE_CODE_METADATA_VALUES_UNUSED = 15, + + // SOURCE_FILENAME: [namechar x N] + MODULE_CODE_SOURCE_FILENAME = 16, + + // HASH: [5*i32] + MODULE_CODE_HASH = 17, + + // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility] + MODULE_CODE_IFUNC = 18, +}; + +/// PARAMATTR blocks have code for defining a parameter attribute set. +enum AttributeCodes { + // FIXME: Remove `PARAMATTR_CODE_ENTRY_OLD' in 4.0 + PARAMATTR_CODE_ENTRY_OLD = 1, // ENTRY: [paramidx0, attr0, + // paramidx1, attr1...] + PARAMATTR_CODE_ENTRY = 2, // ENTRY: [paramidx0, attrgrp0, + // paramidx1, attrgrp1, ...] + PARAMATTR_GRP_CODE_ENTRY = 3 // ENTRY: [id, attr0, att1, ...] +}; + +/// TYPE blocks have codes for each type primitive they use. +enum TypeCodes { + TYPE_CODE_NUMENTRY = 1, // NUMENTRY: [numentries] + + // Type Codes + TYPE_CODE_VOID = 2, // VOID + TYPE_CODE_FLOAT = 3, // FLOAT + TYPE_CODE_DOUBLE = 4, // DOUBLE + TYPE_CODE_LABEL = 5, // LABEL + TYPE_CODE_OPAQUE = 6, // OPAQUE + TYPE_CODE_INTEGER = 7, // INTEGER: [width] + TYPE_CODE_POINTER = 8, // POINTER: [pointee type] + + TYPE_CODE_FUNCTION_OLD = 9, // FUNCTION: [vararg, attrid, retty, + // paramty x N] + + TYPE_CODE_HALF = 10, // HALF + + TYPE_CODE_ARRAY = 11, // ARRAY: [numelts, eltty] + TYPE_CODE_VECTOR = 12, // VECTOR: [numelts, eltty] + + // These are not with the other floating point types because they're + // a late addition, and putting them in the right place breaks + // binary compatibility. + TYPE_CODE_X86_FP80 = 13, // X86 LONG DOUBLE + TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) + TYPE_CODE_PPC_FP128 = 15, // PPC LONG DOUBLE (2 doubles) + + TYPE_CODE_METADATA = 16, // METADATA + + TYPE_CODE_X86_MMX = 17, // X86 MMX + + TYPE_CODE_STRUCT_ANON = 18, // STRUCT_ANON: [ispacked, eltty x N] + TYPE_CODE_STRUCT_NAME = 19, // STRUCT_NAME: [strchr x N] + TYPE_CODE_STRUCT_NAMED = 20, // STRUCT_NAMED: [ispacked, eltty x N] + + TYPE_CODE_FUNCTION = 21, // FUNCTION: [vararg, retty, paramty x N] + + TYPE_CODE_TOKEN = 22 // TOKEN +}; + +enum OperandBundleTagCode { + OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N] +}; + +// The type symbol table only has one code (TST_ENTRY_CODE). +enum TypeSymtabCodes { + TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N] +}; + +// Value symbol table codes. +enum ValueSymtabCodes { + VST_CODE_ENTRY = 1, // VST_ENTRY: [valueid, namechar x N] + VST_CODE_BBENTRY = 2, // VST_BBENTRY: [bbid, namechar x N] + VST_CODE_FNENTRY = 3, // VST_FNENTRY: [valueid, offset, namechar x N] + // VST_COMBINED_ENTRY: [valueid, refguid] + VST_CODE_COMBINED_ENTRY = 5 +}; + +// The module path symbol table only has one code (MST_CODE_ENTRY). +enum ModulePathSymtabCodes { + MST_CODE_ENTRY = 1, // MST_ENTRY: [modid, namechar x N] + MST_CODE_HASH = 2, // MST_HASH: [5*i32] +}; + +// The summary section uses different codes in the per-module +// and combined index cases. +enum GlobalValueSummarySymtabCodes { + // PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + FS_PERMODULE = 1, + // PERMODULE_PROFILE: [valueid, flags, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + FS_PERMODULE_PROFILE = 2, + // PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid] + FS_PERMODULE_GLOBALVAR_INIT_REFS = 3, + // COMBINED: [valueid, modid, flags, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + FS_COMBINED = 4, + // COMBINED_PROFILE: [valueid, modid, flags, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + FS_COMBINED_PROFILE = 5, + // COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] + FS_COMBINED_GLOBALVAR_INIT_REFS = 6, + // ALIAS: [valueid, flags, valueid] + FS_ALIAS = 7, + // COMBINED_ALIAS: [valueid, modid, flags, valueid] + FS_COMBINED_ALIAS = 8, + // COMBINED_ORIGINAL_NAME: [original_name_hash] + FS_COMBINED_ORIGINAL_NAME = 9, + // VERSION of the summary, bumped when adding flags for instance. + FS_VERSION = 10, +}; + +enum MetadataCodes { + METADATA_STRING_OLD = 1, // MDSTRING: [values] + METADATA_VALUE = 2, // VALUE: [type num, value num] + METADATA_NODE = 3, // NODE: [n x md num] + METADATA_NAME = 4, // STRING: [values] + METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] + METADATA_KIND = 6, // [n x [id, name]] + METADATA_LOCATION = 7, // [distinct, line, col, scope, inlined-at?] + METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] + METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)] + METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes] + METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]] + METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num] + METADATA_SUBRANGE = 13, // [distinct, count, lo] + METADATA_ENUMERATOR = 14, // [distinct, value, name] + METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] + METADATA_FILE = 16, // [distinct, filename, directory] + METADATA_DERIVED_TYPE = 17, // [distinct, ...] + METADATA_COMPOSITE_TYPE = 18, // [distinct, ...] + METADATA_SUBROUTINE_TYPE = 19, // [distinct, flags, types, cc] + METADATA_COMPILE_UNIT = 20, // [distinct, ...] + METADATA_SUBPROGRAM = 21, // [distinct, ...] + METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column] + METADATA_LEXICAL_BLOCK_FILE = 23, //[distinct, scope, file, discriminator] + METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line] + METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] + METADATA_TEMPLATE_VALUE = 26, // [distinct, scope, name, type, value, ...] + METADATA_GLOBAL_VAR = 27, // [distinct, ...] + METADATA_LOCAL_VAR = 28, // [distinct, ...] + METADATA_EXPRESSION = 29, // [distinct, n x element] + METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] + METADATA_IMPORTED_ENTITY = 31, // [distinct, tag, scope, entity, line, name] + METADATA_MODULE = 32, // [distinct, scope, name, ...] + METADATA_MACRO = 33, // [distinct, macinfo, line, name, value] + METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] + METADATA_STRINGS = 35, // [count, offset] blob([lengths][chars]) + METADATA_GLOBAL_DECL_ATTACHMENT = 36, // [valueid, n x [id, mdnode]] +}; + +// The constants block (CONSTANTS_BLOCK_ID) describes emission for each +// constant and maintains an implicit current type value. +enum ConstantsCodes { + CST_CODE_SETTYPE = 1, // SETTYPE: [typeid] + CST_CODE_NULL = 2, // NULL + CST_CODE_UNDEF = 3, // UNDEF + CST_CODE_INTEGER = 4, // INTEGER: [intval] + CST_CODE_WIDE_INTEGER = 5, // WIDE_INTEGER: [n x intval] + CST_CODE_FLOAT = 6, // FLOAT: [fpval] + CST_CODE_AGGREGATE = 7, // AGGREGATE: [n x value number] + CST_CODE_STRING = 8, // STRING: [values] + CST_CODE_CSTRING = 9, // CSTRING: [values] + CST_CODE_CE_BINOP = 10, // CE_BINOP: [opcode, opval, opval] + CST_CODE_CE_CAST = 11, // CE_CAST: [opcode, opty, opval] + CST_CODE_CE_GEP = 12, // CE_GEP: [n x operands] + CST_CODE_CE_SELECT = 13, // CE_SELECT: [opval, opval, opval] + CST_CODE_CE_EXTRACTELT = 14, // CE_EXTRACTELT: [opty, opval, opval] + CST_CODE_CE_INSERTELT = 15, // CE_INSERTELT: [opval, opval, opval] + CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval] + CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred] + CST_CODE_INLINEASM_OLD = 18, // INLINEASM: [sideeffect|alignstack, + // asmstr,conststr] + CST_CODE_CE_SHUFVEC_EX = 19, // SHUFVEC_EX: [opty, opval, opval, opval] + CST_CODE_CE_INBOUNDS_GEP = 20, // INBOUNDS_GEP: [n x operands] + CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval, bb#] + CST_CODE_DATA = 22, // DATA: [n x elements] + CST_CODE_INLINEASM = 23 // INLINEASM: [sideeffect|alignstack| + // asmdialect,asmstr,conststr] +}; + +/// CastOpcodes - These are values used in the bitcode files to encode which +/// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums +/// have no fixed relation to the LLVM IR enum values. Changing these will +/// break compatibility with old files. +enum CastOpcodes { + CAST_TRUNC = 0, + CAST_ZEXT = 1, + CAST_SEXT = 2, + CAST_FPTOUI = 3, + CAST_FPTOSI = 4, + CAST_UITOFP = 5, + CAST_SITOFP = 6, + CAST_FPTRUNC = 7, + CAST_FPEXT = 8, + CAST_PTRTOINT = 9, + CAST_INTTOPTR = 10, + CAST_BITCAST = 11, + CAST_ADDRSPACECAST = 12 +}; + +/// BinaryOpcodes - These are values used in the bitcode files to encode which +/// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums +/// have no fixed relation to the LLVM IR enum values. Changing these will +/// break compatibility with old files. +enum BinaryOpcodes { + BINOP_ADD = 0, + BINOP_SUB = 1, + BINOP_MUL = 2, + BINOP_UDIV = 3, + BINOP_SDIV = 4, // overloaded for FP + BINOP_UREM = 5, + BINOP_SREM = 6, // overloaded for FP + BINOP_SHL = 7, + BINOP_LSHR = 8, + BINOP_ASHR = 9, + BINOP_AND = 10, + BINOP_OR = 11, + BINOP_XOR = 12 +}; + +/// These are values used in the bitcode files to encode AtomicRMW operations. +/// The values of these enums have no fixed relation to the LLVM IR enum +/// values. Changing these will break compatibility with old files. +enum RMWOperations { + RMW_XCHG = 0, + RMW_ADD = 1, + RMW_SUB = 2, + RMW_AND = 3, + RMW_NAND = 4, + RMW_OR = 5, + RMW_XOR = 6, + RMW_MAX = 7, + RMW_MIN = 8, + RMW_UMAX = 9, + RMW_UMIN = 10 +}; + +/// OverflowingBinaryOperatorOptionalFlags - Flags for serializing +/// OverflowingBinaryOperator's SubclassOptionalData contents. +enum OverflowingBinaryOperatorOptionalFlags { + OBO_NO_UNSIGNED_WRAP = 0, + OBO_NO_SIGNED_WRAP = 1 +}; + +/// PossiblyExactOperatorOptionalFlags - Flags for serializing +/// PossiblyExactOperator's SubclassOptionalData contents. +enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 }; + +/// Encoded AtomicOrdering values. +enum AtomicOrderingCodes { + ORDERING_NOTATOMIC = 0, + ORDERING_UNORDERED = 1, + ORDERING_MONOTONIC = 2, + ORDERING_ACQUIRE = 3, + ORDERING_RELEASE = 4, + ORDERING_ACQREL = 5, + ORDERING_SEQCST = 6 +}; + +/// Encoded SynchronizationScope values. +enum AtomicSynchScopeCodes { + SYNCHSCOPE_SINGLETHREAD = 0, + SYNCHSCOPE_CROSSTHREAD = 1 +}; + +/// Markers and flags for call instruction. +enum CallMarkersFlags { + CALL_TAIL = 0, + CALL_CCONV = 1, + CALL_MUSTTAIL = 14, + CALL_EXPLICIT_TYPE = 15, + CALL_NOTAIL = 16, + CALL_FMF = 17 // Call has optional fast-math-flags. +}; + +// The function body block (FUNCTION_BLOCK_ID) describes function bodies. It +// can contain a constant block (CONSTANTS_BLOCK_ID). +enum FunctionCodes { + FUNC_CODE_DECLAREBLOCKS = 1, // DECLAREBLOCKS: [n] + + FUNC_CODE_INST_BINOP = 2, // BINOP: [opcode, ty, opval, opval] + FUNC_CODE_INST_CAST = 3, // CAST: [opcode, ty, opty, opval] + FUNC_CODE_INST_GEP_OLD = 4, // GEP: [n x operands] + FUNC_CODE_INST_SELECT = 5, // SELECT: [ty, opval, opval, opval] + FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opty, opval, opval] + FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [ty, opval, opval, opval] + FUNC_CODE_INST_SHUFFLEVEC = 8, // SHUFFLEVEC: [ty, opval, opval, opval] + FUNC_CODE_INST_CMP = 9, // CMP: [opty, opval, opval, pred] + + FUNC_CODE_INST_RET = 10, // RET: [opty,opval<both optional>] + FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] + FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...] + FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] + // 14 is unused. + FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE + + FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...] + // 17 is unused. + // 18 is unused. + FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [instty, opty, op, align] + FUNC_CODE_INST_LOAD = 20, // LOAD: [opty, op, align, vol] + // 21 is unused. + // 22 is unused. + FUNC_CODE_INST_VAARG = 23, // VAARG: [valistty, valist, instty] + // This store code encodes the pointer type, rather than the value type + // this is so information only available in the pointer type (e.g. address + // spaces) is retained. + FUNC_CODE_INST_STORE_OLD = 24, // STORE: [ptrty,ptr,val, align, vol] + // 25 is unused. + FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands] + FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands] + // fcmp/icmp returning Int1TY or vector of Int1Ty. Same as CMP, exists to + // support legacy vicmp/vfcmp instructions. + FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] + // new select on i1 or [N x i1] + FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] + FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, // INBOUNDS_GEP: [n x operands] + FUNC_CODE_INST_INDIRECTBR = 31, // INDIRECTBR: [opty, op0, op1, ...] + // 32 is unused. + FUNC_CODE_DEBUG_LOC_AGAIN = 33, // DEBUG_LOC_AGAIN + + FUNC_CODE_INST_CALL = 34, // CALL: [attr, cc, fnty, fnid, args...] + + FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] + FUNC_CODE_INST_FENCE = 36, // FENCE: [ordering, synchscope] + FUNC_CODE_INST_CMPXCHG_OLD = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol, + // ordering, synchscope] + FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation, + // align, vol, + // ordering, synchscope] + FUNC_CODE_INST_RESUME = 39, // RESUME: [opval] + FUNC_CODE_INST_LANDINGPAD_OLD = + 40, // LANDINGPAD: [ty,val,val,num,id0,val0...] + FUNC_CODE_INST_LOADATOMIC = 41, // LOAD: [opty, op, align, vol, + // ordering, synchscope] + FUNC_CODE_INST_STOREATOMIC_OLD = 42, // STORE: [ptrty,ptr,val, align, vol + // ordering, synchscope] + FUNC_CODE_INST_GEP = 43, // GEP: [inbounds, n x operands] + FUNC_CODE_INST_STORE = 44, // STORE: [ptrty,ptr,valty,val, align, vol] + FUNC_CODE_INST_STOREATOMIC = 45, // STORE: [ptrty,ptr,val, align, vol + FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align, + // vol,ordering,synchscope] + FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...] + FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#] + FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#] + FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...] + FUNC_CODE_INST_CLEANUPPAD = 51, // CLEANUPPAD: [num,args...] + FUNC_CODE_INST_CATCHSWITCH = + 52, // CATCHSWITCH: [num,args...] or [num,args...,bb] + // 53 is unused. + // 54 is unused. + FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] +}; + +enum UseListCodes { + USELIST_CODE_DEFAULT = 1, // DEFAULT: [index..., value-id] + USELIST_CODE_BB = 2 // BB: [index..., bb-id] +}; + +enum AttributeKindCodes { + // = 0 is unused + ATTR_KIND_ALIGNMENT = 1, + ATTR_KIND_ALWAYS_INLINE = 2, + ATTR_KIND_BY_VAL = 3, + ATTR_KIND_INLINE_HINT = 4, + ATTR_KIND_IN_REG = 5, + ATTR_KIND_MIN_SIZE = 6, + ATTR_KIND_NAKED = 7, + ATTR_KIND_NEST = 8, + ATTR_KIND_NO_ALIAS = 9, + ATTR_KIND_NO_BUILTIN = 10, + ATTR_KIND_NO_CAPTURE = 11, + ATTR_KIND_NO_DUPLICATE = 12, + ATTR_KIND_NO_IMPLICIT_FLOAT = 13, + ATTR_KIND_NO_INLINE = 14, + ATTR_KIND_NON_LAZY_BIND = 15, + ATTR_KIND_NO_RED_ZONE = 16, + ATTR_KIND_NO_RETURN = 17, + ATTR_KIND_NO_UNWIND = 18, + ATTR_KIND_OPTIMIZE_FOR_SIZE = 19, + ATTR_KIND_READ_NONE = 20, + ATTR_KIND_READ_ONLY = 21, + ATTR_KIND_RETURNED = 22, + ATTR_KIND_RETURNS_TWICE = 23, + ATTR_KIND_S_EXT = 24, + ATTR_KIND_STACK_ALIGNMENT = 25, + ATTR_KIND_STACK_PROTECT = 26, + ATTR_KIND_STACK_PROTECT_REQ = 27, + ATTR_KIND_STACK_PROTECT_STRONG = 28, + ATTR_KIND_STRUCT_RET = 29, + ATTR_KIND_SANITIZE_ADDRESS = 30, + ATTR_KIND_SANITIZE_THREAD = 31, + ATTR_KIND_SANITIZE_MEMORY = 32, + ATTR_KIND_UW_TABLE = 33, + ATTR_KIND_Z_EXT = 34, + ATTR_KIND_BUILTIN = 35, + ATTR_KIND_COLD = 36, + ATTR_KIND_OPTIMIZE_NONE = 37, + ATTR_KIND_IN_ALLOCA = 38, + ATTR_KIND_NON_NULL = 39, + ATTR_KIND_JUMP_TABLE = 40, + ATTR_KIND_DEREFERENCEABLE = 41, + ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42, + ATTR_KIND_CONVERGENT = 43, + ATTR_KIND_SAFESTACK = 44, + ATTR_KIND_ARGMEMONLY = 45, + ATTR_KIND_SWIFT_SELF = 46, + ATTR_KIND_SWIFT_ERROR = 47, + ATTR_KIND_NO_RECURSE = 48, + ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, + ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, + ATTR_KIND_ALLOC_SIZE = 51, + ATTR_KIND_WRITEONLY = 52 +}; + +enum ComdatSelectionKindCodes { + COMDAT_SELECTION_KIND_ANY = 1, + COMDAT_SELECTION_KIND_EXACT_MATCH = 2, + COMDAT_SELECTION_KIND_LARGEST = 3, + COMDAT_SELECTION_KIND_NO_DUPLICATES = 4, + COMDAT_SELECTION_KIND_SAME_SIZE = 5, +}; } // End bitc namespace } // End llvm namespace diff --git a/include/llvm/Bitcode/ReaderWriter.h b/include/llvm/Bitcode/ReaderWriter.h index 60d865fd2355..76a60a0b8d25 100644 --- a/include/llvm/Bitcode/ReaderWriter.h +++ b/include/llvm/Bitcode/ReaderWriter.h @@ -15,7 +15,7 @@ #define LLVM_BITCODE_READERWRITER_H #include "llvm/IR/DiagnosticInfo.h" -#include "llvm/IR/FunctionInfo.h" +#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" @@ -30,6 +30,14 @@ namespace llvm { class ModulePass; class raw_ostream; + /// Offsets of the 32-bit fields of bitcode wrapper header. + static const unsigned BWH_MagicField = 0*4; + static const unsigned BWH_VersionField = 1*4; + static const unsigned BWH_OffsetField = 2*4; + static const unsigned BWH_SizeField = 3*4; + static const unsigned BWH_CPUTypeField = 4*4; + static const unsigned BWH_HeaderSize = 5*4; + /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If successful, this moves Buffer. On @@ -52,6 +60,11 @@ namespace llvm { std::string getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context); + /// Return true if \p Buffer contains a bitcode file with ObjC code (category + /// or class) in it. + bool isBitcodeContainingObjCCategory(MemoryBufferRef Buffer, + LLVMContext &Context); + /// Read the header of the specified bitcode buffer and extract just the /// producer string information. If successful, this returns a string. On /// error, this returns "". @@ -62,29 +75,15 @@ namespace llvm { ErrorOr<std::unique_ptr<Module>> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); - /// Check if the given bitcode buffer contains a function summary block. - bool hasFunctionSummary(MemoryBufferRef Buffer, - DiagnosticHandlerFunction DiagnosticHandler); - - /// Parse the specified bitcode buffer, returning the function info index. - /// If IsLazy is true, parse the entire function summary into - /// the index. Otherwise skip the function summary section, and only create - /// an index object with a map from function name to function summary offset. - /// The index is used to perform lazy function summary reading later. - ErrorOr<std::unique_ptr<FunctionInfoIndex>> - getFunctionInfoIndex(MemoryBufferRef Buffer, - DiagnosticHandlerFunction DiagnosticHandler, - bool IsLazy = false); - - /// This method supports lazy reading of function summary data from the - /// combined index during function importing. When reading the combined index - /// file, getFunctionInfoIndex is first invoked with IsLazy=true. - /// Then this method is called for each function considered for importing, - /// to parse the summary information for the given function name into - /// the index. - std::error_code readFunctionSummary( - MemoryBufferRef Buffer, DiagnosticHandlerFunction DiagnosticHandler, - StringRef FunctionName, std::unique_ptr<FunctionInfoIndex> Index); + /// Check if the given bitcode buffer contains a summary block. + bool + hasGlobalValueSummary(MemoryBufferRef Buffer, + const DiagnosticHandlerFunction &DiagnosticHandler); + + /// Parse the specified bitcode buffer, returning the module summary index. + ErrorOr<std::unique_ptr<ModuleSummaryIndex>> + getModuleSummaryIndex(MemoryBufferRef Buffer, + const DiagnosticHandlerFunction &DiagnosticHandler); /// \brief Write the specified module to the specified raw output stream. /// @@ -95,17 +94,21 @@ namespace llvm { /// Value in \c M. These will be reconstructed exactly when \a M is /// deserialized. /// - /// If \c EmitFunctionSummary, emit the function summary index (currently + /// If \c EmitSummaryIndex, emit the module's summary index (currently /// for use in ThinLTO optimization). void WriteBitcodeToFile(const Module *M, raw_ostream &Out, bool ShouldPreserveUseListOrder = false, - bool EmitFunctionSummary = false); + const ModuleSummaryIndex *Index = nullptr, + bool GenerateHash = false); - /// Write the specified function summary index to the given raw output stream, + /// Write the specified module summary index to the given raw output stream, /// where it will be written in a new bitcode block. This is used when - /// writing the combined index file for ThinLTO. - void WriteFunctionSummaryToFile(const FunctionInfoIndex &Index, - raw_ostream &Out); + /// writing the combined index file for ThinLTO. When writing a subset of the + /// index for a distributed backend, provide the \p ModuleToSummariesForIndex + /// map. + void WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, + std::map<std::string, GVSummaryMapTy> + *ModuleToSummariesForIndex = nullptr); /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. @@ -163,20 +166,16 @@ namespace llvm { inline bool SkipBitcodeWrapperHeader(const unsigned char *&BufPtr, const unsigned char *&BufEnd, bool VerifyBufferSize) { - enum { - KnownHeaderSize = 4*4, // Size of header we read. - OffsetField = 2*4, // Offset in bytes to Offset field. - SizeField = 3*4 // Offset in bytes to Size field. - }; - - // Must contain the header! - if (BufEnd-BufPtr < KnownHeaderSize) return true; + // Must contain the offset and size field! + if (unsigned(BufEnd - BufPtr) < BWH_SizeField + 4) + return true; - unsigned Offset = support::endian::read32le(&BufPtr[OffsetField]); - unsigned Size = support::endian::read32le(&BufPtr[SizeField]); + unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); + unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); + uint64_t BitcodeOffsetEnd = (uint64_t)Offset + (uint64_t)Size; // Verify that Offset+Size fits in the file. - if (VerifyBufferSize && Offset+Size > unsigned(BufEnd-BufPtr)) + if (VerifyBufferSize && BitcodeOffsetEnd > uint64_t(BufEnd-BufPtr)) return true; BufPtr += Offset; BufEnd = BufPtr+Size; diff --git a/include/llvm/CodeGen/Analysis.h b/include/llvm/CodeGen/Analysis.h index 38e64ad3be29..2e4dc49a1e26 100644 --- a/include/llvm/CodeGen/Analysis.h +++ b/include/llvm/CodeGen/Analysis.h @@ -17,10 +17,12 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/CodeGen.h" namespace llvm { class GlobalValue; diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index cf29fc9ef889..de618d173573 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -34,6 +34,7 @@ class ConstantArray; class DIE; class DIEAbbrev; class GCMetadataPrinter; +class GlobalIndirectSymbol; class GlobalValue; class GlobalVariable; class MachineBasicBlock; @@ -147,6 +148,8 @@ public: DwarfDebug *getDwarfDebug() { return DD; } DwarfDebug *getDwarfDebug() const { return DD; } + bool isPositionIndependent() const; + /// Return true if assembly output should contain comments. /// bool isVerbose() const { return VerboseAsm; } @@ -238,11 +241,6 @@ public: /// virtual void EmitJumpTableInfo(); - /// Emit the control variable for an emulated TLS variable. - virtual void EmitEmulatedTLSControlVariable(const GlobalVariable *GV, - MCSymbol *EmittedSym, - bool AllZeroInitValue); - /// Emit the specified global variable to the .s file. virtual void EmitGlobalVariable(const GlobalVariable *GV); @@ -551,6 +549,9 @@ private: void EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &C); + /// Emit GlobalAlias or GlobalIFunc. + void emitGlobalIndirectSymbol(Module &M, + const GlobalIndirectSymbol& GIS); }; } diff --git a/include/llvm/CodeGen/BasicTTIImpl.h b/include/llvm/CodeGen/BasicTTIImpl.h index d99054eb6f36..69951afb623c 100644 --- a/include/llvm/CodeGen/BasicTTIImpl.h +++ b/include/llvm/CodeGen/BasicTTIImpl.h @@ -105,6 +105,11 @@ public: /// \name Scalar TTI Implementations /// @{ + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace, + unsigned Alignment, bool *Fast) const { + MVT M = MVT::getIntegerVT(BitWidth); + return getTLI()->allowsMisalignedMemoryAccesses(M, AddressSpace, Alignment, Fast); + } bool hasBranchDivergence() { return false; } @@ -152,6 +157,11 @@ public: return getTLI()->isTypeLegal(VT); } + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef<const Value *> Operands) { + return BaseT::getGEPCost(PointeeType, Ptr, Operands); + } + unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef<const Value *> Arguments) { return BaseT::getIntrinsicCost(IID, RetTy, Arguments); @@ -216,6 +226,8 @@ public: return BaseT::getOperationCost(Opcode, Ty, OpTy); } + unsigned getInliningThresholdMultiplier() { return 1; } + void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP) { // This unrolling functionality is target independent, but to provide some // motivation for its intended use, for x86: @@ -307,12 +319,14 @@ public: } if (!TLI->isOperationExpand(ISD, LT.second)) { - // If the operation is custom lowered then assume - // thare the code is twice as expensive. + // If the operation is custom lowered, then assume that the code is twice + // as expensive. return LT.first * 2 * OpCost; } // Else, assume that we need to scalarize this op. + // TODO: If one of the types get legalized by splitting, handle this + // similarly to what getCastInstrCost() does. if (Ty->isVectorTy()) { unsigned Num = Ty->getVectorNumElements(); unsigned Cost = static_cast<T *>(this) @@ -359,6 +373,11 @@ public: TLI->isZExtFree(SrcLT.second, DstLT.second)) return 0; + if (Opcode == Instruction::AddrSpaceCast && + TLI->isNoopAddrSpaceCast(Src->getPointerAddressSpace(), + Dst->getPointerAddressSpace())) + return 0; + // If the cast is marked as legal (or promote) then assume low cost. if (SrcLT.first == DstLT.first && TLI->isOperationLegalOrPromote(ISD, DstLT.second)) @@ -402,9 +421,25 @@ public: return SrcLT.first * 1; } - // If we are converting vectors and the operation is illegal, or - // if the vectors are legalized to different types, estimate the - // scalarization costs. + // If we are legalizing by splitting, query the concrete TTI for the cost + // of casting the original vector twice. We also need to factor int the + // cost of the split itself. Count that as 1, to be consistent with + // TLI->getTypeLegalizationCost(). + if ((TLI->getTypeAction(Src->getContext(), TLI->getValueType(DL, Src)) == + TargetLowering::TypeSplitVector) || + (TLI->getTypeAction(Dst->getContext(), TLI->getValueType(DL, Dst)) == + TargetLowering::TypeSplitVector)) { + Type *SplitDst = VectorType::get(Dst->getVectorElementType(), + Dst->getVectorNumElements() / 2); + Type *SplitSrc = VectorType::get(Src->getVectorElementType(), + Src->getVectorNumElements() / 2); + T *TTI = static_cast<T *>(this); + return TTI->getVectorSplitCost() + + (2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc)); + } + + // In other cases where the source or destination are illegal, assume + // the operation will get scalarized. unsigned Num = Dst->getVectorNumElements(); unsigned Cost = static_cast<T *>(this)->getCastInstrCost( Opcode, Dst->getScalarType(), Src->getScalarType()); @@ -428,6 +463,14 @@ public: llvm_unreachable("Unhandled cast"); } + unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) { + return static_cast<T *>(this)->getVectorInstrCost( + Instruction::ExtractElement, VecTy, Index) + + static_cast<T *>(this)->getCastInstrCost(Opcode, Dst, + VecTy->getElementType()); + } + unsigned getCFInstrCost(unsigned Opcode) { // Branches are assumed to be predicted. return 0; @@ -454,6 +497,8 @@ public: } // Otherwise, assume that the cast is scalarized. + // TODO: If one of the types get legalized by splitting, handle this + // similarly to what getCastInstrCost() does. if (ValTy->isVectorTy()) { unsigned Num = ValTy->getVectorNumElements(); if (CondTy) @@ -462,8 +507,7 @@ public: Opcode, ValTy->getScalarType(), CondTy); // Return the cost of multiple scalar invocation plus the cost of - // inserting - // and extracting the values. + // inserting and extracting the values. return getScalarizationOverhead(ValTy, true, false) + Num * Cost; } @@ -527,6 +571,51 @@ public: unsigned Cost = static_cast<T *>(this)->getMemoryOpCost( Opcode, VecTy, Alignment, AddressSpace); + // Legalize the vector type, and get the legalized and unlegalized type + // sizes. + MVT VecTyLT = getTLI()->getTypeLegalizationCost(DL, VecTy).second; + unsigned VecTySize = + static_cast<T *>(this)->getDataLayout().getTypeStoreSize(VecTy); + unsigned VecTyLTSize = VecTyLT.getStoreSize(); + + // Return the ceiling of dividing A by B. + auto ceil = [](unsigned A, unsigned B) { return (A + B - 1) / B; }; + + // Scale the cost of the memory operation by the fraction of legalized + // instructions that will actually be used. We shouldn't account for the + // cost of dead instructions since they will be removed. + // + // E.g., An interleaved load of factor 8: + // %vec = load <16 x i64>, <16 x i64>* %ptr + // %v0 = shufflevector %vec, undef, <0, 8> + // + // If <16 x i64> is legalized to 8 v2i64 loads, only 2 of the loads will be + // used (those corresponding to elements [0:1] and [8:9] of the unlegalized + // type). The other loads are unused. + // + // We only scale the cost of loads since interleaved store groups aren't + // allowed to have gaps. + if (Opcode == Instruction::Load && VecTySize > VecTyLTSize) { + + // The number of loads of a legal type it will take to represent a load + // of the unlegalized vector type. + unsigned NumLegalInsts = ceil(VecTySize, VecTyLTSize); + + // The number of elements of the unlegalized type that correspond to a + // single legal instruction. + unsigned NumEltsPerLegalInst = ceil(NumElts, NumLegalInsts); + + // Determine which legal instructions will be used. + BitVector UsedInsts(NumLegalInsts, false); + for (unsigned Index : Indices) + for (unsigned Elt = 0; Elt < NumSubElts; ++Elt) + UsedInsts.set((Index + Elt * Factor) / NumEltsPerLegalInst); + + // Scale the cost of the load by the fraction of legal instructions that + // will be used. + Cost *= UsedInsts.count() / NumLegalInsts; + } + // Then plus the cost of interleave operation. if (Opcode == Instruction::Load) { // The interleave cost is similar to extract sub vectors' elements @@ -582,13 +671,14 @@ public: /// Get intrinsic cost based on arguments unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef<Value *> Args) { + ArrayRef<Value *> Args, FastMathFlags FMF) { switch (IID) { default: { SmallVector<Type *, 4> Types; for (Value *Op : Args) Types.push_back(Op->getType()); - return getIntrinsicInstrCost(IID, RetTy, Types); + return static_cast<T *>(this)->getIntrinsicInstrCost(IID, RetTy, Types, + FMF); } case Intrinsic::masked_scatter: { Value *Mask = Args[3]; @@ -614,8 +704,9 @@ public: /// Get intrinsic cost based on argument types unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef<Type *> Tys) { - unsigned ISD = 0; + ArrayRef<Type *> Tys, FastMathFlags FMF) { + SmallVector<unsigned, 2> ISDs; + unsigned SingleCallCost = 10; // Library call cost. Make it expensive. switch (IID) { default: { // Assume that we need to scalarize this intrinsic. @@ -641,74 +732,78 @@ public: return 1; // Return cost of a scalar intrinsic. Assume it to be cheap. unsigned ScalarCost = static_cast<T *>(this)->getIntrinsicInstrCost( - IID, ScalarRetTy, ScalarTys); + IID, ScalarRetTy, ScalarTys, FMF); return ScalarCalls * ScalarCost + ScalarizationCost; } // Look for intrinsics that can be lowered directly or turned into a scalar // intrinsic call. case Intrinsic::sqrt: - ISD = ISD::FSQRT; + ISDs.push_back(ISD::FSQRT); break; case Intrinsic::sin: - ISD = ISD::FSIN; + ISDs.push_back(ISD::FSIN); break; case Intrinsic::cos: - ISD = ISD::FCOS; + ISDs.push_back(ISD::FCOS); break; case Intrinsic::exp: - ISD = ISD::FEXP; + ISDs.push_back(ISD::FEXP); break; case Intrinsic::exp2: - ISD = ISD::FEXP2; + ISDs.push_back(ISD::FEXP2); break; case Intrinsic::log: - ISD = ISD::FLOG; + ISDs.push_back(ISD::FLOG); break; case Intrinsic::log10: - ISD = ISD::FLOG10; + ISDs.push_back(ISD::FLOG10); break; case Intrinsic::log2: - ISD = ISD::FLOG2; + ISDs.push_back(ISD::FLOG2); break; case Intrinsic::fabs: - ISD = ISD::FABS; + ISDs.push_back(ISD::FABS); break; case Intrinsic::minnum: - ISD = ISD::FMINNUM; + ISDs.push_back(ISD::FMINNUM); + if (FMF.noNaNs()) + ISDs.push_back(ISD::FMINNAN); break; case Intrinsic::maxnum: - ISD = ISD::FMAXNUM; + ISDs.push_back(ISD::FMAXNUM); + if (FMF.noNaNs()) + ISDs.push_back(ISD::FMAXNAN); break; case Intrinsic::copysign: - ISD = ISD::FCOPYSIGN; + ISDs.push_back(ISD::FCOPYSIGN); break; case Intrinsic::floor: - ISD = ISD::FFLOOR; + ISDs.push_back(ISD::FFLOOR); break; case Intrinsic::ceil: - ISD = ISD::FCEIL; + ISDs.push_back(ISD::FCEIL); break; case Intrinsic::trunc: - ISD = ISD::FTRUNC; + ISDs.push_back(ISD::FTRUNC); break; case Intrinsic::nearbyint: - ISD = ISD::FNEARBYINT; + ISDs.push_back(ISD::FNEARBYINT); break; case Intrinsic::rint: - ISD = ISD::FRINT; + ISDs.push_back(ISD::FRINT); break; case Intrinsic::round: - ISD = ISD::FROUND; + ISDs.push_back(ISD::FROUND); break; case Intrinsic::pow: - ISD = ISD::FPOW; + ISDs.push_back(ISD::FPOW); break; case Intrinsic::fma: - ISD = ISD::FMA; + ISDs.push_back(ISD::FMA); break; case Intrinsic::fmuladd: - ISD = ISD::FMA; + ISDs.push_back(ISD::FMA); break; // FIXME: We should return 0 whenever getIntrinsicCost == TCC_Free. case Intrinsic::lifetime_start: @@ -720,27 +815,49 @@ public: case Intrinsic::masked_load: return static_cast<T *>(this) ->getMaskedMemoryOpCost(Instruction::Load, RetTy, 0, 0); + case Intrinsic::ctpop: + ISDs.push_back(ISD::CTPOP); + // In case of legalization use TCC_Expensive. This is cheaper than a + // library call but still not a cheap instruction. + SingleCallCost = TargetTransformInfo::TCC_Expensive; + break; + // FIXME: ctlz, cttz, ... } const TargetLoweringBase *TLI = getTLI(); std::pair<unsigned, MVT> LT = TLI->getTypeLegalizationCost(DL, RetTy); - if (TLI->isOperationLegalOrPromote(ISD, LT.second)) { - // The operation is legal. Assume it costs 1. - // If the type is split to multiple registers, assume that there is some - // overhead to this. - // TODO: Once we have extract/insert subvector cost we need to use them. - if (LT.first > 1) - return LT.first * 2; - return LT.first * 1; - } + SmallVector<unsigned, 2> LegalCost; + SmallVector<unsigned, 2> CustomCost; + for (unsigned ISD : ISDs) { + if (TLI->isOperationLegalOrPromote(ISD, LT.second)) { + if (IID == Intrinsic::fabs && TLI->isFAbsFree(LT.second)) { + return 0; + } - if (!TLI->isOperationExpand(ISD, LT.second)) { - // If the operation is custom lowered then assume - // thare the code is twice as expensive. - return LT.first * 2; + // The operation is legal. Assume it costs 1. + // If the type is split to multiple registers, assume that there is some + // overhead to this. + // TODO: Once we have extract/insert subvector cost we need to use them. + if (LT.first > 1) + LegalCost.push_back(LT.first * 2); + else + LegalCost.push_back(LT.first * 1); + } else if (!TLI->isOperationExpand(ISD, LT.second)) { + // If the operation is custom lowered then assume + // that the code is twice as expensive. + CustomCost.push_back(LT.first * 2); + } } + auto MinLegalCostI = std::min_element(LegalCost.begin(), LegalCost.end()); + if (MinLegalCostI != LegalCost.end()) + return *MinLegalCostI; + + auto MinCustomCostI = std::min_element(CustomCost.begin(), CustomCost.end()); + if (MinCustomCostI != CustomCost.end()) + return *MinCustomCostI; + // If we can't lower fmuladd into an FMA estimate the cost as a floating // point mul followed by an add. if (IID == Intrinsic::fmuladd) @@ -763,7 +880,7 @@ public: ScalarTys.push_back(Ty); } unsigned ScalarCost = static_cast<T *>(this)->getIntrinsicInstrCost( - IID, RetTy->getScalarType(), ScalarTys); + IID, RetTy->getScalarType(), ScalarTys, FMF); for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) { if (Tys[i]->isVectorTy()) { ScalarizationCost += getScalarizationOverhead(Tys[i], false, true); @@ -775,7 +892,7 @@ public: } // This is going to be turned into a library call, make it expensive. - return 10; + return SingleCallCost; } /// \brief Compute a cost of the given call instruction. @@ -815,6 +932,8 @@ public: return ShuffleCost + ArithCost + getScalarizationOverhead(Ty, false, true); } + unsigned getVectorSplitCost() { return 1; } + /// @} }; diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 415abb90da57..92e58564e040 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -195,6 +195,7 @@ class CCState { private: CallingConv::ID CallingConv; bool IsVarArg; + bool AnalyzingMustTailForwardedRegs = false; MachineFunction &MF; const TargetRegisterInfo &TRI; SmallVectorImpl<CCValAssign> &Locs; @@ -281,7 +282,7 @@ public: /// be able to store all arguments and such that the alignment requirement /// of each of the arguments is satisfied. unsigned getAlignedCallFrameSize() const { - return RoundUpToAlignment(StackOffset, MaxStackArgAlign); + return alignTo(StackOffset, MaxStackArgAlign); } /// isAllocated - Return true if the specified register (or an alias) is @@ -412,14 +413,19 @@ public: /// and alignment. unsigned AllocateStack(unsigned Size, unsigned Align) { assert(Align && ((Align - 1) & Align) == 0); // Align is power of 2. - StackOffset = RoundUpToAlignment(StackOffset, Align); + StackOffset = alignTo(StackOffset, Align); unsigned Result = StackOffset; StackOffset += Size; MaxStackArgAlign = std::max(Align, MaxStackArgAlign); - MF.getFrameInfo()->ensureMaxAlignment(Align); + ensureMaxAlignment(Align); return Result; } + void ensureMaxAlignment(unsigned Align) { + if (!AnalyzingMustTailForwardedRegs) + MF.getFrameInfo()->ensureMaxAlignment(Align); + } + /// Version of AllocateStack with extra register to be shadowed. unsigned AllocateStack(unsigned Size, unsigned Align, unsigned ShadowReg) { MarkAllocated(ShadowReg); @@ -507,6 +513,14 @@ public: SmallVectorImpl<ForwardedRegister> &Forwards, ArrayRef<MVT> RegParmTypes, CCAssignFn Fn); + /// Returns true if the results of the two calling conventions are compatible. + /// This is usually part of the check for tailcall eligibility. + static bool resultsCompatible(CallingConv::ID CalleeCC, + CallingConv::ID CallerCC, MachineFunction &MF, + LLVMContext &C, + const SmallVectorImpl<ISD::InputArg> &Ins, + CCAssignFn CalleeFn, CCAssignFn CallerFn); + private: /// MarkAllocated - Mark a register and all of its aliases as allocated. void MarkAllocated(unsigned Reg); diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h index 0d37dc00422f..6376c06768b3 100644 --- a/include/llvm/CodeGen/CommandFlags.h +++ b/include/llvm/CodeGen/CommandFlags.h @@ -46,20 +46,23 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); -cl::opt<Reloc::Model> -RelocModel("relocation-model", - cl::desc("Choose relocation model"), - cl::init(Reloc::Default), - cl::values( - clEnumValN(Reloc::Default, "default", - "Target default relocation model"), - clEnumValN(Reloc::Static, "static", - "Non-relocatable code"), - clEnumValN(Reloc::PIC_, "pic", - "Fully relocatable, position independent code"), - clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", - "Relocatable external references, non-relocatable code"), - clEnumValEnd)); +cl::opt<Reloc::Model> RelocModel( + "relocation-model", cl::desc("Choose relocation model"), + cl::values( + clEnumValN(Reloc::Static, "static", "Non-relocatable code"), + clEnumValN(Reloc::PIC_, "pic", + "Fully relocatable, position independent code"), + clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", + "Relocatable external references, non-relocatable code"), + clEnumValEnd)); + +static inline Optional<Reloc::Model> getRelocModel() { + if (RelocModel.getNumOccurrences()) { + Reloc::Model R = RelocModel; + return R; + } + return None; +} cl::opt<ThreadModel::Model> TMModel("thread-model", @@ -87,6 +90,22 @@ CMModel("code-model", "Large code model"), clEnumValEnd)); +cl::opt<llvm::ExceptionHandling> +ExceptionModel("exception-model", + cl::desc("exception model"), + cl::init(ExceptionHandling::None), + cl::values(clEnumValN(ExceptionHandling::None, "default", + "default exception handling model"), + clEnumValN(ExceptionHandling::DwarfCFI, "dwarf", + "DWARF-like CFI based exception handling"), + clEnumValN(ExceptionHandling::SjLj, "sjlj", + "SjLj exception handling"), + clEnumValN(ExceptionHandling::ARM, "arm", + "ARM EHABI exceptions"), + clEnumValN(ExceptionHandling::WinEH, "wineh", + "Windows exception model"), + clEnumValEnd)); + cl::opt<TargetMachine::CodeGenFileType> FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), cl::desc("Choose a file type (not all types are supported by all targets):"), @@ -177,6 +196,11 @@ DisableTailCalls("disable-tail-calls", cl::desc("Never emit tail calls"), cl::init(false)); +cl::opt<bool> +StackSymbolOrdering("stack-symbol-ordering", + cl::desc("Order local stack symbols."), + cl::init(true)); + cl::opt<unsigned> OverrideStackAlignment("stack-alignment", cl::desc("Override default stack alignment"), @@ -193,11 +217,6 @@ TrapFuncName("trap-func", cl::Hidden, cl::init("")); cl::opt<bool> -EnablePIE("enable-pie", - cl::desc("Assume the creation of a position independent executable."), - cl::init(false)); - -cl::opt<bool> UseCtors("use-ctors", cl::desc("Use .ctors instead of .init_array."), cl::init(false)); @@ -211,10 +230,6 @@ cl::opt<std::string> StartAfter("start-after", cl::value_desc("pass-name"), cl::init("")); -cl::opt<std::string> - RunPass("run-pass", cl::desc("Run compiler only for one specific pass"), - cl::value_desc("pass-name"), cl::init("")); - cl::opt<bool> DataSections("data-sections", cl::desc("Emit data into separate sections"), cl::init(false)); @@ -284,12 +299,13 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() { Options.NoZerosInBSS = DontPlaceZerosInBSS; Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.PositionIndependentExecutable = EnablePIE; + Options.StackSymbolOrdering = StackSymbolOrdering; Options.UseInitArray = !UseCtors; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Options.EmulatedTLS = EmulatedTLS; + Options.ExceptionModel = ExceptionModel; Options.MCOptions = InitMCTargetOptionsFromFlags(); Options.JTType = JTableType; diff --git a/include/llvm/CodeGen/DFAPacketizer.h b/include/llvm/CodeGen/DFAPacketizer.h index 40ec201107e8..8de140e91bf3 100644 --- a/include/llvm/CodeGen/DFAPacketizer.h +++ b/include/llvm/CodeGen/DFAPacketizer.h @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/ScheduleDAGMutation.h" #include <map> namespace llvm { @@ -80,7 +81,7 @@ private: // CachedTable is a map from <FromState, Input> to ToState. DenseMap<UnsignPair, unsigned> CachedTable; - // ReadTable - Read the DFA transition table and update CachedTable. + // Read the DFA transition table and update CachedTable. void ReadTable(unsigned state); public: @@ -92,38 +93,39 @@ public: CurrentState = 0; } - // getInsnInput - Return the DFAInput for an instruction class. + // Return the DFAInput for an instruction class. DFAInput getInsnInput(unsigned InsnClass); - // getInsnInput - Return the DFAInput for an instruction class input vector. + // Return the DFAInput for an instruction class input vector. static DFAInput getInsnInput(const std::vector<unsigned> &InsnClass); - // canReserveResources - Check if the resources occupied by a MCInstrDesc - // are available in the current state. + // Check if the resources occupied by a MCInstrDesc are available in + // the current state. bool canReserveResources(const llvm::MCInstrDesc *MID); - // reserveResources - Reserve the resources occupied by a MCInstrDesc and - // change the current state to reflect that change. + // Reserve the resources occupied by a MCInstrDesc and change the current + // state to reflect that change. void reserveResources(const llvm::MCInstrDesc *MID); - // canReserveResources - Check if the resources occupied by a machine - // instruction are available in the current state. - bool canReserveResources(llvm::MachineInstr *MI); + // Check if the resources occupied by a machine instruction are available + // in the current state. + bool canReserveResources(llvm::MachineInstr &MI); - // reserveResources - Reserve the resources occupied by a machine - // instruction and change the current state to reflect that change. - void reserveResources(llvm::MachineInstr *MI); + // Reserve the resources occupied by a machine instruction and change the + // current state to reflect that change. + void reserveResources(llvm::MachineInstr &MI); const InstrItineraryData *getInstrItins() const { return InstrItins; } }; -// VLIWPacketizerList - Implements a simple VLIW packetizer using DFA. The -// packetizer works on machine basic blocks. For each instruction I in BB, the -// packetizer consults the DFA to see if machine resources are available to -// execute I. If so, the packetizer checks if I depends on any instruction J in -// the current packet. If no dependency is found, I is added to current packet -// and machine resource is marked as taken. If any dependency is found, a target -// API call is made to prune the dependence. + +// VLIWPacketizerList implements a simple VLIW packetizer using DFA. The +// packetizer works on machine basic blocks. For each instruction I in BB, +// the packetizer consults the DFA to see if machine resources are available +// to execute I. If so, the packetizer checks if I depends on any instruction +// in the current packet. If no dependency is found, I is added to current +// packet and the machine resource is marked as taken. If any dependency is +// found, a target API call is made to prune the dependence. class VLIWPacketizerList { protected: MachineFunction &MF; @@ -132,13 +134,11 @@ protected: // The VLIW Scheduler. DefaultVLIWScheduler *VLIWScheduler; - // Vector of instructions assigned to the current packet. std::vector<MachineInstr*> CurrentPacketMIs; // DFA resource tracker. DFAPacketizer *ResourceTracker; - - // Generate MI -> SU map. + // Map: MI -> SU. std::map<MachineInstr*, SUnit*> MIToSUnit; public: @@ -148,43 +148,40 @@ public: virtual ~VLIWPacketizerList(); - // PacketizeMIs - Implement this API in the backend to bundle instructions. + // Implement this API in the backend to bundle instructions. void PacketizeMIs(MachineBasicBlock *MBB, MachineBasicBlock::iterator BeginItr, MachineBasicBlock::iterator EndItr); - // getResourceTracker - return ResourceTracker + // Return the ResourceTracker. DFAPacketizer *getResourceTracker() {return ResourceTracker;} // addToPacket - Add MI to the current packet. - virtual MachineBasicBlock::iterator addToPacket(MachineInstr *MI) { - MachineBasicBlock::iterator MII = MI; - CurrentPacketMIs.push_back(MI); + virtual MachineBasicBlock::iterator addToPacket(MachineInstr &MI) { + CurrentPacketMIs.push_back(&MI); ResourceTracker->reserveResources(MI); - return MII; + return MI; } // End the current packet and reset the state of the packetizer. // Overriding this function allows the target-specific packetizer // to perform custom finalization. - virtual void endPacket(MachineBasicBlock *MBB, MachineInstr *MI); + virtual void endPacket(MachineBasicBlock *MBB, + MachineBasicBlock::iterator MI); - // initPacketizerState - perform initialization before packetizing - // an instruction. This function is supposed to be overrided by - // the target dependent packetizer. - virtual void initPacketizerState() { return; } + // Perform initialization before packetizing an instruction. This + // function is supposed to be overrided by the target dependent packetizer. + virtual void initPacketizerState() {} - // ignorePseudoInstruction - Ignore bundling of pseudo instructions. - virtual bool ignorePseudoInstruction(const MachineInstr *I, + // Check if the given instruction I should be ignored by the packetizer. + virtual bool ignorePseudoInstruction(const MachineInstr &I, const MachineBasicBlock *MBB) { return false; } - // isSoloInstruction - return true if instruction MI can not be packetized - // with any other instruction, which means that MI itself is a packet. - virtual bool isSoloInstruction(const MachineInstr *MI) { - return true; - } + // Return true if instruction MI can not be packetized with any other + // instruction, which means that MI itself is a packet. + virtual bool isSoloInstruction(const MachineInstr &MI) { return true; } // Check if the packetizer should try to add the given instruction to // the current packet. One reasons for which it may not be desirable @@ -192,23 +189,22 @@ public: // would cause a stall. // If this function returns "false", the current packet will be ended, // and the instruction will be added to the next packet. - virtual bool shouldAddToPacket(const MachineInstr *MI) { - return true; - } + virtual bool shouldAddToPacket(const MachineInstr &MI) { return true; } - // isLegalToPacketizeTogether - Is it legal to packetize SUI and SUJ - // together. + // Check if it is legal to packetize SUI and SUJ together. virtual bool isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) { return false; } - // isLegalToPruneDependencies - Is it legal to prune dependece between SUI - // and SUJ. + // Check if it is legal to prune dependece between SUI and SUJ. virtual bool isLegalToPruneDependencies(SUnit *SUI, SUnit *SUJ) { return false; } + // Add a DAG mutation to be done before the packetization begins. + void addMutation(std::unique_ptr<ScheduleDAGMutation> Mutation); }; -} + +} // namespace llvm #endif diff --git a/include/llvm/CodeGen/DIE.h b/include/llvm/CodeGen/DIE.h index 72b3adc7de99..7d6e66fa6ec2 100644 --- a/include/llvm/CodeGen/DIE.h +++ b/include/llvm/CodeGen/DIE.h @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/Support/Dwarf.h" -#include <vector> namespace llvm { class AsmPrinter; @@ -29,48 +28,6 @@ class MCSymbol; class raw_ostream; class DwarfTypeUnit; -// AsmStreamerBase - A base abstract interface class defines methods that -// can be implemented to stream objects or can be implemented to -// calculate the size of the streamed objects. -// The derived classes will use an AsmPrinter to implement the methods. -// -// TODO: complete this interface and use it to merge EmitValue and SizeOf -// methods in the DIE classes below. -class AsmStreamerBase { -protected: - const AsmPrinter *AP; - AsmStreamerBase(const AsmPrinter *AP) : AP(AP) {} - -public: - virtual ~AsmStreamerBase() {} - virtual unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, - unsigned PadTo = 0) = 0; - virtual unsigned emitInt8(unsigned char Value) = 0; - virtual unsigned emitBytes(StringRef Data) = 0; -}; - -/// EmittingAsmStreamer - Implements AbstractAsmStreamer to stream objects. -/// Notice that the return value is not the actual size of the streamed object. -/// For size calculation use SizeReporterAsmStreamer. -class EmittingAsmStreamer : public AsmStreamerBase { -public: - EmittingAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {} - unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, - unsigned PadTo = 0) override; - unsigned emitInt8(unsigned char Value) override; - unsigned emitBytes(StringRef Data) override; -}; - -/// SizeReporterAsmStreamer - Only reports the size of the streamed objects. -class SizeReporterAsmStreamer : public AsmStreamerBase { -public: - SizeReporterAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {} - unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, - unsigned PadTo = 0) override; - unsigned emitInt8(unsigned char Value) override; - unsigned emitBytes(StringRef Data) override; -}; - //===--------------------------------------------------------------------===// /// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a /// Dwarf abbreviation. @@ -286,25 +243,6 @@ public: }; //===--------------------------------------------------------------------===// -/// \brief A signature reference to a type unit. -class DIETypeSignature { - const DwarfTypeUnit *Unit; - - DIETypeSignature() = delete; - -public: - explicit DIETypeSignature(const DwarfTypeUnit &Unit) : Unit(&Unit) {} - - void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const; - unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - assert(Form == dwarf::DW_FORM_ref_sig8); - return 8; - } - - void print(raw_ostream &O) const; -}; - -//===--------------------------------------------------------------------===// /// DIELocList - Represents a pointer to a location list in the debug_loc /// section. // @@ -350,8 +288,9 @@ private: /// All values that aren't standard layout (or are larger than 8 bytes) /// should be stored by reference instead of by value. typedef AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel, - DIEDelta *, DIEEntry, DIETypeSignature, - DIEBlock *, DIELoc *, DIELocList> ValTy; + DIEDelta *, DIEEntry, DIEBlock *, DIELoc *, + DIELocList> + ValTy; static_assert(sizeof(ValTy) <= sizeof(uint64_t) || sizeof(ValTy) <= sizeof(void *), "Expected all large types to be stored via pointer"); @@ -626,7 +565,7 @@ public: typedef iterator_range<value_iterator> value_range; typedef iterator_range<const_value_iterator> const_value_range; - value_iterator addValue(BumpPtrAllocator &Alloc, DIEValue V) { + value_iterator addValue(BumpPtrAllocator &Alloc, const DIEValue &V) { List.push_back(*new (Alloc) Node(V)); return value_iterator(ListTy::toIterator(List.back())); } diff --git a/include/llvm/CodeGen/DIEValue.def b/include/llvm/CodeGen/DIEValue.def index 2cfae7b608c6..c5ff4010b2e4 100644 --- a/include/llvm/CodeGen/DIEValue.def +++ b/include/llvm/CodeGen/DIEValue.def @@ -37,7 +37,6 @@ HANDLE_DIEVALUE_SMALL(Expr) HANDLE_DIEVALUE_SMALL(Label) HANDLE_DIEVALUE_LARGE(Delta) HANDLE_DIEVALUE_SMALL(Entry) -HANDLE_DIEVALUE_SMALL(TypeSignature) HANDLE_DIEVALUE_LARGE(Block) HANDLE_DIEVALUE_LARGE(Loc) HANDLE_DIEVALUE_SMALL(LocList) diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index cc4e37059bb8..4bff48de38e4 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -16,7 +16,6 @@ #define LLVM_CODEGEN_FASTISEL_H #include "llvm/ADT/DenseMap.h" -#include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/IntrinsicInst.h" @@ -24,6 +23,8 @@ namespace llvm { +class MachineConstantPool; + /// \brief This is a fast-path instruction selection class that generates poor /// code and doesn't support illegal types or non-trivial lowering, but runs /// quickly. @@ -40,12 +41,15 @@ public: bool IsByVal : 1; bool IsInAlloca : 1; bool IsReturned : 1; + bool IsSwiftSelf : 1; + bool IsSwiftError : 1; uint16_t Alignment; ArgListEntry() : Val(nullptr), Ty(nullptr), IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false), - IsInAlloca(false), IsReturned(false), Alignment(0) {} + IsInAlloca(false), IsReturned(false), IsSwiftSelf(false), + IsSwiftError(false), Alignment(0) {} /// \brief Set CallLoweringInfo attribute flags based on a call instruction /// and called function attributes. @@ -448,7 +452,7 @@ protected: /// \brief Emit an unconditional branch to the given block, unless it is the /// immediate (fall-through) successor, and update the CFG. - void fastEmitBranch(MachineBasicBlock *MBB, DebugLoc DL); + void fastEmitBranch(MachineBasicBlock *MBB, const DebugLoc &DL); /// Emit an unconditional branch to \p FalseMBB, obtains the branch weight /// and adds TrueMBB and FalseMBB to the successor list. diff --git a/include/llvm/CodeGen/FaultMaps.h b/include/llvm/CodeGen/FaultMaps.h index f4b646322143..9b5a3e1ba050 100644 --- a/include/llvm/CodeGen/FaultMaps.h +++ b/include/llvm/CodeGen/FaultMaps.h @@ -10,7 +10,6 @@ #ifndef LLVM_CODEGEN_FAULTMAPS_H #define LLVM_CODEGEN_FAULTMAPS_H -#include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index 09a9991912da..010e34179efc 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -72,6 +72,37 @@ public: /// MBBMap - A mapping from LLVM basic blocks to their machine code entry. DenseMap<const BasicBlock*, MachineBasicBlock *> MBBMap; + typedef SmallVector<unsigned, 1> SwiftErrorVRegs; + typedef SmallVector<const Value*, 1> SwiftErrorValues; + /// A function can only have a single swifterror argument. And if it does + /// have a swifterror argument, it must be the first entry in + /// SwiftErrorVals. + SwiftErrorValues SwiftErrorVals; + + /// Track the virtual register for each swifterror value in a given basic + /// block. Entries in SwiftErrorVRegs have the same ordering as entries + /// in SwiftErrorVals. + /// Note that another choice that is more straight-forward is to use + /// Map<const MachineBasicBlock*, Map<Value*, unsigned/*VReg*/>>. It + /// maintains a map from swifterror values to virtual registers for each + /// machine basic block. This choice does not require a one-to-one + /// correspondence between SwiftErrorValues and SwiftErrorVRegs. But because + /// of efficiency concern, we do not choose it. + llvm::DenseMap<const MachineBasicBlock*, SwiftErrorVRegs> SwiftErrorMap; + + /// Track the virtual register for each swifterror value at the end of a basic + /// block when we need the assignment of a virtual register before the basic + /// block is visited. When we actually visit the basic block, we will make + /// sure the swifterror value is in the correct virtual register. + llvm::DenseMap<const MachineBasicBlock*, SwiftErrorVRegs> + SwiftErrorWorklist; + + /// Find the swifterror virtual register in SwiftErrorMap. We will assert + /// failure when the value does not exist in swifterror map. + unsigned findSwiftErrorVReg(const MachineBasicBlock*, const Value*) const; + /// Set the swifterror virtual register in SwiftErrorMap. + void setSwiftErrorVReg(const MachineBasicBlock *MBB, const Value*, unsigned); + /// ValueMap - Since we emit code for the function a basic block at a time, /// we must remember which virtual registers hold the values for /// cross-basic-block values. @@ -80,15 +111,36 @@ public: /// Track virtual registers created for exception pointers. DenseMap<const Value *, unsigned> CatchPadExceptionPointers; - // Keep track of frame indices allocated for statepoints as they could be used - // across basic block boundaries. - // Key of the map is statepoint instruction, value is a map from spilled - // llvm Value to the optional stack stack slot index. - // If optional is unspecified it means that we have visited this value - // but didn't spill it. - typedef DenseMap<const Value*, Optional<int>> StatepointSpilledValueMapTy; - DenseMap<const Instruction*, StatepointSpilledValueMapTy> - StatepointRelocatedValues; + /// Keep track of frame indices allocated for statepoints as they could be + /// used across basic block boundaries. This struct is more complex than a + /// simple map because the stateopint lowering code de-duplicates gc pointers + /// based on their SDValue (so %p and (bitcast %p to T) will get the same + /// slot), and we track that here. + + struct StatepointSpillMap { + typedef DenseMap<const Value *, Optional<int>> SlotMapTy; + + /// Maps uniqued llvm IR values to the slots they were spilled in. If a + /// value is mapped to None it means we visited the value but didn't spill + /// it (because it was a constant, for instance). + SlotMapTy SlotMap; + + /// Maps llvm IR values to the values they were de-duplicated to. + DenseMap<const Value *, const Value *> DuplicateMap; + + SlotMapTy::const_iterator find(const Value *V) const { + auto DuplIt = DuplicateMap.find(V); + if (DuplIt != DuplicateMap.end()) + V = DuplIt->second; + return SlotMap.find(V); + } + + SlotMapTy::const_iterator end() const { return SlotMap.end(); } + }; + + /// Maps gc.statepoint instructions to their corresponding StatepointSpillMap + /// instances. + DenseMap<const Instruction *, StatepointSpillMap> StatepointSpillMaps; /// StaticAllocaMap - Keep track of frame indices for fixed sized allocas in /// the entry block. This allows the allocas to be efficiently referenced @@ -119,7 +171,7 @@ public: struct LiveOutInfo { unsigned NumSignBits : 31; - bool IsValid : 1; + unsigned IsValid : 1; APInt KnownOne, KnownZero; LiveOutInfo() : NumSignBits(0), IsValid(true), KnownOne(1, 0), KnownZero(1, 0) {} diff --git a/include/llvm/CodeGen/GCMetadata.h b/include/llvm/CodeGen/GCMetadata.h index 163117b0781c..e6afcbc8ded2 100644 --- a/include/llvm/CodeGen/GCMetadata.h +++ b/include/llvm/CodeGen/GCMetadata.h @@ -40,6 +40,7 @@ #include "llvm/IR/DebugLoc.h" #include "llvm/Pass.h" #include <memory> +#include <utility> namespace llvm { class AsmPrinter; @@ -54,7 +55,7 @@ struct GCPoint { DebugLoc Loc; GCPoint(GC::PointKind K, MCSymbol *L, DebugLoc DL) - : Kind(K), Label(L), Loc(DL) {} + : Kind(K), Label(L), Loc(std::move(DL)) {} }; /// GCRoot - Metadata for a pointer to an object managed by the garbage @@ -120,7 +121,7 @@ public: /// addSafePoint - Notes the existence of a safe point. Num is the ID of the /// label just prior to the safe point (if the code generator is using /// MachineModuleInfo). - void addSafePoint(GC::PointKind Kind, MCSymbol *Label, DebugLoc DL) { + void addSafePoint(GC::PointKind Kind, MCSymbol *Label, const DebugLoc &DL) { SafePoints.emplace_back(Kind, Label, DL); } diff --git a/include/llvm/CodeGen/GlobalISel/CallLowering.h b/include/llvm/CodeGen/GlobalISel/CallLowering.h new file mode 100644 index 000000000000..bbd0b6d88593 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/CallLowering.h @@ -0,0 +1,72 @@ +//===-- llvm/CodeGen/GlobalISel/CallLowering.h - Call lowering --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes how to lower LLVM calls to machine code calls. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H +#define LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Function.h" + +namespace llvm { +// Forward declarations. +class MachineIRBuilder; +class TargetLowering; +class Value; + +class CallLowering { + const TargetLowering *TLI; + protected: + /// Getter for generic TargetLowering class. + const TargetLowering *getTLI() const { + return TLI; + } + + /// Getter for target specific TargetLowering class. + template <class XXXTargetLowering> + const XXXTargetLowering *getTLI() const { + return static_cast<const XXXTargetLowering *>(TLI); + } + public: + CallLowering(const TargetLowering *TLI) : TLI(TLI) {} + virtual ~CallLowering() {} + + /// This hook must be implemented to lower outgoing return values, described + /// by \p Val, into the specified virtual register \p VReg. + /// This hook is used by GlobalISel. + /// + /// \return True if the lowering succeeds, false otherwise. + virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, + unsigned VReg) const { + return false; + } + + /// This hook must be implemented to lower the incoming (formal) + /// arguments, described by \p Args, for GlobalISel. Each argument + /// must end up in the related virtual register described by VRegs. + /// In other words, the first argument should end up in VRegs[0], + /// the second in VRegs[1], and so on. + /// \p MIRBuilder is set to the proper insertion for the argument + /// lowering. + /// + /// \return True if the lowering succeeded, false otherwise. + virtual bool + lowerFormalArguments(MachineIRBuilder &MIRBuilder, + const Function::ArgumentListType &Args, + const SmallVectorImpl<unsigned> &VRegs) const { + return false; + } +}; +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/GISelAccessor.h b/include/llvm/CodeGen/GlobalISel/GISelAccessor.h new file mode 100644 index 000000000000..7c5ec9f3adc0 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/GISelAccessor.h @@ -0,0 +1,33 @@ +//===-- GISelAccessor.h - GISel Accessor ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// This file declares the API to access the various APIs related +/// to GlobalISel. +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_CODEGEN_GLOBALISEL_GISELACCESSOR_H +#define LLVM_CODEGEN_GLOBALISEL_GISELACCESSOR_H + +namespace llvm { +class CallLowering; +class RegisterBankInfo; + +/// The goal of this helper class is to gather the accessor to all +/// the APIs related to GlobalISel. +/// It should be derived to feature an actual accessor to the GISel APIs. +/// The reason why this is not simply done into the subtarget is to avoid +/// spreading ifdefs around. +struct GISelAccessor { + virtual ~GISelAccessor() {} + virtual const CallLowering *getCallLowering() const { return nullptr;} + virtual const RegisterBankInfo *getRegBankInfo() const { return nullptr;} +}; +} // End namespace llvm; +#endif diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h new file mode 100644 index 000000000000..833e87493cad --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -0,0 +1,158 @@ +//===-- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares the IRTranslator pass. +/// This pass is responsible for translating LLVM IR into MachineInstr. +/// It uses target hooks to lower the ABI but aside from that, the pass +/// generated code is generic. This is the default translator used for +/// GlobalISel. +/// +/// \todo Replace the comments with actual doxygen comments. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H +#define LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H + +#include "Types.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { +// Forward declarations. +class BasicBlock; +class CallLowering; +class Constant; +class Instruction; +class MachineBasicBlock; +class MachineFunction; +class MachineInstr; +class MachineRegisterInfo; + +// Technically the pass should run on an hypothetical MachineModule, +// since it should translate Global into some sort of MachineGlobal. +// The MachineGlobal should ultimately just be a transfer of ownership of +// the interesting bits that are relevant to represent a global value. +// That being said, we could investigate what would it cost to just duplicate +// the information from the LLVM IR. +// The idea is that ultimately we would be able to free up the memory used +// by the LLVM IR as soon as the translation is over. +class IRTranslator : public MachineFunctionPass { +public: + static char ID; + +private: + /// Interface used to lower the everything related to calls. + const CallLowering *CLI; + /// Mapping of the values of the current LLVM IR function + /// to the related virtual registers. + ValueToVReg ValToVReg; + // Constants are special because when we encounter one, + // we do not know at first where to insert the definition since + // this depends on all its uses. + // Thus, we will insert the sequences to materialize them when + // we know all their users. + // In the meantime, just keep it in a set. + // Note: Constants that end up as immediate in the related instructions, + // do not appear in that map. + SmallSetVector<const Constant *, 8> Constants; + + DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB; + + /// Methods for translating form LLVM IR to MachineInstr. + /// \see ::translate for general information on the translate methods. + /// @{ + + /// Translate \p Inst into its corresponding MachineInstr instruction(s). + /// Insert the newly translated instruction(s) right where the MIRBuilder + /// is set. + /// + /// The general algorithm is: + /// 1. Look for a virtual register for each operand or + /// create one. + /// 2 Update the ValToVReg accordingly. + /// 2.alt. For constant arguments, if they are compile time constants, + /// produce an immediate in the right operand and do not touch + /// ValToReg. Actually we will go with a virtual register for each + /// constants because it may be expensive to actually materialize the + /// constant. Moreover, if the constant spans on several instructions, + /// CSE may not catch them. + /// => Update ValToVReg and remember that we saw a constant in Constants. + /// We will materialize all the constants in finalize. + /// Note: we would need to do something so that we can recognize such operand + /// as constants. + /// 3. Create the generic instruction. + /// + /// \return true if the translation succeeded. + bool translate(const Instruction &Inst); + + /// Translate \p Inst into a binary operation \p Opcode. + /// \pre \p Inst is a binary operation. + bool translateBinaryOp(unsigned Opcode, const Instruction &Inst); + + /// Translate branch (br) instruction. + /// \pre \p Inst is a branch instruction. + bool translateBr(const Instruction &Inst); + + /// Translate return (ret) instruction. + /// The target needs to implement CallLowering::lowerReturn for + /// this to succeed. + /// \pre \p Inst is a return instruction. + bool translateReturn(const Instruction &Inst); + /// @} + + // Builder for machine instruction a la IRBuilder. + // I.e., compared to regular MIBuilder, this one also inserts the instruction + // in the current block, it can creates block, etc., basically a kind of + // IRBuilder, but for Machine IR. + MachineIRBuilder MIRBuilder; + + /// MachineRegisterInfo used to create virtual registers. + MachineRegisterInfo *MRI; + + // * Insert all the code needed to materialize the constants + // at the proper place. E.g., Entry block or dominator block + // of each constant depending on how fancy we want to be. + // * Clear the different maps. + void finalize(); + + /// Get the VReg that represents \p Val. + /// If such VReg does not exist, it is created. + unsigned getOrCreateVReg(const Value &Val); + + /// Get the MachineBasicBlock that represents \p BB. + /// If such basic block does not exist, it is created. + MachineBasicBlock &getOrCreateBB(const BasicBlock &BB); + +public: + // Ctor, nothing fancy. + IRTranslator(); + + const char *getPassName() const override { + return "IRTranslator"; + } + + // Algo: + // CallLowering = MF.subtarget.getCallLowering() + // F = MF.getParent() + // MIRBuilder.reset(MF) + // MIRBuilder.getOrCreateBB(F.getEntryBB()) + // CallLowering->translateArguments(MIRBuilder, F, ValToVReg) + // for each bb in F + // MIRBuilder.getOrCreateBB(bb) + // for each inst in bb + // if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence)) + // report_fatal_error(“Don’t know how to translate input"); + // finalize() + bool runOnMachineFunction(MachineFunction &MF) override; +}; + +} // End namespace llvm. +#endif diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h new file mode 100644 index 000000000000..efdc59a9cddf --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -0,0 +1,146 @@ +//===-- llvm/CodeGen/GlobalISel/MachineIRBuilder.h - MIBuilder --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares the MachineIRBuilder class. +/// This is a helper class to build MachineInstr. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H +#define LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H + +#include "llvm/CodeGen/GlobalISel/Types.h" + +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/IR/DebugLoc.h" + +namespace llvm { + +// Forward declarations. +class MachineFunction; +class MachineInstr; +class TargetInstrInfo; + +/// Helper class to build MachineInstr. +/// It keeps internally the insertion point and debug location for all +/// the new instructions we want to create. +/// This information can be modify via the related setters. +class MachineIRBuilder { + /// MachineFunction under construction. + MachineFunction *MF; + /// Information used to access the description of the opcodes. + const TargetInstrInfo *TII; + /// Debug location to be set to any instruction we create. + DebugLoc DL; + + /// Fields describing the insertion point. + /// @{ + MachineBasicBlock *MBB; + MachineInstr *MI; + bool Before; + /// @} + + const TargetInstrInfo &getTII() { + assert(TII && "TargetInstrInfo is not set"); + return *TII; + } + +public: + /// Getter for the function we currently build. + MachineFunction &getMF() { + assert(MF && "MachineFunction is not set"); + return *MF; + } + + /// Getter for the basic block we currently build. + MachineBasicBlock &getMBB() { + assert(MBB && "MachineBasicBlock is not set"); + return *MBB; + } + + /// Current insertion point for new instructions. + MachineBasicBlock::iterator getInsertPt(); + + /// Setters for the insertion point. + /// @{ + /// Set the MachineFunction where to build instructions. + void setMF(MachineFunction &); + + /// Set the insertion point to the beginning (\p Beginning = true) or end + /// (\p Beginning = false) of \p MBB. + /// \pre \p MBB must be contained by getMF(). + void setMBB(MachineBasicBlock &MBB, bool Beginning = false); + + /// Set the insertion point to before (\p Before = true) or after + /// (\p Before = false) \p MI. + /// \pre MI must be in getMF(). + void setInstr(MachineInstr &MI, bool Before = false); + /// @} + + /// Set the debug location to \p DL for all the next build instructions. + void setDebugLoc(const DebugLoc &DL) { this->DL = DL; } + + /// Build and insert <empty> = \p Opcode [\p Ty] <empty>. + /// \p Ty is the type of the instruction if \p Opcode describes + /// a generic machine instruction. \p Ty must be nullptr if \p Opcode + /// does not describe a generic instruction. + /// The insertion point is the one set by the last call of either + /// setBasicBlock or setMI. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode, Type *Ty); + + /// Build and insert <empty> = \p Opcode [\p Ty] \p BB. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode, Type *Ty, MachineBasicBlock &BB); + + /// Build and insert \p Res<def> = \p Opcode [\p Ty] \p Op0, \p Op1. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre Ty == nullptr or isPreISelGenericOpcode(Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode, Type *Ty, unsigned Res, + unsigned Op0, unsigned Op1); + + /// Build and insert \p Res<def> = \p Opcode \p Op0, \p Op1. + /// I.e., instruction with a non-generic opcode. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre not isPreISelGenericOpcode(\p Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode, unsigned Res, unsigned Op0, + unsigned Op1); + + /// Build and insert \p Res<def> = \p Opcode \p Op0. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre not isPreISelGenericOpcode(\p Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode, unsigned Res, unsigned Op0); + + /// Build and insert <empty> = \p Opcode <empty>. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre not isPreISelGenericOpcode(\p Opcode) + /// + /// \return The newly created instruction. + MachineInstr *buildInstr(unsigned Opcode); +}; + +} // End namespace llvm. +#endif // LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H diff --git a/include/llvm/CodeGen/GlobalISel/RegBankSelect.h b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h new file mode 100644 index 000000000000..b393744e67cb --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h @@ -0,0 +1,614 @@ +//== llvm/CodeGen/GlobalISel/RegBankSelect.h - Reg Bank Selector -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file describes the interface of the MachineFunctionPass +/// responsible for assigning the generic virtual registers to register bank. + +/// By default, the reg bank selector relies on local decisions to +/// assign the register bank. In other words, it looks at one instruction +/// at a time to decide where the operand of that instruction should live. +/// +/// At higher optimization level, we could imagine that the reg bank selector +/// would use more global analysis and do crazier thing like duplicating +/// instructions and so on. This is future work. +/// +/// For now, the pass uses a greedy algorithm to decide where the operand +/// of an instruction should live. It asks the target which banks may be +/// used for each operand of the instruction and what is the cost. Then, +/// it chooses the solution which minimize the cost of the instruction plus +/// the cost of any move that may be needed to to the values into the right +/// register bank. +/// In other words, the cost for an instruction on a register bank RegBank +/// is: Cost of I on RegBank plus the sum of the cost for bringing the +/// input operands from their current register bank to RegBank. +/// Thus, the following formula: +/// cost(I, RegBank) = cost(I.Opcode, RegBank) + +/// sum(for each arg in I.arguments: costCrossCopy(arg.RegBank, RegBank)) +/// +/// E.g., Let say we are assigning the register bank for the instruction +/// defining v2. +/// v0(A_REGBANK) = ... +/// v1(A_REGBANK) = ... +/// v2 = G_ADD i32 v0, v1 <-- MI +/// +/// The target may say it can generate G_ADD i32 on register bank A and B +/// with a cost of respectively 5 and 1. +/// Then, let say the cost of a cross register bank copies from A to B is 1. +/// The reg bank selector would compare the following two costs: +/// cost(MI, A_REGBANK) = cost(G_ADD, A_REGBANK) + cost(v0.RegBank, A_REGBANK) + +/// cost(v1.RegBank, A_REGBANK) +/// = 5 + cost(A_REGBANK, A_REGBANK) + cost(A_REGBANK, +/// A_REGBANK) +/// = 5 + 0 + 0 = 5 +/// cost(MI, B_REGBANK) = cost(G_ADD, B_REGBANK) + cost(v0.RegBank, B_REGBANK) + +/// cost(v1.RegBank, B_REGBANK) +/// = 1 + cost(A_REGBANK, B_REGBANK) + cost(A_REGBANK, +/// B_REGBANK) +/// = 1 + 1 + 1 = 3 +/// Therefore, in this specific example, the reg bank selector would choose +/// bank B for MI. +/// v0(A_REGBANK) = ... +/// v1(A_REGBANK) = ... +/// tmp0(B_REGBANK) = COPY v0 +/// tmp1(B_REGBANK) = COPY v1 +/// v2(B_REGBANK) = G_ADD i32 tmp0, tmp1 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { +// Forward declarations. +class BlockFrequency; +class MachineBranchProbabilityInfo; +class MachineBlockFrequencyInfo; +class MachineRegisterInfo; +class TargetRegisterInfo; + +/// This pass implements the reg bank selector pass used in the GlobalISel +/// pipeline. At the end of this pass, all register operands have been assigned +class RegBankSelect : public MachineFunctionPass { +public: + static char ID; + + /// List of the modes supported by the RegBankSelect pass. + enum Mode { + /// Assign the register banks as fast as possible (default). + Fast, + /// Greedily minimize the cost of assigning register banks. + /// This should produce code of greater quality, but will + /// require more compile time. + Greedy + }; + + /// Abstract class used to represent an insertion point in a CFG. + /// This class records an insertion point and materializes it on + /// demand. + /// It allows to reason about the frequency of this insertion point, + /// without having to logically materialize it (e.g., on an edge), + /// before we actually need to insert something. + class InsertPoint { + protected: + /// Tell if the insert point has already been materialized. + bool WasMaterialized = false; + /// Materialize the insertion point. + /// + /// If isSplit() is true, this involves actually splitting + /// the block or edge. + /// + /// \post getPointImpl() returns a valid iterator. + /// \post getInsertMBBImpl() returns a valid basic block. + /// \post isSplit() == false ; no more splitting should be required. + virtual void materialize() = 0; + + /// Return the materialized insertion basic block. + /// Code will be inserted into that basic block. + /// + /// \pre ::materialize has been called. + virtual MachineBasicBlock &getInsertMBBImpl() = 0; + + /// Return the materialized insertion point. + /// Code will be inserted before that point. + /// + /// \pre ::materialize has been called. + virtual MachineBasicBlock::iterator getPointImpl() = 0; + + public: + virtual ~InsertPoint() {} + + /// The first call to this method will cause the splitting to + /// happen if need be, then sub sequent calls just return + /// the iterator to that point. I.e., no more splitting will + /// occur. + /// + /// \return The iterator that should be used with + /// MachineBasicBlock::insert. I.e., additional code happens + /// before that point. + MachineBasicBlock::iterator getPoint() { + if (!WasMaterialized) { + WasMaterialized = true; + assert(canMaterialize() && "Impossible to materialize this point"); + materialize(); + } + // When we materialized the point we should have done the splitting. + assert(!isSplit() && "Wrong pre-condition"); + return getPointImpl(); + } + + /// The first call to this method will cause the splitting to + /// happen if need be, then sub sequent calls just return + /// the basic block that contains the insertion point. + /// I.e., no more splitting will occur. + /// + /// \return The basic block should be used with + /// MachineBasicBlock::insert and ::getPoint. The new code should + /// happen before that point. + MachineBasicBlock &getInsertMBB() { + if (!WasMaterialized) { + WasMaterialized = true; + assert(canMaterialize() && "Impossible to materialize this point"); + materialize(); + } + // When we materialized the point we should have done the splitting. + assert(!isSplit() && "Wrong pre-condition"); + return getInsertMBBImpl(); + } + + /// Insert \p MI in the just before ::getPoint() + MachineBasicBlock::iterator insert(MachineInstr &MI) { + return getInsertMBB().insert(getPoint(), &MI); + } + + /// Does this point involve splitting an edge or block? + /// As soon as ::getPoint is called and thus, the point + /// materialized, the point will not require splitting anymore, + /// i.e., this will return false. + virtual bool isSplit() const { return false; } + + /// Frequency of the insertion point. + /// \p P is used to access the various analysis that will help to + /// get that information, like MachineBlockFrequencyInfo. If \p P + /// does not contain enough enough to return the actual frequency, + /// this returns 1. + virtual uint64_t frequency(const Pass &P) const { return 1; } + + /// Check whether this insertion point can be materialized. + /// As soon as ::getPoint is called and thus, the point materialized + /// calling this method does not make sense. + virtual bool canMaterialize() const { return false; } + }; + + /// Insertion point before or after an instruction. + class InstrInsertPoint : public InsertPoint { + private: + /// Insertion point. + MachineInstr &Instr; + /// Does the insertion point is before or after Instr. + bool Before; + + void materialize() override; + + MachineBasicBlock::iterator getPointImpl() override { + if (Before) + return Instr; + return Instr.getNextNode() ? *Instr.getNextNode() + : Instr.getParent()->end(); + } + + MachineBasicBlock &getInsertMBBImpl() override { + return *Instr.getParent(); + } + + public: + /// Create an insertion point before (\p Before=true) or after \p Instr. + InstrInsertPoint(MachineInstr &Instr, bool Before = true); + bool isSplit() const override; + uint64_t frequency(const Pass &P) const override; + + // Worst case, we need to slice the basic block, but that is still doable. + bool canMaterialize() const override { return true; } + }; + + /// Insertion point at the beginning or end of a basic block. + class MBBInsertPoint : public InsertPoint { + private: + /// Insertion point. + MachineBasicBlock &MBB; + /// Does the insertion point is at the beginning or end of MBB. + bool Beginning; + + void materialize() override { /*Nothing to do to materialize*/ + } + + MachineBasicBlock::iterator getPointImpl() override { + return Beginning ? MBB.begin() : MBB.end(); + } + + MachineBasicBlock &getInsertMBBImpl() override { return MBB; } + + public: + MBBInsertPoint(MachineBasicBlock &MBB, bool Beginning = true) + : InsertPoint(), MBB(MBB), Beginning(Beginning) { + // If we try to insert before phis, we should use the insertion + // points on the incoming edges. + assert((!Beginning || MBB.getFirstNonPHI() == MBB.begin()) && + "Invalid beginning point"); + // If we try to insert after the terminators, we should use the + // points on the outcoming edges. + assert((Beginning || MBB.getFirstTerminator() == MBB.end()) && + "Invalid end point"); + } + bool isSplit() const override { return false; } + uint64_t frequency(const Pass &P) const override; + bool canMaterialize() const override { return true; }; + }; + + /// Insertion point on an edge. + class EdgeInsertPoint : public InsertPoint { + private: + /// Source of the edge. + MachineBasicBlock &Src; + /// Destination of the edge. + /// After the materialization is done, this hold the basic block + /// that resulted from the splitting. + MachineBasicBlock *DstOrSplit; + /// P is used to update the analysis passes as applicable. + Pass &P; + + void materialize() override; + + MachineBasicBlock::iterator getPointImpl() override { + // DstOrSplit should be the Split block at this point. + // I.e., it should have one predecessor, Src, and one successor, + // the original Dst. + assert(DstOrSplit && DstOrSplit->isPredecessor(&Src) && + DstOrSplit->pred_size() == 1 && DstOrSplit->succ_size() == 1 && + "Did not split?!"); + return DstOrSplit->begin(); + } + + MachineBasicBlock &getInsertMBBImpl() override { return *DstOrSplit; } + + public: + EdgeInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst, Pass &P) + : InsertPoint(), Src(Src), DstOrSplit(&Dst), P(P) {} + bool isSplit() const override { + return Src.succ_size() > 1 && DstOrSplit->pred_size() > 1; + } + uint64_t frequency(const Pass &P) const override; + bool canMaterialize() const override; + }; + + /// Struct used to represent the placement of a repairing point for + /// a given operand. + class RepairingPlacement { + public: + /// Define the kind of action this repairing needs. + enum RepairingKind { + /// Nothing to repair, just drop this action. + None, + /// Reparing code needs to happen before InsertPoints. + Insert, + /// (Re)assign the register bank of the operand. + Reassign, + /// Mark this repairing placement as impossible. + Impossible + }; + + /// Convenient types for a list of insertion points. + /// @{ + typedef SmallVector<std::unique_ptr<InsertPoint>, 2> InsertionPoints; + typedef InsertionPoints::iterator insertpt_iterator; + typedef InsertionPoints::const_iterator const_insertpt_iterator; + /// @} + + private: + /// Kind of repairing. + RepairingKind Kind; + /// Index of the operand that will be repaired. + unsigned OpIdx; + /// Are all the insert points materializeable? + bool CanMaterialize; + /// Is there any of the insert points needing splitting? + bool HasSplit; + /// Insertion point for the repair code. + /// The repairing code needs to happen just before these points. + InsertionPoints InsertPoints; + /// Some insertion points may need to update the liveness and such. + Pass &P; + + public: + /// Create a repairing placement for the \p OpIdx-th operand of + /// \p MI. \p TRI is used to make some checks on the register aliases + /// if the machine operand is a physical register. \p P is used to + /// to update liveness information and such when materializing the + /// points. + RepairingPlacement(MachineInstr &MI, unsigned OpIdx, + const TargetRegisterInfo &TRI, Pass &P, + RepairingKind Kind = RepairingKind::Insert); + + /// Getters. + /// @{ + RepairingKind getKind() const { return Kind; } + unsigned getOpIdx() const { return OpIdx; } + bool canMaterialize() const { return CanMaterialize; } + bool hasSplit() { return HasSplit; } + /// @} + + /// Overloaded methods to add an insertion point. + /// @{ + /// Add a MBBInsertionPoint to the list of InsertPoints. + void addInsertPoint(MachineBasicBlock &MBB, bool Beginning); + /// Add a InstrInsertionPoint to the list of InsertPoints. + void addInsertPoint(MachineInstr &MI, bool Before); + /// Add an EdgeInsertionPoint (\p Src, \p Dst) to the list of InsertPoints. + void addInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst); + /// Add an InsertPoint to the list of insert points. + /// This method takes the ownership of &\p Point. + void addInsertPoint(InsertPoint &Point); + /// @} + + /// Accessors related to the insertion points. + /// @{ + insertpt_iterator begin() { return InsertPoints.begin(); } + insertpt_iterator end() { return InsertPoints.end(); } + + const_insertpt_iterator begin() const { return InsertPoints.begin(); } + const_insertpt_iterator end() const { return InsertPoints.end(); } + + unsigned getNumInsertPoints() const { return InsertPoints.size(); } + /// @} + + /// Change the type of this repairing placement to \p NewKind. + /// It is not possible to switch a repairing placement to the + /// RepairingKind::Insert. There is no fundamental problem with + /// that, but no uses as well, so do not support it for now. + /// + /// \pre NewKind != RepairingKind::Insert + /// \post getKind() == NewKind + void switchTo(RepairingKind NewKind) { + assert(NewKind != Kind && "Already of the right Kind"); + Kind = NewKind; + InsertPoints.clear(); + CanMaterialize = NewKind != RepairingKind::Impossible; + HasSplit = false; + assert(NewKind != RepairingKind::Insert && + "We would need more MI to switch to Insert"); + } + }; + +private: + /// Helper class used to represent the cost for mapping an instruction. + /// When mapping an instruction, we may introduce some repairing code. + /// In most cases, the repairing code is local to the instruction, + /// thus, we can omit the basic block frequency from the cost. + /// However, some alternatives may produce non-local cost, e.g., when + /// repairing a phi, and thus we then need to scale the local cost + /// to the non-local cost. This class does this for us. + /// \note: We could simply always scale the cost. The problem is that + /// there are higher chances that we saturate the cost easier and end + /// up having the same cost for actually different alternatives. + /// Another option would be to use APInt everywhere. + class MappingCost { + private: + /// Cost of the local instructions. + /// This cost is free of basic block frequency. + uint64_t LocalCost; + /// Cost of the non-local instructions. + /// This cost should include the frequency of the related blocks. + uint64_t NonLocalCost; + /// Frequency of the block where the local instructions live. + uint64_t LocalFreq; + + MappingCost(uint64_t LocalCost, uint64_t NonLocalCost, uint64_t LocalFreq) + : LocalCost(LocalCost), NonLocalCost(NonLocalCost), + LocalFreq(LocalFreq) {} + + /// Check if this cost is saturated. + bool isSaturated() const; + + public: + /// Create a MappingCost assuming that most of the instructions + /// will occur in a basic block with \p LocalFreq frequency. + MappingCost(const BlockFrequency &LocalFreq); + + /// Add \p Cost to the local cost. + /// \return true if this cost is saturated, false otherwise. + bool addLocalCost(uint64_t Cost); + + /// Add \p Cost to the non-local cost. + /// Non-local cost should reflect the frequency of their placement. + /// \return true if this cost is saturated, false otherwise. + bool addNonLocalCost(uint64_t Cost); + + /// Saturate the cost to the maximal representable value. + void saturate(); + + /// Return an instance of MappingCost that represents an + /// impossible mapping. + static MappingCost ImpossibleCost(); + + /// Check if this is less than \p Cost. + bool operator<(const MappingCost &Cost) const; + /// Check if this is equal to \p Cost. + bool operator==(const MappingCost &Cost) const; + /// Check if this is not equal to \p Cost. + bool operator!=(const MappingCost &Cost) const { return !(*this == Cost); } + /// Check if this is greater than \p Cost. + bool operator>(const MappingCost &Cost) const { + return *this != Cost && Cost < *this; + } + }; + + /// Interface to the target lowering info related + /// to register banks. + const RegisterBankInfo *RBI; + + /// MRI contains all the register class/bank information that this + /// pass uses and updates. + MachineRegisterInfo *MRI; + + /// Information on the register classes for the current function. + const TargetRegisterInfo *TRI; + + /// Get the frequency of blocks. + /// This is required for non-fast mode. + MachineBlockFrequencyInfo *MBFI; + + /// Get the frequency of the edges. + /// This is required for non-fast mode. + MachineBranchProbabilityInfo *MBPI; + + /// Helper class used for every code morphing. + MachineIRBuilder MIRBuilder; + + /// Optimization mode of the pass. + Mode OptMode; + + /// Assign the register bank of each operand of \p MI. + void assignInstr(MachineInstr &MI); + + /// Initialize the field members using \p MF. + void init(MachineFunction &MF); + + /// Check if \p Reg is already assigned what is described by \p ValMapping. + /// \p OnlyAssign == true means that \p Reg just needs to be assigned a + /// register bank. I.e., no repairing is necessary to have the + /// assignment match. + bool assignmentMatch(unsigned Reg, + const RegisterBankInfo::ValueMapping &ValMapping, + bool &OnlyAssign) const; + + /// Insert repairing code for \p Reg as specified by \p ValMapping. + /// The repairing placement is specified by \p RepairPt. + /// \p NewVRegs contains all the registers required to remap \p Reg. + /// In other words, the number of registers in NewVRegs must be equal + /// to ValMapping.BreakDown.size(). + /// + /// The transformation could be sketched as: + /// \code + /// ... = op Reg + /// \endcode + /// Becomes + /// \code + /// <NewRegs> = COPY or extract Reg + /// ... = op Reg + /// \endcode + /// + /// and + /// \code + /// Reg = op ... + /// \endcode + /// Becomes + /// \code + /// Reg = op ... + /// Reg = COPY or build_sequence <NewRegs> + /// \endcode + /// + /// \pre NewVRegs.size() == ValMapping.BreakDown.size() + /// + /// \note The caller is supposed to do the rewriting of op if need be. + /// I.e., Reg = op ... => <NewRegs> = NewOp ... + void repairReg(MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping, + RegBankSelect::RepairingPlacement &RepairPt, + const iterator_range<SmallVectorImpl<unsigned>::const_iterator> + &NewVRegs); + + /// Return the cost of the instruction needed to map \p MO to \p ValMapping. + /// The cost is free of basic block frequencies. + /// \pre MO.isReg() + /// \pre MO is assigned to a register bank. + /// \pre ValMapping is a valid mapping for MO. + uint64_t + getRepairCost(const MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping) const; + + /// Find the best mapping for \p MI from \p PossibleMappings. + /// \return a reference on the best mapping in \p PossibleMappings. + RegisterBankInfo::InstructionMapping & + findBestMapping(MachineInstr &MI, + RegisterBankInfo::InstructionMappings &PossibleMappings, + SmallVectorImpl<RepairingPlacement> &RepairPts); + + /// Compute the cost of mapping \p MI with \p InstrMapping and + /// compute the repairing placement for such mapping in \p + /// RepairPts. + /// \p BestCost is used to specify when the cost becomes too high + /// and thus it is not worth computing the RepairPts. Moreover if + /// \p BestCost == nullptr, the mapping cost is actually not + /// computed. + MappingCost + computeMapping(MachineInstr &MI, + const RegisterBankInfo::InstructionMapping &InstrMapping, + SmallVectorImpl<RepairingPlacement> &RepairPts, + const MappingCost *BestCost = nullptr); + + /// When \p RepairPt involves splitting to repair \p MO for the + /// given \p ValMapping, try to change the way we repair such that + /// the splitting is not required anymore. + /// + /// \pre \p RepairPt.hasSplit() + /// \pre \p MO == MO.getParent()->getOperand(\p RepairPt.getOpIdx()) + /// \pre \p ValMapping is the mapping of \p MO for MO.getParent() + /// that implied \p RepairPt. + void tryAvoidingSplit(RegBankSelect::RepairingPlacement &RepairPt, + const MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping) const; + + /// Apply \p Mapping to \p MI. \p RepairPts represents the different + /// mapping action that need to happen for the mapping to be + /// applied. + void applyMapping(MachineInstr &MI, + const RegisterBankInfo::InstructionMapping &InstrMapping, + SmallVectorImpl<RepairingPlacement> &RepairPts); + +public: + /// Create a RegBankSelect pass with the specified \p RunningMode. + RegBankSelect(Mode RunningMode = Fast); + + const char *getPassName() const override { + return "RegBankSelect"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Walk through \p MF and assign a register bank to every virtual register + /// that are still mapped to nothing. + /// The target needs to provide a RegisterBankInfo and in particular + /// override RegisterBankInfo::getInstrMapping. + /// + /// Simplified algo: + /// \code + /// RBI = MF.subtarget.getRegBankInfo() + /// MIRBuilder.setMF(MF) + /// for each bb in MF + /// for each inst in bb + /// MIRBuilder.setInstr(inst) + /// MappingCosts = RBI.getMapping(inst); + /// Idx = findIdxOfMinCost(MappingCosts) + /// CurRegBank = MappingCosts[Idx].RegBank + /// MRI.setRegBank(inst.getOperand(0).getReg(), CurRegBank) + /// for each argument in inst + /// if (CurRegBank != argument.RegBank) + /// ArgReg = argument.getReg() + /// Tmp = MRI.createNewVirtual(MRI.getSize(ArgReg), CurRegBank) + /// MIRBuilder.buildInstr(COPY, Tmp, ArgReg) + /// inst.getOperand(argument.getOperandNo()).setReg(Tmp) + /// \endcode + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBank.h b/include/llvm/CodeGen/GlobalISel/RegisterBank.h new file mode 100644 index 000000000000..e886382fd8e8 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegisterBank.h @@ -0,0 +1,101 @@ +//==-- llvm/CodeGen/GlobalISel/RegisterBank.h - Register Bank ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file declares the API of register banks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANK_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANK_H + +#include "llvm/ADT/BitVector.h" + +namespace llvm { +// Forward declarations. +class RegisterBankInfo; +class raw_ostream; +class TargetRegisterClass; +class TargetRegisterInfo; + +/// This class implements the register bank concept. +/// Two instances of RegisterBank must have different ID. +/// This property is enforced by the RegisterBankInfo class. +class RegisterBank { +private: + unsigned ID; + const char *Name; + unsigned Size; + BitVector ContainedRegClasses; + + /// Sentinel value used to recognize register bank not properly + /// initialized yet. + static const unsigned InvalidID; + + /// Only the RegisterBankInfo can create RegisterBank. + /// The default constructor will leave the object in + /// an invalid state. I.e. isValid() == false. + /// The field must be updated to fix that. + RegisterBank(); + + friend RegisterBankInfo; + +public: + /// Get the identifier of this register bank. + unsigned getID() const { return ID; } + + /// Get a user friendly name of this register bank. + /// Should be used only for debugging purposes. + const char *getName() const { return Name; } + + /// Get the maximal size in bits that fits in this register bank. + unsigned getSize() const { return Size; } + + /// Check whether this instance is ready to be used. + bool isValid() const; + + /// Check if this register bank is valid. In other words, + /// if it has been properly constructed. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const TargetRegisterInfo &TRI) const; + + /// Check whether this register bank covers \p RC. + /// In other words, check if this register bank fully covers + /// the registers that \p RC contains. + /// \pre isValid() + bool covers(const TargetRegisterClass &RC) const; + + /// Check whether \p OtherRB is the same as this. + bool operator==(const RegisterBank &OtherRB) const; + bool operator!=(const RegisterBank &OtherRB) const { + return !this->operator==(OtherRB); + } + + /// Dump the register mask on dbgs() stream. + /// The dump is verbose. + void dump(const TargetRegisterInfo *TRI = nullptr) const; + + /// Print the register mask on OS. + /// If IsForDebug is false, then only the name of the register bank + /// is printed. Otherwise, all the fields are printing. + /// TRI is then used to print the name of the register classes that + /// this register bank covers. + void print(raw_ostream &OS, bool IsForDebug = false, + const TargetRegisterInfo *TRI = nullptr) const; +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const RegisterBank &RegBank) { + RegBank.print(OS); + return OS; +} +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h new file mode 100644 index 000000000000..19d170365858 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h @@ -0,0 +1,602 @@ +//==-- llvm/CodeGen/GlobalISel/RegisterBankInfo.h ----------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file declares the API for the register bank info. +/// This API is responsible for handling the register banks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/GlobalISel/RegisterBank.h" +#include "llvm/CodeGen/MachineValueType.h" // For SimpleValueType. +#include "llvm/Support/ErrorHandling.h" + +#include <cassert> +#include <memory> // For unique_ptr. + +namespace llvm { +class MachineInstr; +class MachineRegisterInfo; +class TargetInstrInfo; +class TargetRegisterInfo; +class raw_ostream; + +/// Holds all the information related to register banks. +class RegisterBankInfo { +public: + /// Helper struct that represents how a value is partially mapped + /// into a register. + /// The StartIdx and Length represent what region of the orginal + /// value this partial mapping covers. + /// This can be represented as a Mask of contiguous bit starting + /// at StartIdx bit and spanning Length bits. + /// StartIdx is the number of bits from the less significant bits. + struct PartialMapping { + /// Number of bits at which this partial mapping starts in the + /// original value. The bits are counted from less significant + /// bits to most significant bits. + unsigned StartIdx; + /// Length of this mapping in bits. This is how many bits this + /// partial mapping covers in the original value: + /// from StartIdx to StartIdx + Length -1. + unsigned Length; + /// Register bank where the partial value lives. + const RegisterBank *RegBank; + + PartialMapping() = default; + + /// Provide a shortcut for quickly building PartialMapping. + PartialMapping(unsigned StartIdx, unsigned Length, + const RegisterBank &RegBank) + : StartIdx(StartIdx), Length(Length), RegBank(&RegBank) {} + + /// \return the index of in the original value of the most + /// significant bit that this partial mapping covers. + unsigned getHighBitIdx() const { return StartIdx + Length - 1; } + + /// Print this partial mapping on dbgs() stream. + void dump() const; + + /// Print this partial mapping on \p OS; + void print(raw_ostream &OS) const; + + /// Check that the Mask is compatible with the RegBank. + /// Indeed, if the RegBank cannot accomadate the "active bits" of the mask, + /// there is no way this mapping is valid. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify() const; + }; + + /// Helper struct that represents how a value is mapped through + /// different register banks. + struct ValueMapping { + /// How the value is broken down between the different register banks. + SmallVector<PartialMapping, 2> BreakDown; + + /// Verify that this mapping makes sense for a value of \p ExpectedBitWidth. + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(unsigned ExpectedBitWidth) const; + + /// Print this on dbgs() stream. + void dump() const; + + /// Print this on \p OS; + void print(raw_ostream &OS) const; + }; + + /// Helper class that represents how the value of an instruction may be + /// mapped and what is the related cost of such mapping. + class InstructionMapping { + /// Identifier of the mapping. + /// This is used to communicate between the target and the optimizers + /// which mapping should be realized. + unsigned ID; + /// Cost of this mapping. + unsigned Cost; + /// Mapping of all the operands. + std::unique_ptr<ValueMapping[]> OperandsMapping; + /// Number of operands. + unsigned NumOperands; + + ValueMapping &getOperandMapping(unsigned i) { + assert(i < getNumOperands() && "Out of bound operand"); + return OperandsMapping[i]; + } + + public: + /// Constructor for the mapping of an instruction. + /// \p NumOperands must be equal to number of all the operands of + /// the related instruction. + /// The rationale is that it is more efficient for the optimizers + /// to be able to assume that the mapping of the ith operand is + /// at the index i. + /// + /// \pre ID != InvalidMappingID + InstructionMapping(unsigned ID, unsigned Cost, unsigned NumOperands) + : ID(ID), Cost(Cost), NumOperands(NumOperands) { + assert(getID() != InvalidMappingID && + "Use the default constructor for invalid mapping"); + OperandsMapping.reset(new ValueMapping[getNumOperands()]); + } + + /// Default constructor. + /// Use this constructor to express that the mapping is invalid. + InstructionMapping() : ID(InvalidMappingID), Cost(0), NumOperands(0) {} + + /// Get the cost. + unsigned getCost() const { return Cost; } + + /// Get the ID. + unsigned getID() const { return ID; } + + /// Get the number of operands. + unsigned getNumOperands() const { return NumOperands; } + + /// Get the value mapping of the ith operand. + const ValueMapping &getOperandMapping(unsigned i) const { + return const_cast<InstructionMapping *>(this)->getOperandMapping(i); + } + + /// Get the value mapping of the ith operand. + void setOperandMapping(unsigned i, const ValueMapping &ValMapping) { + getOperandMapping(i) = ValMapping; + } + + /// Check whether this object is valid. + /// This is a lightweight check for obvious wrong instance. + bool isValid() const { return getID() != InvalidMappingID; } + + /// Set the operand mapping for the \p OpIdx-th operand. + /// The mapping will consist of only one element in the break down list. + /// This element will map to \p RegBank and fully define a mask, whose + /// bitwidth matches the size of \p MaskSize. + void setOperandMapping(unsigned OpIdx, unsigned MaskSize, + const RegisterBank &RegBank); + + /// Verifiy that this mapping makes sense for \p MI. + /// \pre \p MI must be connected to a MachineFunction. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const MachineInstr &MI) const; + + /// Print this on dbgs() stream. + void dump() const; + + /// Print this on \p OS; + void print(raw_ostream &OS) const; + }; + + /// Convenient type to represent the alternatives for mapping an + /// instruction. + /// \todo When we move to TableGen this should be an array ref. + typedef SmallVector<InstructionMapping, 4> InstructionMappings; + + /// Helper class use to get/create the virtual registers that will be used + /// to replace the MachineOperand when applying a mapping. + class OperandsMapper { + /// The OpIdx-th cell contains the index in NewVRegs where the VRegs of the + /// OpIdx-th operand starts. -1 means we do not have such mapping yet. + std::unique_ptr<int[]> OpToNewVRegIdx; + /// Hold the registers that will be used to map MI with InstrMapping. + SmallVector<unsigned, 8> NewVRegs; + /// Current MachineRegisterInfo, used to create new virtual registers. + MachineRegisterInfo &MRI; + /// Instruction being remapped. + MachineInstr &MI; + /// New mapping of the instruction. + const InstructionMapping &InstrMapping; + + /// Constant value identifying that the index in OpToNewVRegIdx + /// for an operand has not been set yet. + static const int DontKnowIdx; + + /// Get the range in NewVRegs to store all the partial + /// values for the \p OpIdx-th operand. + /// + /// \return The iterator range for the space created. + // + /// \pre getMI().getOperand(OpIdx).isReg() + iterator_range<SmallVectorImpl<unsigned>::iterator> + getVRegsMem(unsigned OpIdx); + + /// Get the end iterator for a range starting at \p StartIdx and + /// spannig \p NumVal in NewVRegs. + /// \pre StartIdx + NumVal <= NewVRegs.size() + SmallVectorImpl<unsigned>::const_iterator + getNewVRegsEnd(unsigned StartIdx, unsigned NumVal) const; + SmallVectorImpl<unsigned>::iterator getNewVRegsEnd(unsigned StartIdx, + unsigned NumVal); + + public: + /// Create an OperandsMapper that will hold the information to apply \p + /// InstrMapping to \p MI. + /// \pre InstrMapping.verify(MI) + OperandsMapper(MachineInstr &MI, const InstructionMapping &InstrMapping, + MachineRegisterInfo &MRI); + + /// Getters. + /// @{ + /// The MachineInstr being remapped. + MachineInstr &getMI() const { return MI; } + + /// The final mapping of the instruction. + const InstructionMapping &getInstrMapping() const { return InstrMapping; } + /// @} + + /// Create as many new virtual registers as needed for the mapping of the \p + /// OpIdx-th operand. + /// The number of registers is determined by the number of breakdown for the + /// related operand in the instruction mapping. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// + /// \post All the partial mapping of the \p OpIdx-th operand have been + /// assigned a new virtual register. + void createVRegs(unsigned OpIdx); + + /// Set the virtual register of the \p PartialMapIdx-th partial mapping of + /// the OpIdx-th operand to \p NewVReg. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// \pre getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() > + /// PartialMapIdx + /// \pre NewReg != 0 + /// + /// \post the \p PartialMapIdx-th register of the value mapping of the \p + /// OpIdx-th operand has been set. + void setVRegs(unsigned OpIdx, unsigned PartialMapIdx, unsigned NewVReg); + + /// Get all the virtual registers required to map the \p OpIdx-th operand of + /// the instruction. + /// + /// This return an empty range when createVRegs or setVRegs has not been + /// called. + /// The iterator may be invalidated by a call to setVRegs or createVRegs. + /// + /// When \p ForDebug is true, we will not check that the list of new virtual + /// registers does not contain uninitialized values. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// \pre ForDebug || All partial mappings have been set a register + iterator_range<SmallVectorImpl<unsigned>::const_iterator> + getVRegs(unsigned OpIdx, bool ForDebug = false) const; + + /// Print this operands mapper on dbgs() stream. + void dump() const; + + /// Print this operands mapper on \p OS stream. + void print(raw_ostream &OS, bool ForDebug = false) const; + }; + +protected: + /// Hold the set of supported register banks. + std::unique_ptr<RegisterBank[]> RegBanks; + /// Total number of register banks. + unsigned NumRegBanks; + + /// Mapping from MVT::SimpleValueType to register banks. + std::unique_ptr<const RegisterBank *[]> VTToRegBank; + + /// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks + /// RegisterBank instances. + /// + /// \note For the verify method to succeed all the \p NumRegBanks + /// must be initialized by createRegisterBank and updated with + /// addRegBankCoverage RegisterBank. + RegisterBankInfo(unsigned NumRegBanks); + + /// This constructor is meaningless. + /// It just provides a default constructor that can be used at link time + /// when GlobalISel is not built. + /// That way, targets can still inherit from this class without doing + /// crazy gymnastic to avoid link time failures. + /// \note That works because the constructor is inlined. + RegisterBankInfo() { + llvm_unreachable("This constructor should not be executed"); + } + + /// Create a new register bank with the given parameter and add it + /// to RegBanks. + /// \pre \p ID must not already be used. + /// \pre \p ID < NumRegBanks. + void createRegisterBank(unsigned ID, const char *Name); + + /// Add \p RCId to the set of register class that the register bank, + /// identified \p ID, covers. + /// This method transitively adds all the sub classes and the subreg-classes + /// of \p RCId to the set of covered register classes. + /// It also adjusts the size of the register bank to reflect the maximal + /// size of a value that can be hold into that register bank. + /// + /// If \p AddTypeMapping is true, this method also records what types can + /// be mapped to \p ID. Although this done by default, targets may want to + /// disable it, espicially if a given type may be mapped on different + /// register bank. Indeed, in such case, this method only records the + /// first register bank where the type matches. + /// This information is only used to provide default mapping + /// (see getInstrMappingImpl). + /// + /// \note This method does *not* add the super classes of \p RCId. + /// The rationale is if \p ID covers the registers of \p RCId, that + /// does not necessarily mean that \p ID covers the set of registers + /// of RCId's superclasses. + /// This method does *not* add the superreg classes as well for consistents. + /// The expected use is to add the coverage top-down with respect to the + /// register hierarchy. + /// + /// \todo TableGen should just generate the BitSet vector for us. + void addRegBankCoverage(unsigned ID, unsigned RCId, + const TargetRegisterInfo &TRI, + bool AddTypeMapping = true); + + /// Get the register bank identified by \p ID. + RegisterBank &getRegBank(unsigned ID) { + assert(ID < getNumRegBanks() && "Accessing an unknown register bank"); + return RegBanks[ID]; + } + + /// Get the register bank that has been recorded to cover \p SVT. + const RegisterBank *getRegBankForType(MVT::SimpleValueType SVT) const { + if (!VTToRegBank) + return nullptr; + assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); + return VTToRegBank.get()[SVT]; + } + + /// Record \p RegBank as the register bank that covers \p SVT. + /// If a record was already set for \p SVT, the mapping is not + /// updated, unless \p Force == true + /// + /// \post if getRegBankForType(SVT)\@pre == nullptr then + /// getRegBankForType(SVT) == &RegBank + /// \post if Force == true then getRegBankForType(SVT) == &RegBank + void recordRegBankForType(const RegisterBank &RegBank, + MVT::SimpleValueType SVT, bool Force = false) { + if (!VTToRegBank) { + VTToRegBank.reset( + new const RegisterBank *[MVT::SimpleValueType::LAST_VALUETYPE]); + std::fill(&VTToRegBank[0], + &VTToRegBank[MVT::SimpleValueType::LAST_VALUETYPE], nullptr); + } + assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); + // If we want to override the mapping or the mapping does not exits yet, + // set the register bank for SVT. + if (Force || !getRegBankForType(SVT)) + VTToRegBank.get()[SVT] = &RegBank; + } + + /// Try to get the mapping of \p MI. + /// See getInstrMapping for more details on what a mapping represents. + /// + /// Unlike getInstrMapping the returned InstructionMapping may be invalid + /// (isValid() == false). + /// This means that the target independent code is not smart enough + /// to get the mapping of \p MI and thus, the target has to provide the + /// information for \p MI. + /// + /// This implementation is able to get the mapping of: + /// - Target specific instructions by looking at the encoding constraints. + /// - Any instruction if all the register operands are already been assigned + /// a register, a register class, or a register bank. + /// - Copies and phis if at least one of the operand has been assigned a + /// register, a register class, or a register bank. + /// In other words, this method will likely fail to find a mapping for + /// any generic opcode that has not been lowered by target specific code. + InstructionMapping getInstrMappingImpl(const MachineInstr &MI) const; + + /// Get the register bank for the \p OpIdx-th operand of \p MI form + /// the encoding constraints, if any. + /// + /// \return A register bank that covers the register class of the + /// related encoding constraints or nullptr if \p MI did not provide + /// enough information to deduce it. + const RegisterBank * + getRegBankFromConstraints(const MachineInstr &MI, unsigned OpIdx, + const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI) const; + + /// Helper method to apply something that is like the default mapping. + /// Basically, that means that \p OpdMapper.getMI() is left untouched + /// aside from the reassignment of the register operand that have been + /// remapped. + /// If the mapping of one of the operand spans several registers, this + /// method will abort as this is not like a default mapping anymore. + /// + /// \pre For OpIdx in {0..\p OpdMapper.getMI().getNumOperands()) + /// the range OpdMapper.getVRegs(OpIdx) is empty or of size 1. + static void applyDefaultMapping(const OperandsMapper &OpdMapper); + + /// See ::applyMapping. + virtual void applyMappingImpl(const OperandsMapper &OpdMapper) const { + llvm_unreachable("The target has to implement that part"); + } + +public: + virtual ~RegisterBankInfo() {} + + /// Get the register bank identified by \p ID. + const RegisterBank &getRegBank(unsigned ID) const { + return const_cast<RegisterBankInfo *>(this)->getRegBank(ID); + } + + /// Get the register bank of \p Reg. + /// If Reg has not been assigned a register, a register class, + /// or a register bank, then this returns nullptr. + /// + /// \pre Reg != 0 (NoRegister) + const RegisterBank *getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI) const; + + /// Get the total number of register banks. + unsigned getNumRegBanks() const { return NumRegBanks; } + + /// Get a register bank that covers \p RC. + /// + /// \pre \p RC is a user-defined register class (as opposed as one + /// generated by TableGen). + /// + /// \note The mapping RC -> RegBank could be built while adding the + /// coverage for the register banks. However, we do not do it, because, + /// at least for now, we only need this information for register classes + /// that are used in the description of instruction. In other words, + /// there are just a handful of them and we do not want to waste space. + /// + /// \todo This should be TableGen'ed. + virtual const RegisterBank & + getRegBankFromRegClass(const TargetRegisterClass &RC) const { + llvm_unreachable("The target must override this method"); + } + + /// Get the cost of a copy from \p B to \p A, or put differently, + /// get the cost of A = COPY B. Since register banks may cover + /// different size, \p Size specifies what will be the size in bits + /// that will be copied around. + /// + /// \note Since this is a copy, both registers have the same size. + virtual unsigned copyCost(const RegisterBank &A, const RegisterBank &B, + unsigned Size) const { + // Optimistically assume that copies are coalesced. I.e., when + // they are on the same bank, they are free. + // Otherwise assume a non-zero cost of 1. The targets are supposed + // to override that properly anyway if they care. + return &A != &B; + } + + /// Identifier used when the related instruction mapping instance + /// is generated by target independent code. + /// Make sure not to use that identifier to avoid possible collision. + static const unsigned DefaultMappingID; + + /// Identifier used when the related instruction mapping instance + /// is generated by the default constructor. + /// Make sure not to use that identifier. + static const unsigned InvalidMappingID; + + /// Get the mapping of the different operands of \p MI + /// on the register bank. + /// This mapping should be the direct translation of \p MI. + /// In other words, when \p MI is mapped with the returned mapping, + /// only the register banks of the operands of \p MI need to be updated. + /// In particular, neither the opcode or the type of \p MI needs to be + /// updated for this direct mapping. + /// + /// The target independent implementation gives a mapping based on + /// the register classes for the target specific opcode. + /// It uses the ID RegisterBankInfo::DefaultMappingID for that mapping. + /// Make sure you do not use that ID for the alternative mapping + /// for MI. See getInstrAlternativeMappings for the alternative + /// mappings. + /// + /// For instance, if \p MI is a vector add, the mapping should + /// not be a scalarization of the add. + /// + /// \post returnedVal.verify(MI). + /// + /// \note If returnedVal does not verify MI, this would probably mean + /// that the target does not support that instruction. + virtual InstructionMapping getInstrMapping(const MachineInstr &MI) const; + + /// Get the alternative mappings for \p MI. + /// Alternative in the sense different from getInstrMapping. + virtual InstructionMappings + getInstrAlternativeMappings(const MachineInstr &MI) const; + + /// Get the possible mapping for \p MI. + /// A mapping defines where the different operands may live and at what cost. + /// For instance, let us consider: + /// v0(16) = G_ADD <2 x i8> v1, v2 + /// The possible mapping could be: + /// + /// {/*ID*/VectorAdd, /*Cost*/1, /*v0*/{(0xFFFF, VPR)}, /*v1*/{(0xFFFF, VPR)}, + /// /*v2*/{(0xFFFF, VPR)}} + /// {/*ID*/ScalarAddx2, /*Cost*/2, /*v0*/{(0x00FF, GPR),(0xFF00, GPR)}, + /// /*v1*/{(0x00FF, GPR),(0xFF00, GPR)}, + /// /*v2*/{(0x00FF, GPR),(0xFF00, GPR)}} + /// + /// \note The first alternative of the returned mapping should be the + /// direct translation of \p MI current form. + /// + /// \post !returnedVal.empty(). + InstructionMappings getInstrPossibleMappings(const MachineInstr &MI) const; + + /// Apply \p OpdMapper.getInstrMapping() to \p OpdMapper.getMI(). + /// After this call \p OpdMapper.getMI() may not be valid anymore. + /// \p OpdMapper.getInstrMapping().getID() carries the information of + /// what has been chosen to map \p OpdMapper.getMI(). This ID is set + /// by the various getInstrXXXMapping method. + /// + /// Therefore, getting the mapping and applying it should be kept in + /// sync. + void applyMapping(const OperandsMapper &OpdMapper) const { + // The only mapping we know how to handle is the default mapping. + if (OpdMapper.getInstrMapping().getID() == DefaultMappingID) + return applyDefaultMapping(OpdMapper); + // For other mapping, the target needs to do the right thing. + // If that means calling applyDefaultMapping, fine, but this + // must be explicitly stated. + applyMappingImpl(OpdMapper); + } + + /// Get the size in bits of \p Reg. + /// Utility method to get the size of any registers. Unlike + /// MachineRegisterInfo::getSize, the register does not need to be a + /// virtual register. + /// + /// \pre \p Reg != 0 (NoRegister). + static unsigned getSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI); + + /// Check that information hold by this instance make sense for the + /// given \p TRI. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const TargetRegisterInfo &TRI) const; +}; + +inline raw_ostream & +operator<<(raw_ostream &OS, + const RegisterBankInfo::PartialMapping &PartMapping) { + PartMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, const RegisterBankInfo::ValueMapping &ValMapping) { + ValMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, + const RegisterBankInfo::InstructionMapping &InstrMapping) { + InstrMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, const RegisterBankInfo::OperandsMapper &OpdMapper) { + OpdMapper.print(OS, /*ForDebug*/ false); + return OS; +} +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/Types.h b/include/llvm/CodeGen/GlobalISel/Types.h new file mode 100644 index 000000000000..7d974878d3b9 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/Types.h @@ -0,0 +1,32 @@ +//===-- llvm/CodeGen/GlobalISel/Types.h - Types used by GISel ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes high level types that are used by several passes or +/// APIs involved in the GlobalISel pipeline. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_TYPES_H +#define LLVM_CODEGEN_GLOBALISEL_TYPES_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/Value.h" + +namespace llvm { + +/// Map a value to a virtual register. +/// For now, we chose to map aggregate types to on single virtual +/// register. This might be revisited if it turns out to be inefficient. +/// PR26161 tracks that. +/// Note: We need to expose this type to the target hooks for thing like +/// ABI lowering that would be used during IRTranslation. +typedef DenseMap<const Value *, unsigned> ValueToVReg; + +} // End namespace llvm. +#endif diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 158ff3cd36a8..89cb7a86f99f 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -257,6 +257,9 @@ namespace ISD { /// value as an integer 0/1 value. FGETSIGN, + /// Returns platform specific canonical encoding of a floating point number. + FCANONICALIZE, + /// BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a vector with the /// specified, possibly variable, elements. The number of elements is /// required to be a power of two. The types of the operands must all be @@ -483,6 +486,12 @@ namespace ISD { /// the same bit size (e.g. f32 <-> i32). This can also be used for /// int-to-int or fp-to-fp conversions, but that is a noop, deleted by /// getNode(). + /// + /// This operator is subtly different from the bitcast instruction from + /// LLVM-IR since this node may change the bits in the register. For + /// example, this occurs on big-endian NEON and big-endian MSA where the + /// layout of the bits in the register depends on the vector type and this + /// operator acts as a shuffle operation for some vector type combinations. BITCAST, /// ADDRSPACECAST - This operator converts between pointers of different @@ -869,56 +878,52 @@ namespace ISD { SETCC_INVALID // Marker value. }; - /// isSignedIntSetCC - Return true if this is a setcc instruction that - /// performs a signed comparison when used with integer operands. + /// Return true if this is a setcc instruction that performs a signed + /// comparison when used with integer operands. inline bool isSignedIntSetCC(CondCode Code) { return Code == SETGT || Code == SETGE || Code == SETLT || Code == SETLE; } - /// isUnsignedIntSetCC - Return true if this is a setcc instruction that - /// performs an unsigned comparison when used with integer operands. + /// Return true if this is a setcc instruction that performs an unsigned + /// comparison when used with integer operands. inline bool isUnsignedIntSetCC(CondCode Code) { return Code == SETUGT || Code == SETUGE || Code == SETULT || Code == SETULE; } - /// isTrueWhenEqual - Return true if the specified condition returns true if - /// the two operands to the condition are equal. Note that if one of the two - /// operands is a NaN, this value is meaningless. + /// Return true if the specified condition returns true if the two operands to + /// the condition are equal. Note that if one of the two operands is a NaN, + /// this value is meaningless. inline bool isTrueWhenEqual(CondCode Cond) { return ((int)Cond & 1) != 0; } - /// getUnorderedFlavor - This function returns 0 if the condition is always - /// false if an operand is a NaN, 1 if the condition is always true if the - /// operand is a NaN, and 2 if the condition is undefined if the operand is a - /// NaN. + /// This function returns 0 if the condition is always false if an operand is + /// a NaN, 1 if the condition is always true if the operand is a NaN, and 2 if + /// the condition is undefined if the operand is a NaN. inline unsigned getUnorderedFlavor(CondCode Cond) { return ((int)Cond >> 3) & 3; } - /// getSetCCInverse - Return the operation corresponding to !(X op Y), where - /// 'op' is a valid SetCC operation. + /// Return the operation corresponding to !(X op Y), where 'op' is a valid + /// SetCC operation. CondCode getSetCCInverse(CondCode Operation, bool isInteger); - /// getSetCCSwappedOperands - Return the operation corresponding to (Y op X) - /// when given the operation for (X op Y). + /// Return the operation corresponding to (Y op X) when given the operation + /// for (X op Y). CondCode getSetCCSwappedOperands(CondCode Operation); - /// getSetCCOrOperation - Return the result of a logical OR between different - /// comparisons of identical values: ((X op1 Y) | (X op2 Y)). This - /// function returns SETCC_INVALID if it is not possible to represent the - /// resultant comparison. + /// Return the result of a logical OR between different comparisons of + /// identical values: ((X op1 Y) | (X op2 Y)). This function returns + /// SETCC_INVALID if it is not possible to represent the resultant comparison. CondCode getSetCCOrOperation(CondCode Op1, CondCode Op2, bool isInteger); - /// getSetCCAndOperation - Return the result of a logical AND between - /// different comparisons of identical values: ((X op1 Y) & (X op2 Y)). This - /// function returns SETCC_INVALID if it is not possible to represent the - /// resultant comparison. + /// Return the result of a logical AND between different comparisons of + /// identical values: ((X op1 Y) & (X op2 Y)). This function returns + /// SETCC_INVALID if it is not possible to represent the resultant comparison. CondCode getSetCCAndOperation(CondCode Op1, CondCode Op2, bool isInteger); //===--------------------------------------------------------------------===// - /// CvtCode enum - This enum defines the various converts CONVERT_RNDSAT - /// supports. + /// This enum defines the various converts CONVERT_RNDSAT supports. enum CvtCode { CVT_FF, /// Float from Float CVT_FS, /// Float from Signed diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h index f1ea2c03f13c..04e840dea2ca 100644 --- a/include/llvm/CodeGen/LiveInterval.h +++ b/include/llvm/CodeGen/LiveInterval.h @@ -190,8 +190,8 @@ namespace llvm { void dump() const; }; - typedef SmallVector<Segment,4> Segments; - typedef SmallVector<VNInfo*,4> VNInfoList; + typedef SmallVector<Segment, 2> Segments; + typedef SmallVector<VNInfo *, 2> VNInfoList; Segments segments; // the liveness segments VNInfoList valnos; // value#'s @@ -613,6 +613,9 @@ namespace llvm { BumpPtrAllocator &Allocator) : LiveRange(Other, Allocator), Next(nullptr), LaneMask(LaneMask) { } + + void print(raw_ostream &OS) const; + void dump() const; }; private: @@ -712,10 +715,6 @@ namespace llvm { /// are not considered valid and should only exist temporarily). void removeEmptySubRanges(); - /// Construct main live range by merging the SubRanges of @p LI. - void constructMainRangeFromSubranges(const SlotIndexes &Indexes, - VNInfo::Allocator &VNIAllocator); - /// getSize - Returns the sum of sizes of all the LiveRange's. /// unsigned getSize() const; @@ -759,6 +758,12 @@ namespace llvm { void freeSubRange(SubRange *S); }; + inline raw_ostream &operator<<(raw_ostream &OS, + const LiveInterval::SubRange &SR) { + SR.print(OS); + return OS; + } + inline raw_ostream &operator<<(raw_ostream &OS, const LiveInterval &LI) { LI.print(OS); return OS; @@ -868,6 +873,5 @@ namespace llvm { void Distribute(LiveInterval &LI, LiveInterval *LIV[], MachineRegisterInfo &MRI); }; - } #endif diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 87421e2f83b4..d4ee0582cc41 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -31,7 +31,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetRegisterInfo.h" #include <cmath> -#include <iterator> namespace llvm { @@ -105,7 +104,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; // Calculate the spill weight to assign to a single instruction. static float getSpillWeight(bool isDef, bool isUse, const MachineBlockFrequencyInfo *MBFI, - const MachineInstr *Instr); + const MachineInstr &Instr); LiveInterval &getInterval(unsigned Reg) { if (hasInterval(Reg)) @@ -145,7 +144,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// Given a register and an instruction, adds a live segment from that /// instruction to the end of its MBB. LiveInterval::Segment addSegmentToEndOfBlock(unsigned reg, - MachineInstr* startInst); + MachineInstr &startInst); /// After removing some uses of a register, shrink its live range to just /// the remaining uses. This method does not compute reaching defs for new @@ -195,13 +194,13 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// isNotInMIMap - returns true if the specified machine instr has been /// removed or was never entered in the map. - bool isNotInMIMap(const MachineInstr* Instr) const { + bool isNotInMIMap(const MachineInstr &Instr) const { return !Indexes->hasIndex(Instr); } /// Returns the base index of the given instruction. - SlotIndex getInstructionIndex(const MachineInstr *instr) const { - return Indexes->getInstructionIndex(instr); + SlotIndex getInstructionIndex(const MachineInstr &Instr) const { + return Indexes->getInstructionIndex(Instr); } /// Returns the instruction associated with the given index. @@ -240,21 +239,21 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; RegMaskBlocks.push_back(std::make_pair(RegMaskSlots.size(), 0)); } - SlotIndex InsertMachineInstrInMaps(MachineInstr *MI) { + SlotIndex InsertMachineInstrInMaps(MachineInstr &MI) { return Indexes->insertMachineInstrInMaps(MI); } void InsertMachineInstrRangeInMaps(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E) { for (MachineBasicBlock::iterator I = B; I != E; ++I) - Indexes->insertMachineInstrInMaps(I); + Indexes->insertMachineInstrInMaps(*I); } - void RemoveMachineInstrFromMaps(MachineInstr *MI) { + void RemoveMachineInstrFromMaps(MachineInstr &MI) { Indexes->removeMachineInstrFromMaps(MI); } - void ReplaceMachineInstrInMaps(MachineInstr *MI, MachineInstr *NewMI) { + void ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI) { Indexes->replaceMachineInstrInMaps(MI, NewMI); } @@ -288,7 +287,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// are not supported. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. - void handleMove(MachineInstr* MI, bool UpdateFlags = false); + void handleMove(MachineInstr &MI, bool UpdateFlags = false); /// moveIntoBundle - Update intervals for operands of MI so that they /// begin/end on the SlotIndex for BundleStart. @@ -298,7 +297,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// Requires MI and BundleStart to have SlotIndexes, and assumes /// existing liveness is accurate. BundleStart should be the first /// instruction in the Bundle. - void handleMoveIntoBundle(MachineInstr* MI, MachineInstr* BundleStart, + void handleMoveIntoBundle(MachineInstr &MI, MachineInstr &BundleStart, bool UpdateFlags = false); /// repairIntervalsInRange - Update live intervals for instructions in a @@ -406,6 +405,11 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; void splitSeparateComponents(LiveInterval &LI, SmallVectorImpl<LiveInterval*> &SplitLIs); + /// For live interval \p LI with correct SubRanges construct matching + /// information for the main live range. Expects the main live range to not + /// have any segments or value numbers. + void constructMainRangeFromSubranges(LiveInterval &LI); + private: /// Compute live intervals for all virtual registers. void computeVirtRegs(); diff --git a/include/llvm/CodeGen/LivePhysRegs.h b/include/llvm/CodeGen/LivePhysRegs.h index 3bdf5ae8d013..1cea9d5b90d6 100644 --- a/include/llvm/CodeGen/LivePhysRegs.h +++ b/include/llvm/CodeGen/LivePhysRegs.h @@ -84,12 +84,8 @@ public: void removeReg(unsigned Reg) { assert(TRI && "LivePhysRegs is not initialized."); assert(Reg <= TRI->getNumRegs() && "Expected a physical register."); - for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true); - SubRegs.isValid(); ++SubRegs) - LiveRegs.erase(*SubRegs); - for (MCSuperRegIterator SuperRegs(Reg, TRI, /*IncludeSelf=*/false); - SuperRegs.isValid(); ++SuperRegs) - LiveRegs.erase(*SuperRegs); + for (MCRegAliasIterator R(Reg, TRI, true); R.isValid(); ++R) + LiveRegs.erase(*R); } /// \brief Removes physical registers clobbered by the regmask operand @p MO. @@ -97,10 +93,15 @@ public: SmallVectorImpl<std::pair<unsigned, const MachineOperand*>> *Clobbers); /// \brief Returns true if register @p Reg is contained in the set. This also - /// works if only the super register of @p Reg has been defined, because we - /// always add also all sub-registers to the set. + /// works if only the super register of @p Reg has been defined, because + /// addReg() always adds all sub-registers to the set as well. + /// Note: Returns false if just some sub registers are live, use available() + /// when searching a free register. bool contains(unsigned Reg) const { return LiveRegs.count(Reg); } + /// Returns true if register \p Reg and no aliasing register is in the set. + bool available(const MachineRegisterInfo &MRI, unsigned Reg) const; + /// \brief Simulates liveness when stepping backwards over an /// instruction(bundle): Remove Defs, add uses. This is the recommended way of /// calculating liveness. @@ -116,15 +117,20 @@ public: void stepForward(const MachineInstr &MI, SmallVectorImpl<std::pair<unsigned, const MachineOperand*>> &Clobbers); - /// \brief Adds all live-in registers of basic block @p MBB; After prologue/ - /// epilogue insertion \p AddPristines should be set to true to insert the + /// Adds all live-in registers of basic block @p MBB. + /// Live in registers are the registers in the blocks live-in list and the /// pristine registers. - void addLiveIns(const MachineBasicBlock *MBB, bool AddPristines = false); + void addLiveIns(const MachineBasicBlock &MBB); + + /// Adds all live-out registers of basic block @p MBB. + /// Live out registers are the union of the live-in registers of the successor + /// blocks and pristine registers. Live out registers of the end block are the + /// callee saved registers. + void addLiveOuts(const MachineBasicBlock &MBB); - /// \brief Adds all live-out registers of basic block @p MBB; After prologue/ - /// epilogue insertion \p AddPristinesAndCSRs should be set to true. - void addLiveOuts(const MachineBasicBlock *MBB, - bool AddPristinesAndCSRs = false); + /// Like addLiveOuts() but does not add pristine registers/callee saved + /// registers. + void addLiveOutsNoPristines(const MachineBasicBlock &MBB); typedef SparseSet<unsigned>::const_iterator const_iterator; const_iterator begin() const { return LiveRegs.begin(); } diff --git a/include/llvm/CodeGen/LiveRangeEdit.h b/include/llvm/CodeGen/LiveRangeEdit.h index 2271e3352aa2..4250777682ba 100644 --- a/include/llvm/CodeGen/LiveRangeEdit.h +++ b/include/llvm/CodeGen/LiveRangeEdit.h @@ -72,6 +72,10 @@ private: /// ScannedRemattable - true when remattable values have been identified. bool ScannedRemattable; + /// DeadRemats - The saved instructions which have already been dead after + /// rematerialization but not deleted yet -- to be done in postOptimization. + SmallPtrSet<MachineInstr *, 32> *DeadRemats; + /// Remattable - Values defined by remattable instructions as identified by /// tii.isTriviallyReMaterializable(). SmallPtrSet<const VNInfo*,4> Remattable; @@ -96,7 +100,8 @@ private: SmallVector<LiveInterval*, 8>, SmallPtrSet<LiveInterval*, 8> > ToShrinkSet; /// Helper for eliminateDeadDefs. - void eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink); + void eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink, + AliasAnalysis *AA); /// MachineRegisterInfo callback to notify when new virtual /// registers are created. @@ -116,13 +121,16 @@ public: /// @param vrm Map of virtual registers to physical registers for this /// function. If NULL, no virtual register map updates will /// be done. This could be the case if called before Regalloc. + /// @param deadRemats The collection of all the instructions defining an + /// original reg and are dead after remat. LiveRangeEdit(LiveInterval *parent, SmallVectorImpl<unsigned> &newRegs, MachineFunction &MF, LiveIntervals &lis, VirtRegMap *vrm, - Delegate *delegate = nullptr) + Delegate *delegate = nullptr, + SmallPtrSet<MachineInstr *, 32> *deadRemats = nullptr) : Parent(parent), NewRegs(newRegs), MRI(MF.getRegInfo()), LIS(lis), - VRM(vrm), TII(*MF.getSubtarget().getInstrInfo()), - TheDelegate(delegate), FirstNew(newRegs.size()), - ScannedRemattable(false) { + VRM(vrm), TII(*MF.getSubtarget().getInstrInfo()), TheDelegate(delegate), + FirstNew(newRegs.size()), ScannedRemattable(false), + DeadRemats(deadRemats) { MRI.setDelegate(this); } @@ -142,6 +150,16 @@ public: bool empty() const { return size() == 0; } unsigned get(unsigned idx) const { return NewRegs[idx+FirstNew]; } + /// pop_back - It allows LiveRangeEdit users to drop new registers. + /// The context is when an original def instruction of a register is + /// dead after rematerialization, we still want to keep it for following + /// rematerializations. We save the def instruction in DeadRemats, + /// and replace the original dst register with a new dummy register so + /// the live range of original dst register can be shrinked normally. + /// We don't want to allocate phys register for the dummy register, so + /// we want to drop it from the NewRegs set. + void pop_back() { NewRegs.pop_back(); } + ArrayRef<unsigned> regs() const { return makeArrayRef(NewRegs).slice(FirstNew); } @@ -175,15 +193,15 @@ public: /// Remat - Information needed to rematerialize at a specific location. struct Remat { VNInfo *ParentVNI; // parent_'s value at the remat location. - MachineInstr *OrigMI; // Instruction defining ParentVNI. + MachineInstr *OrigMI; // Instruction defining OrigVNI. It contains the + // real expr for remat. explicit Remat(VNInfo *ParentVNI) : ParentVNI(ParentVNI), OrigMI(nullptr) {} }; /// canRematerializeAt - Determine if ParentVNI can be rematerialized at /// UseIdx. It is assumed that parent_.getVNINfoAt(UseIdx) == ParentVNI. /// When cheapAsAMove is set, only cheap remats are allowed. - bool canRematerializeAt(Remat &RM, - SlotIndex UseIdx, + bool canRematerializeAt(Remat &RM, VNInfo *OrigVNI, SlotIndex UseIdx, bool cheapAsAMove); /// rematerializeAt - Rematerialize RM.ParentVNI into DestReg by inserting an @@ -208,6 +226,12 @@ public: return Rematted.count(ParentVNI); } + void markDeadRemat(MachineInstr *inst) { + // DeadRemats is an optional field. + if (DeadRemats) + DeadRemats->insert(inst); + } + /// eraseVirtReg - Notify the delegate that Reg is no longer in use, and try /// to erase it from LIS. void eraseVirtReg(unsigned Reg); @@ -218,8 +242,9 @@ public: /// RegsBeingSpilled lists registers currently being spilled by the register /// allocator. These registers should not be split into new intervals /// as currently those new intervals are not guaranteed to spill. - void eliminateDeadDefs(SmallVectorImpl<MachineInstr*> &Dead, - ArrayRef<unsigned> RegsBeingSpilled = None); + void eliminateDeadDefs(SmallVectorImpl<MachineInstr *> &Dead, + ArrayRef<unsigned> RegsBeingSpilled = None, + AliasAnalysis *AA = nullptr); /// calculateRegClassAndHint - Recompute register class and hint for each new /// register. diff --git a/include/llvm/CodeGen/LiveVariables.h b/include/llvm/CodeGen/LiveVariables.h index 55b97dc3e71d..bc210dda08c0 100644 --- a/include/llvm/CodeGen/LiveVariables.h +++ b/include/llvm/CodeGen/LiveVariables.h @@ -91,9 +91,9 @@ public: /// removeKill - Delete a kill corresponding to the specified /// machine instruction. Returns true if there was a kill /// corresponding to this instruction, false otherwise. - bool removeKill(MachineInstr *MI) { - std::vector<MachineInstr*>::iterator - I = std::find(Kills.begin(), Kills.end(), MI); + bool removeKill(MachineInstr &MI) { + std::vector<MachineInstr *>::iterator I = + std::find(Kills.begin(), Kills.end(), &MI); if (I == Kills.end()) return false; Kills.erase(I); @@ -155,10 +155,10 @@ private: // Intermediate data structures /// HandleRegMask - Call HandlePhysRegKill for all registers clobbered by Mask. void HandleRegMask(const MachineOperand&); - void HandlePhysRegUse(unsigned Reg, MachineInstr *MI); + void HandlePhysRegUse(unsigned Reg, MachineInstr &MI); void HandlePhysRegDef(unsigned Reg, MachineInstr *MI, SmallVectorImpl<unsigned> &Defs); - void UpdatePhysRegDefs(MachineInstr *MI, SmallVectorImpl<unsigned> &Defs); + void UpdatePhysRegDefs(MachineInstr &MI, SmallVectorImpl<unsigned> &Defs); /// FindLastRefOrPartRef - Return the last reference or partial reference of /// the specified register. @@ -176,7 +176,7 @@ private: // Intermediate data structures /// is coming from. void analyzePHINodes(const MachineFunction& Fn); - void runOnInstr(MachineInstr *MI, SmallVectorImpl<unsigned> &Defs); + void runOnInstr(MachineInstr &MI, SmallVectorImpl<unsigned> &Defs); void runOnBlock(MachineBasicBlock *MBB, unsigned NumRegs); public: @@ -185,37 +185,37 @@ public: /// RegisterDefIsDead - Return true if the specified instruction defines the /// specified register, but that definition is dead. - bool RegisterDefIsDead(MachineInstr *MI, unsigned Reg) const; + bool RegisterDefIsDead(MachineInstr &MI, unsigned Reg) const; //===--------------------------------------------------------------------===// // API to update live variable information /// replaceKillInstruction - Update register kill info by replacing a kill /// instruction with a new one. - void replaceKillInstruction(unsigned Reg, MachineInstr *OldMI, - MachineInstr *NewMI); + void replaceKillInstruction(unsigned Reg, MachineInstr &OldMI, + MachineInstr &NewMI); /// addVirtualRegisterKilled - Add information about the fact that the /// specified register is killed after being used by the specified /// instruction. If AddIfNotFound is true, add a implicit operand if it's /// not found. - void addVirtualRegisterKilled(unsigned IncomingReg, MachineInstr *MI, + void addVirtualRegisterKilled(unsigned IncomingReg, MachineInstr &MI, bool AddIfNotFound = false) { - if (MI->addRegisterKilled(IncomingReg, TRI, AddIfNotFound)) - getVarInfo(IncomingReg).Kills.push_back(MI); + if (MI.addRegisterKilled(IncomingReg, TRI, AddIfNotFound)) + getVarInfo(IncomingReg).Kills.push_back(&MI); } /// removeVirtualRegisterKilled - Remove the specified kill of the virtual /// register from the live variable information. Returns true if the /// variable was marked as killed by the specified instruction, /// false otherwise. - bool removeVirtualRegisterKilled(unsigned reg, MachineInstr *MI) { + bool removeVirtualRegisterKilled(unsigned reg, MachineInstr &MI) { if (!getVarInfo(reg).removeKill(MI)) return false; bool Removed = false; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); if (MO.isReg() && MO.isKill() && MO.getReg() == reg) { MO.setIsKill(false); Removed = true; @@ -230,28 +230,28 @@ public: /// removeVirtualRegistersKilled - Remove all killed info for the specified /// instruction. - void removeVirtualRegistersKilled(MachineInstr *MI); + void removeVirtualRegistersKilled(MachineInstr &MI); /// addVirtualRegisterDead - Add information about the fact that the specified /// register is dead after being used by the specified instruction. If /// AddIfNotFound is true, add a implicit operand if it's not found. - void addVirtualRegisterDead(unsigned IncomingReg, MachineInstr *MI, + void addVirtualRegisterDead(unsigned IncomingReg, MachineInstr &MI, bool AddIfNotFound = false) { - if (MI->addRegisterDead(IncomingReg, TRI, AddIfNotFound)) - getVarInfo(IncomingReg).Kills.push_back(MI); + if (MI.addRegisterDead(IncomingReg, TRI, AddIfNotFound)) + getVarInfo(IncomingReg).Kills.push_back(&MI); } /// removeVirtualRegisterDead - Remove the specified kill of the virtual /// register from the live variable information. Returns true if the /// variable was marked dead at the specified instruction, false /// otherwise. - bool removeVirtualRegisterDead(unsigned reg, MachineInstr *MI) { + bool removeVirtualRegisterDead(unsigned reg, MachineInstr &MI) { if (!getVarInfo(reg).removeKill(MI)) return false; bool Removed = false; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); if (MO.isReg() && MO.isDef() && MO.getReg() == reg) { MO.setIsDead(false); Removed = true; @@ -278,9 +278,8 @@ public: void MarkVirtRegAliveInBlock(VarInfo& VRInfo, MachineBasicBlock* DefBlock, MachineBasicBlock *BB, std::vector<MachineBasicBlock*> &WorkList); - void HandleVirtRegDef(unsigned reg, MachineInstr *MI); - void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB, - MachineInstr *MI); + void HandleVirtRegDef(unsigned reg, MachineInstr &MI); + void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB, MachineInstr &MI); bool isLiveIn(unsigned Reg, const MachineBasicBlock &MBB) { return getVarInfo(Reg).isLiveIn(MBB, Reg, *MRI); diff --git a/include/llvm/CodeGen/MIRParser/MIRParser.h b/include/llvm/CodeGen/MIRParser/MIRParser.h index a569d5ec1f5e..dd0780397f42 100644 --- a/include/llvm/CodeGen/MIRParser/MIRParser.h +++ b/include/llvm/CodeGen/MIRParser/MIRParser.h @@ -18,7 +18,6 @@ #ifndef LLVM_CODEGEN_MIRPARSER_MIRPARSER_H #define LLVM_CODEGEN_MIRPARSER_MIRPARSER_H -#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineFunctionInitializer.h" #include "llvm/IR/Module.h" #include "llvm/Support/MemoryBuffer.h" @@ -26,6 +25,7 @@ namespace llvm { +class StringRef; class MIRParserImpl; class SMDiagnostic; diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index 14d3744741c5..7f9c44833336 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// // -// The MIR serialization library is currently a work in progress. It can't -// serialize machine functions at this time. -// // This file implements the mapping between various MIR data structures and // their corresponding YAML representation. // @@ -385,6 +382,8 @@ struct MachineFunction { unsigned Alignment = 0; bool ExposesReturnsTwice = false; bool HasInlineAsm = false; + // MachineFunctionProperties + bool AllVRegsAllocated = false; // Register information bool IsSSA = false; bool TracksRegLiveness = false; @@ -408,6 +407,7 @@ template <> struct MappingTraits<MachineFunction> { YamlIO.mapOptional("alignment", MF.Alignment); YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice); YamlIO.mapOptional("hasInlineAsm", MF.HasInlineAsm); + YamlIO.mapOptional("allVRegsAllocated", MF.AllVRegsAllocated); YamlIO.mapOptional("isSSA", MF.IsSSA); YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness); YamlIO.mapOptional("tracksSubRegLiveness", MF.TracksSubRegLiveness); diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index 3d58c499823e..d5f918eb2bb9 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -15,6 +15,8 @@ #define LLVM_CODEGEN_MACHINEBASICBLOCK_H #include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/CodeGen/MachineInstrBundleIterator.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Support/BranchProbability.h" #include "llvm/MC/MCRegisterInfo.h" @@ -157,80 +159,14 @@ public: const MachineFunction *getParent() const { return xParent; } MachineFunction *getParent() { return xParent; } - /// MachineBasicBlock iterator that automatically skips over MIs that are - /// inside bundles (i.e. walk top level MIs only). - template<typename Ty, typename IterTy> - class bundle_iterator - : public std::iterator<std::bidirectional_iterator_tag, Ty, ptrdiff_t> { - IterTy MII; - - public: - bundle_iterator(IterTy MI) : MII(MI) {} - - bundle_iterator(Ty &MI) : MII(MI) { - assert(!MI.isBundledWithPred() && - "It's not legal to initialize bundle_iterator with a bundled MI"); - } - bundle_iterator(Ty *MI) : MII(MI) { - assert((!MI || !MI->isBundledWithPred()) && - "It's not legal to initialize bundle_iterator with a bundled MI"); - } - // Template allows conversion from const to nonconst. - template<class OtherTy, class OtherIterTy> - bundle_iterator(const bundle_iterator<OtherTy, OtherIterTy> &I) - : MII(I.getInstrIterator()) {} - bundle_iterator() : MII(nullptr) {} - - Ty &operator*() const { return *MII; } - Ty *operator->() const { return &operator*(); } - - operator Ty *() const { return MII.getNodePtrUnchecked(); } - - bool operator==(const bundle_iterator &X) const { - return MII == X.MII; - } - bool operator!=(const bundle_iterator &X) const { - return !operator==(X); - } - - // Increment and decrement operators... - bundle_iterator &operator--() { // predecrement - Back up - do --MII; - while (MII->isBundledWithPred()); - return *this; - } - bundle_iterator &operator++() { // preincrement - Advance - while (MII->isBundledWithSucc()) - ++MII; - ++MII; - return *this; - } - bundle_iterator operator--(int) { // postdecrement operators... - bundle_iterator tmp = *this; - --*this; - return tmp; - } - bundle_iterator operator++(int) { // postincrement operators... - bundle_iterator tmp = *this; - ++*this; - return tmp; - } - - IterTy getInstrIterator() const { - return MII; - } - }; - typedef Instructions::iterator instr_iterator; typedef Instructions::const_iterator const_instr_iterator; typedef std::reverse_iterator<instr_iterator> reverse_instr_iterator; typedef std::reverse_iterator<const_instr_iterator> const_reverse_instr_iterator; - typedef - bundle_iterator<MachineInstr,instr_iterator> iterator; - typedef - bundle_iterator<const MachineInstr,const_instr_iterator> const_iterator; + typedef MachineInstrBundleIterator<MachineInstr> iterator; + typedef MachineInstrBundleIterator<const MachineInstr> const_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; @@ -257,6 +193,13 @@ public: reverse_instr_iterator instr_rend () { return Insts.rend(); } const_reverse_instr_iterator instr_rend () const { return Insts.rend(); } + typedef iterator_range<instr_iterator> instr_range; + typedef iterator_range<const_instr_iterator> const_instr_range; + instr_range instrs() { return instr_range(instr_begin(), instr_end()); } + const_instr_range instrs() const { + return const_instr_range(instr_begin(), instr_end()); + } + iterator begin() { return instr_begin(); } const_iterator begin() const { return instr_begin(); } iterator end () { return instr_end(); } @@ -399,10 +342,6 @@ public: /// via an exception handler. void setIsEHPad(bool V = true) { IsEHPad = V; } - /// If this block has a successor that is a landing pad, return it. Otherwise - /// return NULL. - const MachineBasicBlock *getLandingPadSuccessor() const; - bool hasEHPadSuccessor() const; /// Returns true if this is the entry block of an EH funclet. @@ -563,7 +502,13 @@ public: /// /// This function updates LiveVariables, MachineDominatorTree, and /// MachineLoopInfo, as applicable. - MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P); + MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P); + + /// Check if the edge between this block and the given successor \p + /// Succ, can be split. If this returns true a subsequent call to + /// SplitCriticalEdge is guaranteed to return a valid basic block if + /// no changes occured in the meantime. + bool canSplitCriticalEdge(const MachineBasicBlock *Succ) const; void pop_front() { Insts.pop_front(); } void pop_back() { Insts.pop_back(); } @@ -729,9 +674,9 @@ public: // Debugging methods. void dump() const; - void print(raw_ostream &OS, SlotIndexes* = nullptr) const; + void print(raw_ostream &OS, const SlotIndexes* = nullptr) const; void print(raw_ostream &OS, ModuleSlotTracker &MST, - SlotIndexes * = nullptr) const; + const SlotIndexes* = nullptr) const; // Printing method used by LoopInfo. void printAsOperand(raw_ostream &OS, bool PrintType = true) const; diff --git a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h index feb394e7a69e..7a236086ed09 100644 --- a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h +++ b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H #define LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H +#include "llvm/ADT/Optional.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/Support/BlockFrequency.h" #include <climits> @@ -50,7 +51,10 @@ public: /// BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const; + Optional<uint64_t> getBlockProfileCount(const MachineBasicBlock *MBB) const; + const MachineFunction *getFunction() const; + const MachineBranchProbabilityInfo *getMBPI() const; void view() const; // Print the block frequency Freq to OS using the current functions entry diff --git a/include/llvm/CodeGen/MachineCombinerPattern.h b/include/llvm/CodeGen/MachineCombinerPattern.h index f3891227746f..11238016d447 100644 --- a/include/llvm/CodeGen/MachineCombinerPattern.h +++ b/include/llvm/CodeGen/MachineCombinerPattern.h @@ -38,7 +38,40 @@ enum class MachineCombinerPattern { MULSUBX_OP1, MULSUBX_OP2, MULADDXI_OP1, - MULSUBXI_OP1 + MULSUBXI_OP1, + // Floating Point + FMULADDS_OP1, + FMULADDS_OP2, + FMULSUBS_OP1, + FMULSUBS_OP2, + FMULADDD_OP1, + FMULADDD_OP2, + FMULSUBD_OP1, + FMULSUBD_OP2, + FMLAv1i32_indexed_OP1, + FMLAv1i32_indexed_OP2, + FMLAv1i64_indexed_OP1, + FMLAv1i64_indexed_OP2, + FMLAv2f32_OP2, + FMLAv2f32_OP1, + FMLAv2f64_OP1, + FMLAv2f64_OP2, + FMLAv2i32_indexed_OP1, + FMLAv2i32_indexed_OP2, + FMLAv2i64_indexed_OP1, + FMLAv2i64_indexed_OP2, + FMLAv4f32_OP1, + FMLAv4f32_OP2, + FMLAv4i32_indexed_OP1, + FMLAv4i32_indexed_OP2, + FMLSv1i32_indexed_OP2, + FMLSv1i64_indexed_OP2, + FMLSv2i32_indexed_OP2, + FMLSv2i64_indexed_OP2, + FMLSv2f32_OP2, + FMLSv2f64_OP2, + FMLSv4i32_indexed_OP2, + FMLSv4f32_OP2 }; } // end namespace llvm diff --git a/include/llvm/CodeGen/MachineDominators.h b/include/llvm/CodeGen/MachineDominators.h index a69936f6e267..ed7cc277e8b6 100644 --- a/include/llvm/CodeGen/MachineDominators.h +++ b/include/llvm/CodeGen/MachineDominators.h @@ -216,6 +216,8 @@ public: void releaseMemory() override; + void verifyAnalysis() const override; + void print(raw_ostream &OS, const Module*) const override; /// \brief Record that the critical edge (FromBB, ToBB) has been @@ -239,6 +241,27 @@ public: "A basic block inserted via edge splitting cannot appear twice"); CriticalEdgesToSplit.push_back({FromBB, ToBB, NewBB}); } + + /// \brief Returns *false* if the other dominator tree matches this dominator + /// tree. + inline bool compare(const MachineDominatorTree &Other) const { + const MachineDomTreeNode *R = getRootNode(); + const MachineDomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(*Other.DT)) + return true; + + return false; + } + + /// \brief Verify the correctness of the domtree by re-computing it. + /// + /// This should only be used for debugging as it aborts the program if the + /// verification fails. + void verifyDomTree() const; }; //===------------------------------------- diff --git a/include/llvm/CodeGen/MachineFrameInfo.h b/include/llvm/CodeGen/MachineFrameInfo.h index e50779aacc23..59755674c69e 100644 --- a/include/llvm/CodeGen/MachineFrameInfo.h +++ b/include/llvm/CodeGen/MachineFrameInfo.h @@ -122,21 +122,28 @@ class MachineFrameInfo { // arguments have ABI-prescribed offsets). bool isAliased; + /// If true, the object has been zero-extended. + bool isZExt; + + /// If true, the object has been zero-extended. + bool isSExt; + StackObject(uint64_t Sz, unsigned Al, int64_t SP, bool IM, bool isSS, const AllocaInst *Val, bool A) : SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM), isSpillSlot(isSS), isStatepointSpillSlot(false), Alloca(Val), - PreAllocated(false), isAliased(A) {} + PreAllocated(false), isAliased(A), isZExt(false), isSExt(false) {} }; /// The alignment of the stack. unsigned StackAlignment; - /// Can the stack be realigned. - /// Targets that set this to false don't have the ability to overalign - /// their stack frame, and thus, overaligned allocas are all treated - /// as dynamic allocations and the target must handle them as part - /// of DYNAMIC_STACKALLOC lowering. + /// Can the stack be realigned. This can be false if the target does not + /// support stack realignment, or if the user asks us not to realign the + /// stack. In this situation, overaligned allocas are all treated as dynamic + /// allocations and the target must handle them as part of DYNAMIC_STACKALLOC + /// lowering. All non-alloca stack objects have their alignment clamped to the + /// base ABI stack alignment. /// FIXME: There is room for improvement in this case, in terms of /// grouping overaligned allocas into a "secondary stack frame" and /// then only use a single alloca to allocate this frame and only a @@ -145,39 +152,42 @@ class MachineFrameInfo { /// realignment. bool StackRealignable; + /// Whether the function has the \c alignstack attribute. + bool ForcedRealign; + /// The list of stack objects allocated. std::vector<StackObject> Objects; /// This contains the number of fixed objects contained on /// the stack. Because fixed objects are stored at a negative index in the /// Objects list, this is also the index to the 0th object in the list. - unsigned NumFixedObjects; + unsigned NumFixedObjects = 0; /// This boolean keeps track of whether any variable /// sized objects have been allocated yet. - bool HasVarSizedObjects; + bool HasVarSizedObjects = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.frameaddress. - bool FrameAddressTaken; + bool FrameAddressTaken = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.returnaddress. - bool ReturnAddressTaken; + bool ReturnAddressTaken = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.experimental.stackmap. - bool HasStackMap; + bool HasStackMap = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.experimental.patchpoint. - bool HasPatchPoint; + bool HasPatchPoint = false; /// The prolog/epilog code inserter calculates the final stack /// offsets for all of the fixed size objects, updating the Objects list /// above. It then updates StackSize to contain the number of bytes that need /// to be allocated on entry to the function. - uint64_t StackSize; + uint64_t StackSize = 0; /// The amount that a frame offset needs to be adjusted to /// have the actual offset from the stack/frame pointer. The exact usage of @@ -188,7 +198,7 @@ class MachineFrameInfo { /// targets, this value is only used when generating debug info (via /// TargetRegisterInfo::getFrameIndexReference); when generating code, the /// corresponding adjustments are performed directly. - int OffsetAdjustment; + int OffsetAdjustment = 0; /// The prolog/epilog code inserter may process objects that require greater /// alignment than the default alignment the target provides. @@ -197,27 +207,27 @@ class MachineFrameInfo { /// native alignment maintained by the compiler, dynamic alignment code will /// be needed. /// - unsigned MaxAlignment; + unsigned MaxAlignment = 0; /// Set to true if this function adjusts the stack -- e.g., /// when calling another function. This is only valid during and after /// prolog/epilog code insertion. - bool AdjustsStack; + bool AdjustsStack = false; /// Set to true if this function has any function calls. - bool HasCalls; + bool HasCalls = false; /// The frame index for the stack protector. - int StackProtectorIdx; + int StackProtectorIdx = -1; /// The frame index for the function context. Used for SjLj exceptions. - int FunctionContextIdx; + int FunctionContextIdx = -1; /// This contains the size of the largest call frame if the target uses frame /// setup/destroy pseudo instructions (as defined in the TargetFrameInfo /// class). This information is important for frame pointer elimination. /// It is only valid during and after prolog/epilog code insertion. - unsigned MaxCallFrameSize; + unsigned MaxCallFrameSize = 0; /// The prolog/epilog code inserter fills in this vector with each /// callee saved register saved in the frame. Beyond its use by the prolog/ @@ -226,79 +236,53 @@ class MachineFrameInfo { std::vector<CalleeSavedInfo> CSInfo; /// Has CSInfo been set yet? - bool CSIValid; + bool CSIValid = false; /// References to frame indices which are mapped /// into the local frame allocation block. <FrameIdx, LocalOffset> SmallVector<std::pair<int, int64_t>, 32> LocalFrameObjects; /// Size of the pre-allocated local frame block. - int64_t LocalFrameSize; + int64_t LocalFrameSize = 0; /// Required alignment of the local object blob, which is the strictest /// alignment of any object in it. - unsigned LocalFrameMaxAlign; + unsigned LocalFrameMaxAlign = 0; /// Whether the local object blob needs to be allocated together. If not, /// PEI should ignore the isPreAllocated flags on the stack objects and /// just allocate them normally. - bool UseLocalStackAllocationBlock; - - /// Whether the "realign-stack" option is on. - bool RealignOption; + bool UseLocalStackAllocationBlock = false; /// True if the function dynamically adjusts the stack pointer through some /// opaque mechanism like inline assembly or Win32 EH. - bool HasOpaqueSPAdjustment; + bool HasOpaqueSPAdjustment = false; /// True if the function contains operations which will lower down to /// instructions which manipulate the stack pointer. - bool HasCopyImplyingStackAdjustment; + bool HasCopyImplyingStackAdjustment = false; /// True if the function contains a call to the llvm.vastart intrinsic. - bool HasVAStart; + bool HasVAStart = false; /// True if this is a varargs function that contains a musttail call. - bool HasMustTailInVarArgFunc; + bool HasMustTailInVarArgFunc = false; /// True if this function contains a tail call. If so immutable objects like /// function arguments are no longer so. A tail call *can* override fixed /// stack objects like arguments so we can't treat them as immutable. - bool HasTailCall; + bool HasTailCall = false; /// Not null, if shrink-wrapping found a better place for the prologue. - MachineBasicBlock *Save; + MachineBasicBlock *Save = nullptr; /// Not null, if shrink-wrapping found a better place for the epilogue. - MachineBasicBlock *Restore; + MachineBasicBlock *Restore = nullptr; public: - explicit MachineFrameInfo(unsigned StackAlign, bool isStackRealign, - bool RealignOpt) - : StackAlignment(StackAlign), StackRealignable(isStackRealign), - RealignOption(RealignOpt) { - StackSize = NumFixedObjects = OffsetAdjustment = MaxAlignment = 0; - HasVarSizedObjects = false; - FrameAddressTaken = false; - ReturnAddressTaken = false; - HasStackMap = false; - HasPatchPoint = false; - AdjustsStack = false; - HasCalls = false; - StackProtectorIdx = -1; - FunctionContextIdx = -1; - MaxCallFrameSize = 0; - CSIValid = false; - LocalFrameSize = 0; - LocalFrameMaxAlign = 0; - UseLocalStackAllocationBlock = false; - HasOpaqueSPAdjustment = false; - HasCopyImplyingStackAdjustment = false; - HasVAStart = false; - HasMustTailInVarArgFunc = false; - Save = nullptr; - Restore = nullptr; - HasTailCall = false; - } + explicit MachineFrameInfo(unsigned StackAlignment, bool StackRealignable, + bool ForcedRealign) + : StackAlignment(StackAlignment), StackRealignable(StackRealignable), + ForcedRealign(ForcedRealign) {} /// Return true if there are any stack objects in this function. bool hasStackObjects() const { return !Objects.empty(); } @@ -450,6 +434,30 @@ public: return Objects[ObjectIdx+NumFixedObjects].SPOffset; } + bool isObjectZExt(int ObjectIdx) const { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + return Objects[ObjectIdx+NumFixedObjects].isZExt; + } + + void setObjectZExt(int ObjectIdx, bool IsZExt) { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + Objects[ObjectIdx+NumFixedObjects].isZExt = IsZExt; + } + + bool isObjectSExt(int ObjectIdx) const { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + return Objects[ObjectIdx+NumFixedObjects].isSExt; + } + + void setObjectSExt(int ObjectIdx, bool IsSExt) { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + Objects[ObjectIdx+NumFixedObjects].isSExt = IsSExt; + } + /// Set the stack frame offset of the specified object. The /// offset is relative to the stack pointer on entry to the function. void setObjectOffset(int ObjectIdx, int64_t SPOffset) { diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index df7c951743c9..4aa9a92e6bee 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -18,12 +18,15 @@ #ifndef LLVM_CODEGEN_MACHINEFUNCTION_H #define LLVM_CODEGEN_MACHINEFUNCTION_H +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/ilist.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ArrayRecycler.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Recycler.h" namespace llvm { @@ -50,6 +53,8 @@ struct ilist_traits<MachineBasicBlock> : public ilist_default_traits<MachineBasicBlock> { mutable ilist_half_node<MachineBasicBlock> Sentinel; public: + // FIXME: This downcast is UB. See llvm.org/PR26753. + LLVM_NO_SANITIZE("object-size") MachineBasicBlock *createSentinel() const { return static_cast<MachineBasicBlock*>(&Sentinel); } @@ -85,6 +90,74 @@ struct MachineFunctionInfo { } }; +/// Properties which a MachineFunction may have at a given point in time. +/// Each of these has checking code in the MachineVerifier, and passes can +/// require that a property be set. +class MachineFunctionProperties { + // TODO: Add MachineVerifier checks for AllVRegsAllocated + // TODO: Add a way to print the properties and make more useful error messages + // Possible TODO: Allow targets to extend this (perhaps by allowing the + // constructor to specify the size of the bit vector) + // Possible TODO: Allow requiring the negative (e.g. VRegsAllocated could be + // stated as the negative of "has vregs" + +public: + // The properties are stated in "positive" form; i.e. a pass could require + // that the property hold, but not that it does not hold. + + // Property descriptions: + // IsSSA: True when the machine function is in SSA form and virtual registers + // have a single def. + // TracksLiveness: True when tracking register liveness accurately. + // While this property is set, register liveness information in basic block + // live-in lists and machine instruction operands (e.g. kill flags, implicit + // defs) is accurate. This means it can be used to change the code in ways + // that affect the values in registers, for example by the register + // scavenger. + // When this property is clear, liveness is no longer reliable. + // AllVRegsAllocated: All virtual registers have been allocated; i.e. all + // register operands are physical registers. + enum class Property : unsigned { + IsSSA, + TracksLiveness, + AllVRegsAllocated, + LastProperty, + }; + + bool hasProperty(Property P) const { + return Properties[static_cast<unsigned>(P)]; + } + MachineFunctionProperties &set(Property P) { + Properties.set(static_cast<unsigned>(P)); + return *this; + } + MachineFunctionProperties &clear(Property P) { + Properties.reset(static_cast<unsigned>(P)); + return *this; + } + MachineFunctionProperties &set(const MachineFunctionProperties &MFP) { + Properties |= MFP.Properties; + return *this; + } + MachineFunctionProperties &clear(const MachineFunctionProperties &MFP) { + Properties.reset(MFP.Properties); + return *this; + } + // Returns true if all properties set in V (i.e. required by a pass) are set + // in this. + bool verifyRequiredProperties(const MachineFunctionProperties &V) const { + return !V.Properties.test(Properties); + } + + // Print the MachineFunctionProperties in human-readable form. If OnlySet is + // true, only print the properties that are set. + void print(raw_ostream &ROS, bool OnlySet=false) const; + +private: + BitVector Properties = + BitVector(static_cast<unsigned>(Property::LastProperty)); +}; + class MachineFunction { const Function *Fn; const TargetMachine &Target; @@ -146,10 +219,14 @@ class MachineFunction { /// the attribute itself. /// This is used to limit optimizations which cannot reason /// about the control flow of such functions. - bool ExposesReturnsTwice; + bool ExposesReturnsTwice = false; /// True if the function includes any inline assembly. - bool HasInlineAsm; + bool HasInlineAsm = false; + + /// Current high-level properties of the IR of the function (e.g. is in SSA + /// form or whether registers have been allocated) + MachineFunctionProperties Properties; // Allocation management for pseudo source values. std::unique_ptr<PseudoSourceValueManager> PSVManager; @@ -268,6 +345,10 @@ public: HasInlineAsm = B; } + /// Get the function properties + const MachineFunctionProperties &getProperties() const { return Properties; } + MachineFunctionProperties &getProperties() { return Properties; } + /// getInfo - Keep track of various per-function pieces of information for /// backends that would like to do so. /// @@ -311,7 +392,7 @@ public: /// print - Print out the MachineFunction in a format suitable for debugging /// to the specified stream. /// - void print(raw_ostream &OS, SlotIndexes* = nullptr) const; + void print(raw_ostream &OS, const SlotIndexes* = nullptr) const; /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the @@ -332,9 +413,11 @@ public: /// void dump() const; - /// verify - Run the current MachineFunction through the machine code - /// verifier, useful for debugger use. - void verify(Pass *p = nullptr, const char *Banner = nullptr) const; + /// Run the current MachineFunction through the machine code verifier, useful + /// for debugger use. + /// \returns true if no problems were found. + bool verify(Pass *p = nullptr, const char *Banner = nullptr, + bool AbortOnError = true) const; // Provide accessors for the MachineBasicBlock list... typedef BasicBlockListType::iterator iterator; @@ -420,8 +503,7 @@ public: /// CreateMachineInstr - Allocate a new MachineInstr. Use this instead /// of `new MachineInstr'. /// - MachineInstr *CreateMachineInstr(const MCInstrDesc &MCID, - DebugLoc DL, + MachineInstr *CreateMachineInstr(const MCInstrDesc &MCID, const DebugLoc &DL, bool NoImp = false); /// CloneMachineInstr - Create a new MachineInstr which is a copy of the @@ -449,8 +531,8 @@ public: /// MachineMemOperands are owned by the MachineFunction and need not be /// explicitly deallocated. MachineMemOperand *getMachineMemOperand(MachinePointerInfo PtrInfo, - unsigned f, uint64_t s, - unsigned base_alignment, + MachineMemOperand::Flags f, + uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); diff --git a/include/llvm/CodeGen/MachineFunctionPass.h b/include/llvm/CodeGen/MachineFunctionPass.h index 50a1f6e96217..653d1175d04b 100644 --- a/include/llvm/CodeGen/MachineFunctionPass.h +++ b/include/llvm/CodeGen/MachineFunctionPass.h @@ -20,16 +20,24 @@ #define LLVM_CODEGEN_MACHINEFUNCTIONPASS_H #include "llvm/Pass.h" +#include "llvm/CodeGen/MachineFunction.h" namespace llvm { -class MachineFunction; - /// MachineFunctionPass - This class adapts the FunctionPass interface to /// allow convenient creation of passes that operate on the MachineFunction /// representation. Instead of overriding runOnFunction, subclasses /// override runOnMachineFunction. class MachineFunctionPass : public FunctionPass { +public: + bool doInitialization(Module&) override { + // Cache the properties info at module-init time so we don't have to + // construct them for every function. + RequiredProperties = getRequiredProperties(); + SetProperties = getSetProperties(); + ClearedProperties = getClearedProperties(); + return false; + } protected: explicit MachineFunctionPass(char &ID) : FunctionPass(ID) {} @@ -46,7 +54,21 @@ protected: /// void getAnalysisUsage(AnalysisUsage &AU) const override; + virtual MachineFunctionProperties getRequiredProperties() const { + return MachineFunctionProperties(); + } + virtual MachineFunctionProperties getSetProperties() const { + return MachineFunctionProperties(); + } + virtual MachineFunctionProperties getClearedProperties() const { + return MachineFunctionProperties(); + } + private: + MachineFunctionProperties RequiredProperties; + MachineFunctionProperties SetProperties; + MachineFunctionProperties ClearedProperties; + /// createPrinterPass - Get a machine function printer pass. Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const override; diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h index 05c9a9e0b079..8f1cb9b6f659 100644 --- a/include/llvm/CodeGen/MachineInstr.h +++ b/include/llvm/CodeGen/MachineInstr.h @@ -16,16 +16,13 @@ #ifndef LLVM_CODEGEN_MACHINEINSTR_H #define LLVM_CODEGEN_MACHINEINSTR_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/InlineAsm.h" #include "llvm/MC/MCInstrDesc.h" @@ -34,10 +31,17 @@ namespace llvm { +class StringRef; +template <typename T> class ArrayRef; template <typename T> class SmallVectorImpl; +class DILocalVariable; +class DIExpression; class TargetInstrInfo; class TargetRegisterClass; class TargetRegisterInfo; +#ifdef LLVM_BUILD_GLOBAL_ISEL +class Type; +#endif class MachineFunction; class MachineMemOperand; @@ -102,6 +106,13 @@ private: DebugLoc debugLoc; // Source line information. +#ifdef LLVM_BUILD_GLOBAL_ISEL + /// Type of the instruction in case of a generic opcode. + /// \invariant This must be nullptr is getOpcode() is not + /// in the range of generic opcodes. + Type *Ty; +#endif + MachineInstr(const MachineInstr&) = delete; void operator=(const MachineInstr&) = delete; // Use MachineFunction::DeleteMachineInstr() instead. @@ -176,6 +187,11 @@ public: Flags &= ~((uint8_t)Flag); } + /// Set the type of the instruction. + /// \pre getOpcode() is in the range of the generic opcodes. + void setType(Type *Ty); + Type *getType() const; + /// Return true if MI is in a bundle (but not the first MI in a bundle). /// /// A bundle looks like this before it's finalized: @@ -248,17 +264,11 @@ public: /// Return the debug variable referenced by /// this DBG_VALUE instruction. - const DILocalVariable *getDebugVariable() const { - assert(isDebugValue() && "not a DBG_VALUE"); - return cast<DILocalVariable>(getOperand(2).getMetadata()); - } + const DILocalVariable *getDebugVariable() const; /// Return the complex address expression referenced by /// this DBG_VALUE instruction. - const DIExpression *getDebugExpression() const { - assert(isDebugValue() && "not a DBG_VALUE"); - return cast<DIExpression>(getOperand(3).getMetadata()); - } + const DIExpression *getDebugExpression() const; /// Emit an error referring to the source location of this instruction. /// This should only be used for inline assembly that is somehow @@ -343,6 +353,14 @@ public: return make_range(operands_begin() + getDesc().getNumDefs(), operands_end()); } + iterator_range<mop_iterator> explicit_uses() { + return make_range(operands_begin() + getDesc().getNumDefs(), + operands_begin() + getNumExplicitOperands() ); + } + iterator_range<const_mop_iterator> explicit_uses() const { + return make_range(operands_begin() + getDesc().getNumDefs(), + operands_begin() + getNumExplicitOperands() ); + } /// Returns the number of the operand iterator \p I points to. unsigned getOperandNo(const_mop_iterator I) const { @@ -508,6 +526,11 @@ public: /// Convergent instructions can not be made control-dependent on any /// additional values. bool isConvergent(QueryType Type = AnyInBundle) const { + if (isInlineAsm()) { + unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_IsConvergent) + return true; + } return hasProperty(MCID::Convergent, Type); } @@ -713,7 +736,7 @@ public: /// Return true if this instruction is identical to (same /// opcode and same operands as) the specified instruction. - bool isIdenticalTo(const MachineInstr *Other, + bool isIdenticalTo(const MachineInstr &Other, MICheckType Check = CheckDefs) const; /// Unlink 'this' from the containing basic block, and return it without @@ -899,6 +922,10 @@ public: return findRegisterDefOperandIdx(Reg, true, false, TRI) != -1; } + /// Returns true if the MachineInstr has an implicit-use operand of exactly + /// the given register (not considering sub/super-registers). + bool hasRegisterImplicitUseOperand(unsigned Reg) const; + /// Returns the operand index that is a use of the specific register or -1 /// if it is not found. It further tightens the search criteria to a use /// that kills the register if isKill is true. @@ -1054,8 +1081,8 @@ public: const TargetRegisterInfo *RegInfo, bool AddIfNotFound = false); - /// Clear all kill flags affecting Reg. If RegInfo is - /// provided, this includes super-register kills. + /// Clear all kill flags affecting Reg. If RegInfo is provided, this includes + /// all aliasing registers. void clearRegisterKills(unsigned Reg, const TargetRegisterInfo *RegInfo); /// We have determined MI defined a register without a use. @@ -1125,7 +1152,7 @@ public: /// Copy implicit register operands from specified /// instruction to this instruction. - void copyImplicitOps(MachineFunction &MF, const MachineInstr *MI); + void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI); // // Debugging support @@ -1168,7 +1195,7 @@ public: assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); } - /// Erase an operand from an instruction, leaving it with one + /// Erase an operand from an instruction, leaving it with one /// fewer operand than it started with. void RemoveOperand(unsigned i); @@ -1268,7 +1295,7 @@ struct MachineInstrExpressionTrait : DenseMapInfo<MachineInstr*> { if (RHS == getEmptyKey() || RHS == getTombstoneKey() || LHS == getEmptyKey() || LHS == getTombstoneKey()) return LHS == RHS; - return LHS->isIdenticalTo(RHS, MachineInstr::IgnoreVRegDefs); + return LHS->isIdenticalTo(*RHS, MachineInstr::IgnoreVRegDefs); } }; diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 8fe9b280d5d2..37b67aa0cf5c 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -10,7 +10,9 @@ // This file exposes a function named BuildMI, which is useful for dramatically // simplifying how MachineInstr's are created. It allows use of code like this: // -// M = BuildMI(X86::ADDrr8, 2).addReg(argVal1).addReg(argVal2); +// M = BuildMI(MBB, MI, DL, TII.get(X86::ADD8rr), Dst) +// .addReg(argVal1) +// .addReg(argVal2); // //===----------------------------------------------------------------------===// @@ -51,6 +53,8 @@ public: /// Create a MachineInstrBuilder for manipulating an existing instruction. /// F must be the machine function that was used to allocate I. MachineInstrBuilder(MachineFunction &F, MachineInstr *I) : MF(&F), MI(I) {} + MachineInstrBuilder(MachineFunction &F, MachineBasicBlock::iterator I) + : MF(&F), MI(&*I) {} /// Allow automatic conversion to the machine instruction we are working on. operator MachineInstr*() const { return MI; } @@ -228,25 +232,22 @@ public: /// Copy all the implicit operands from OtherMI onto this one. const MachineInstrBuilder & - copyImplicitOps(const MachineInstr *OtherMI) const { + copyImplicitOps(const MachineInstr &OtherMI) const { MI->copyImplicitOps(*MF, OtherMI); return *this; } }; /// Builder interface. Specify how to create the initial instruction itself. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID) { return MachineInstrBuilder(MF, MF.CreateMachineInstr(MCID, DL)); } /// This version of the builder sets up the first operand as a /// destination virtual register. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, - DebugLoc DL, - const MCInstrDesc &MCID, - unsigned DestReg) { +inline MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, + const MCInstrDesc &MCID, unsigned DestReg) { return MachineInstrBuilder(MF, MF.CreateMachineInstr(MCID, DL)) .addReg(DestReg, RegState::Define); } @@ -256,8 +257,7 @@ inline MachineInstrBuilder BuildMI(MachineFunction &MF, /// operand as a destination virtual register. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::iterator I, - DebugLoc DL, - const MCInstrDesc &MCID, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -265,10 +265,15 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI).addReg(DestReg, RegState::Define); } +/// This version of the builder inserts the newly-built instruction before +/// the given position in the given MachineBasicBlock, and sets up the first +/// operand as a destination virtual register. +/// +/// If \c I is inside a bundle, then the newly inserted \a MachineInstr is +/// added to the same bundle. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::instr_iterator I, - DebugLoc DL, - const MCInstrDesc &MCID, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -276,18 +281,20 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI).addReg(DestReg, RegState::Define); } -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineInstr *I, - DebugLoc DL, - const MCInstrDesc &MCID, +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr &I, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { - if (I->isInsideBundle()) { - MachineBasicBlock::instr_iterator MII(I); - return BuildMI(BB, MII, DL, MCID, DestReg); - } + // Calling the overload for instr_iterator is always correct. However, the + // definition is not available in headers, so inline the check. + if (I.isInsideBundle()) + return BuildMI(BB, MachineBasicBlock::instr_iterator(I), DL, MCID, DestReg); + return BuildMI(BB, MachineBasicBlock::iterator(I), DL, MCID, DestReg); +} - MachineBasicBlock::iterator MII = I; - return BuildMI(BB, MII, DL, MCID, DestReg); +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr *I, + const DebugLoc &DL, const MCInstrDesc &MCID, + unsigned DestReg) { + return BuildMI(BB, *I, DL, MCID, DestReg); } /// This version of the builder inserts the newly-built instruction before the @@ -295,7 +302,7 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, /// destination register. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::iterator I, - DebugLoc DL, + const DebugLoc &DL, const MCInstrDesc &MCID) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -305,7 +312,7 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::instr_iterator I, - DebugLoc DL, + const DebugLoc &DL, const MCInstrDesc &MCID) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -313,23 +320,25 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI); } -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineInstr *I, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr &I, + const DebugLoc &DL, const MCInstrDesc &MCID) { - if (I->isInsideBundle()) { - MachineBasicBlock::instr_iterator MII(I); - return BuildMI(BB, MII, DL, MCID); - } + // Calling the overload for instr_iterator is always correct. However, the + // definition is not available in headers, so inline the check. + if (I.isInsideBundle()) + return BuildMI(BB, MachineBasicBlock::instr_iterator(I), DL, MCID); + return BuildMI(BB, MachineBasicBlock::iterator(I), DL, MCID); +} - MachineBasicBlock::iterator MII = I; - return BuildMI(BB, MII, DL, MCID); +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr *I, + const DebugLoc &DL, + const MCInstrDesc &MCID) { + return BuildMI(BB, *I, DL, MCID); } /// This version of the builder inserts the newly-built instruction at the end /// of the given MachineBasicBlock, and does NOT take a destination register. -inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, const DebugLoc &DL, const MCInstrDesc &MCID) { return BuildMI(*BB, BB->end(), DL, MCID); } @@ -337,10 +346,8 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, /// This version of the builder inserts the newly-built instruction at the /// end of the given MachineBasicBlock, and sets up the first operand as a /// destination virtual register. -inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, - DebugLoc DL, - const MCInstrDesc &MCID, - unsigned DestReg) { +inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, const DebugLoc &DL, + const MCInstrDesc &MCID, unsigned DestReg) { return BuildMI(*BB, BB->end(), DL, MCID, DestReg); } @@ -348,47 +355,19 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, /// for either a value in a register or a register-indirect+offset /// address. The convention is that a DBG_VALUE is indirect iff the /// second operand is an immediate. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, - const MCInstrDesc &MCID, bool IsIndirect, - unsigned Reg, unsigned Offset, - const MDNode *Variable, const MDNode *Expr) { - assert(isa<DILocalVariable>(Variable) && "not a variable"); - assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); - assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); - if (IsIndirect) - return BuildMI(MF, DL, MCID) - .addReg(Reg, RegState::Debug) - .addImm(Offset) - .addMetadata(Variable) - .addMetadata(Expr); - else { - assert(Offset == 0 && "A direct address cannot have an offset."); - return BuildMI(MF, DL, MCID) - .addReg(Reg, RegState::Debug) - .addReg(0U, RegState::Debug) - .addMetadata(Variable) - .addMetadata(Expr); - } -} +MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, + const MCInstrDesc &MCID, bool IsIndirect, + unsigned Reg, unsigned Offset, + const MDNode *Variable, const MDNode *Expr); /// This version of the builder builds a DBG_VALUE intrinsic /// for either a value in a register or a register-indirect+offset /// address and inserts it at position I. -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineBasicBlock::iterator I, DebugLoc DL, - const MCInstrDesc &MCID, bool IsIndirect, - unsigned Reg, unsigned Offset, - const MDNode *Variable, const MDNode *Expr) { - assert(isa<DILocalVariable>(Variable) && "not a variable"); - assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); - MachineFunction &MF = *BB.getParent(); - MachineInstr *MI = - BuildMI(MF, DL, MCID, IsIndirect, Reg, Offset, Variable, Expr); - BB.insert(I, MI); - return MachineInstrBuilder(MF, MI); -} - +MachineInstrBuilder BuildMI(MachineBasicBlock &BB, + MachineBasicBlock::iterator I, const DebugLoc &DL, + const MCInstrDesc &MCID, bool IsIndirect, + unsigned Reg, unsigned Offset, + const MDNode *Variable, const MDNode *Expr); inline unsigned getDefRegState(bool B) { return B ? RegState::Define : 0; @@ -412,6 +391,17 @@ inline unsigned getDebugRegState(bool B) { return B ? RegState::Debug : 0; } +/// Get all register state flags from machine operand \p RegOp. +inline unsigned getRegState(const MachineOperand &RegOp) { + assert(RegOp.isReg() && "Not a register operand"); + return getDefRegState(RegOp.isDef()) | + getImplRegState(RegOp.isImplicit()) | + getKillRegState(RegOp.isKill()) | + getDeadRegState(RegOp.isDead()) | + getUndefRegState(RegOp.isUndef()) | + getInternalReadRegState(RegOp.isInternalRead()) | + getDebugRegState(RegOp.isDebug()); +} /// Helper class for constructing bundles of MachineInstrs. /// @@ -426,28 +416,26 @@ class MIBundleBuilder { public: /// Create an MIBundleBuilder that inserts instructions into a new bundle in /// BB above the bundle or instruction at Pos. - MIBundleBuilder(MachineBasicBlock &BB, - MachineBasicBlock::iterator Pos) - : MBB(BB), Begin(Pos.getInstrIterator()), End(Begin) {} + MIBundleBuilder(MachineBasicBlock &BB, MachineBasicBlock::iterator Pos) + : MBB(BB), Begin(Pos.getInstrIterator()), End(Begin) {} /// Create a bundle from the sequence of instructions between B and E. - MIBundleBuilder(MachineBasicBlock &BB, - MachineBasicBlock::iterator B, + MIBundleBuilder(MachineBasicBlock &BB, MachineBasicBlock::iterator B, MachineBasicBlock::iterator E) - : MBB(BB), Begin(B.getInstrIterator()), End(E.getInstrIterator()) { + : MBB(BB), Begin(B.getInstrIterator()), End(E.getInstrIterator()) { assert(B != E && "No instructions to bundle"); ++B; while (B != E) { - MachineInstr *MI = B; + MachineInstr &MI = *B; ++B; - MI->bundleWithPred(); + MI.bundleWithPred(); } } /// Create an MIBundleBuilder representing an existing instruction or bundle /// that has MI as its head. explicit MIBundleBuilder(MachineInstr *MI) - : MBB(*MI->getParent()), Begin(MI), End(getBundleEnd(MI)) {} + : MBB(*MI->getParent()), Begin(MI), End(getBundleEnd(*MI)) {} /// Return a reference to the basic block containing this bundle. MachineBasicBlock &getMBB() const { return MBB; } diff --git a/include/llvm/CodeGen/MachineInstrBundle.h b/include/llvm/CodeGen/MachineInstrBundle.h index 4e88606c05a7..c0033a5148cf 100644 --- a/include/llvm/CodeGen/MachineInstrBundle.h +++ b/include/llvm/CodeGen/MachineInstrBundle.h @@ -43,23 +43,22 @@ bool finalizeBundles(MachineFunction &MF); /// getBundleStart - Returns the first instruction in the bundle containing MI. /// -inline MachineInstr *getBundleStart(MachineInstr *MI) { +inline MachineInstr &getBundleStart(MachineInstr &MI) { MachineBasicBlock::instr_iterator I(MI); while (I->isBundledWithPred()) --I; - return &*I; + return *I; } -inline const MachineInstr *getBundleStart(const MachineInstr *MI) { +inline const MachineInstr &getBundleStart(const MachineInstr &MI) { MachineBasicBlock::const_instr_iterator I(MI); while (I->isBundledWithPred()) --I; - return &*I; + return *I; } /// Return an iterator pointing beyond the bundle containing MI. -inline MachineBasicBlock::instr_iterator -getBundleEnd(MachineInstr *MI) { +inline MachineBasicBlock::instr_iterator getBundleEnd(MachineInstr &MI) { MachineBasicBlock::instr_iterator I(MI); while (I->isBundledWithSucc()) ++I; @@ -68,7 +67,7 @@ getBundleEnd(MachineInstr *MI) { /// Return an iterator pointing beyond the bundle containing MI. inline MachineBasicBlock::const_instr_iterator -getBundleEnd(const MachineInstr *MI) { +getBundleEnd(const MachineInstr &MI) { MachineBasicBlock::const_instr_iterator I(MI); while (I->isBundledWithSucc()) ++I; @@ -114,12 +113,12 @@ protected: /// @param MI The instruction to examine. /// @param WholeBundle When true, visit all operands on the entire bundle. /// - explicit MachineOperandIteratorBase(MachineInstr *MI, bool WholeBundle) { + explicit MachineOperandIteratorBase(MachineInstr &MI, bool WholeBundle) { if (WholeBundle) { - InstrI = getBundleStart(MI)->getIterator(); - InstrE = MI->getParent()->instr_end(); + InstrI = getBundleStart(MI).getIterator(); + InstrE = MI.getParent()->instr_end(); } else { - InstrI = InstrE = MI->getIterator(); + InstrI = InstrE = MI.getIterator(); ++InstrE; } OpI = InstrI->operands_begin(); @@ -184,10 +183,16 @@ public: /// Reg or a super-register is read. The full register is read. bool FullyRead; - /// Reg is FullyDefined and all defs of reg or an overlapping register are - /// dead. + /// Either: + /// - Reg is FullyDefined and all defs of reg or an overlapping + /// register are dead, or + /// - Reg is completely dead because "defined" by a clobber. bool DeadDef; + /// Reg is Defined and all defs of reg or an overlapping register are + /// dead. + bool PartialDeadDef; + /// There is a use operand of reg or a super-register with kill flag set. bool Killed; }; @@ -216,7 +221,7 @@ public: /// class MIOperands : public MachineOperandIteratorBase { public: - MIOperands(MachineInstr *MI) : MachineOperandIteratorBase(MI, false) {} + MIOperands(MachineInstr &MI) : MachineOperandIteratorBase(MI, false) {} MachineOperand &operator* () const { return deref(); } MachineOperand *operator->() const { return &deref(); } }; @@ -225,8 +230,8 @@ public: /// class ConstMIOperands : public MachineOperandIteratorBase { public: - ConstMIOperands(const MachineInstr *MI) - : MachineOperandIteratorBase(const_cast<MachineInstr*>(MI), false) {} + ConstMIOperands(const MachineInstr &MI) + : MachineOperandIteratorBase(const_cast<MachineInstr &>(MI), false) {} const MachineOperand &operator* () const { return deref(); } const MachineOperand *operator->() const { return &deref(); } }; @@ -236,7 +241,7 @@ public: /// class MIBundleOperands : public MachineOperandIteratorBase { public: - MIBundleOperands(MachineInstr *MI) : MachineOperandIteratorBase(MI, true) {} + MIBundleOperands(MachineInstr &MI) : MachineOperandIteratorBase(MI, true) {} MachineOperand &operator* () const { return deref(); } MachineOperand *operator->() const { return &deref(); } }; @@ -246,8 +251,8 @@ public: /// class ConstMIBundleOperands : public MachineOperandIteratorBase { public: - ConstMIBundleOperands(const MachineInstr *MI) - : MachineOperandIteratorBase(const_cast<MachineInstr*>(MI), true) {} + ConstMIBundleOperands(const MachineInstr &MI) + : MachineOperandIteratorBase(const_cast<MachineInstr &>(MI), true) {} const MachineOperand &operator* () const { return deref(); } const MachineOperand *operator->() const { return &deref(); } }; diff --git a/include/llvm/CodeGen/MachineInstrBundleIterator.h b/include/llvm/CodeGen/MachineInstrBundleIterator.h new file mode 100644 index 000000000000..45a9a188f90e --- /dev/null +++ b/include/llvm/CodeGen/MachineInstrBundleIterator.h @@ -0,0 +1,92 @@ +//===- llvm/CodeGen/MachineInstrBundleIterator.h ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines an iterator class that bundles MachineInstr. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H +#define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H + +#include "llvm/ADT/ilist.h" +#include <iterator> + +namespace llvm { + +/// MachineBasicBlock iterator that automatically skips over MIs that are +/// inside bundles (i.e. walk top level MIs only). +template <typename Ty> +class MachineInstrBundleIterator + : public std::iterator<std::bidirectional_iterator_tag, Ty, ptrdiff_t> { + typedef ilist_iterator<Ty> instr_iterator; + instr_iterator MII; + +public: + MachineInstrBundleIterator(instr_iterator MI) : MII(MI) {} + + MachineInstrBundleIterator(Ty &MI) : MII(MI) { + assert(!MI.isBundledWithPred() && "It's not legal to initialize " + "MachineInstrBundleIterator with a " + "bundled MI"); + } + MachineInstrBundleIterator(Ty *MI) : MII(MI) { + // FIXME: This conversion should be explicit. + assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize " + "MachineInstrBundleIterator " + "with a bundled MI"); + } + // Template allows conversion from const to nonconst. + template <class OtherTy> + MachineInstrBundleIterator(const MachineInstrBundleIterator<OtherTy> &I) + : MII(I.getInstrIterator()) {} + MachineInstrBundleIterator() : MII(nullptr) {} + + Ty &operator*() const { return *MII; } + Ty *operator->() const { return &operator*(); } + + // FIXME: This conversion should be explicit. + operator Ty *() const { return MII.getNodePtrUnchecked(); } + + bool operator==(const MachineInstrBundleIterator &X) const { + return MII == X.MII; + } + bool operator!=(const MachineInstrBundleIterator &X) const { + return !operator==(X); + } + + // Increment and decrement operators... + MachineInstrBundleIterator &operator--() { + do + --MII; + while (MII->isBundledWithPred()); + return *this; + } + MachineInstrBundleIterator &operator++() { + while (MII->isBundledWithSucc()) + ++MII; + ++MII; + return *this; + } + MachineInstrBundleIterator operator--(int) { + MachineInstrBundleIterator Temp = *this; + --*this; + return Temp; + } + MachineInstrBundleIterator operator++(int) { + MachineInstrBundleIterator Temp = *this; + ++*this; + return Temp; + } + + instr_iterator getInstrIterator() const { return MII; } +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/CodeGen/MachineLoopInfo.h b/include/llvm/CodeGen/MachineLoopInfo.h index 4868b7363f82..224a2a1aa59f 100644 --- a/include/llvm/CodeGen/MachineLoopInfo.h +++ b/include/llvm/CodeGen/MachineLoopInfo.h @@ -44,14 +44,14 @@ class MachineLoop : public LoopBase<MachineBasicBlock, MachineLoop> { public: MachineLoop(); - /// getTopBlock - Return the "top" block in the loop, which is the first - /// block in the linear layout, ignoring any parts of the loop not - /// contiguous with the part the contains the header. + /// Return the "top" block in the loop, which is the first block in the linear + /// layout, ignoring any parts of the loop not contiguous with the part that + /// contains the header. MachineBasicBlock *getTopBlock(); - /// getBottomBlock - Return the "bottom" block in the loop, which is the last - /// block in the linear layout, ignoring any parts of the loop not - /// contiguous with the part the contains the header. + /// Return the "bottom" block in the loop, which is the last block in the + /// linear layout, ignoring any parts of the loop not contiguous with the part + /// that contains the header. MachineBasicBlock *getBottomBlock(); void dump() const; @@ -81,72 +81,64 @@ public: LoopInfoBase<MachineBasicBlock, MachineLoop>& getBase() { return LI; } - /// iterator/begin/end - The interface to the top-level loops in the current - /// function. - /// + /// The iterator interface to the top-level loops in the current function. typedef LoopInfoBase<MachineBasicBlock, MachineLoop>::iterator iterator; inline iterator begin() const { return LI.begin(); } inline iterator end() const { return LI.end(); } bool empty() const { return LI.empty(); } - /// getLoopFor - Return the inner most loop that BB lives in. If a basic - /// block is in no loop (for example the entry node), null is returned. - /// + /// Return the innermost loop that BB lives in. If a basic block is in no loop + /// (for example the entry node), null is returned. inline MachineLoop *getLoopFor(const MachineBasicBlock *BB) const { return LI.getLoopFor(BB); } - /// operator[] - same as getLoopFor... - /// + /// Same as getLoopFor. inline const MachineLoop *operator[](const MachineBasicBlock *BB) const { return LI.getLoopFor(BB); } - /// getLoopDepth - Return the loop nesting level of the specified block... - /// + /// Return the loop nesting level of the specified block. inline unsigned getLoopDepth(const MachineBasicBlock *BB) const { return LI.getLoopDepth(BB); } - // isLoopHeader - True if the block is a loop header node + /// True if the block is a loop header node. inline bool isLoopHeader(const MachineBasicBlock *BB) const { return LI.isLoopHeader(BB); } - /// runOnFunction - Calculate the natural loop information. - /// + /// Calculate the natural loop information. bool runOnMachineFunction(MachineFunction &F) override; void releaseMemory() override { LI.releaseMemory(); } void getAnalysisUsage(AnalysisUsage &AU) const override; - /// removeLoop - This removes the specified top-level loop from this loop info - /// object. The loop is not deleted, as it will presumably be inserted into - /// another loop. + /// This removes the specified top-level loop from this loop info object. The + /// loop is not deleted, as it will presumably be inserted into another loop. inline MachineLoop *removeLoop(iterator I) { return LI.removeLoop(I); } - /// changeLoopFor - Change the top-level loop that contains BB to the - /// specified loop. This should be used by transformations that restructure - /// the loop hierarchy tree. + /// Change the top-level loop that contains BB to the specified loop. This + /// should be used by transformations that restructure the loop hierarchy + /// tree. inline void changeLoopFor(MachineBasicBlock *BB, MachineLoop *L) { LI.changeLoopFor(BB, L); } - /// changeTopLevelLoop - Replace the specified loop in the top-level loops - /// list with the indicated loop. + /// Replace the specified loop in the top-level loops list with the indicated + /// loop. inline void changeTopLevelLoop(MachineLoop *OldLoop, MachineLoop *NewLoop) { LI.changeTopLevelLoop(OldLoop, NewLoop); } - /// addTopLevelLoop - This adds the specified loop to the collection of - /// top-level loops. + /// This adds the specified loop to the collection of top-level loops. inline void addTopLevelLoop(MachineLoop *New) { LI.addTopLevelLoop(New); } - /// removeBlock - This method completely removes BB from all data structures, - /// including all of the Loop objects it is nested in and our mapping from + /// This method completely removes BB from all data structures, including all + /// of the Loop objects it is nested in and our mapping from /// MachineBasicBlocks to loops. void removeBlock(MachineBasicBlock *BB) { LI.removeBlock(BB); diff --git a/include/llvm/CodeGen/MachineMemOperand.h b/include/llvm/CodeGen/MachineMemOperand.h index 1ca0d90465a4..5fa7058733b3 100644 --- a/include/llvm/CodeGen/MachineMemOperand.h +++ b/include/llvm/CodeGen/MachineMemOperand.h @@ -16,6 +16,7 @@ #ifndef LLVM_CODEGEN_MACHINEMEMOPERAND_H #define LLVM_CODEGEN_MACHINEMEMOPERAND_H +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/IR/Metadata.h" @@ -30,12 +31,11 @@ class raw_ostream; class MachineFunction; class ModuleSlotTracker; -/// MachinePointerInfo - This class contains a discriminated union of -/// information about pointers in memory operands, relating them back to LLVM IR -/// or to virtual locations (such as frame indices) that are exposed during -/// codegen. +/// This class contains a discriminated union of information about pointers in +/// memory operands, relating them back to LLVM IR or to virtual locations (such +/// as frame indices) that are exposed during codegen. struct MachinePointerInfo { - /// V - This is the IR pointer value for the access, or it is null if unknown. + /// This is the IR pointer value for the access, or it is null if unknown. /// If this is null, then the access is to a pointer in the default address /// space. PointerUnion<const Value *, const PseudoSourceValue *> V; @@ -57,34 +57,30 @@ struct MachinePointerInfo { return MachinePointerInfo(V.get<const PseudoSourceValue*>(), Offset+O); } - /// getAddrSpace - Return the LLVM IR address space number that this pointer - /// points into. + /// Return the LLVM IR address space number that this pointer points into. unsigned getAddrSpace() const; - /// getConstantPool - Return a MachinePointerInfo record that refers to the - /// constant pool. + /// Return a MachinePointerInfo record that refers to the constant pool. static MachinePointerInfo getConstantPool(MachineFunction &MF); - /// getFixedStack - Return a MachinePointerInfo record that refers to the - /// the specified FrameIndex. + /// Return a MachinePointerInfo record that refers to the specified + /// FrameIndex. static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset = 0); - /// getJumpTable - Return a MachinePointerInfo record that refers to a - /// jump table entry. + /// Return a MachinePointerInfo record that refers to a jump table entry. static MachinePointerInfo getJumpTable(MachineFunction &MF); - /// getGOT - Return a MachinePointerInfo record that refers to a - /// GOT entry. + /// Return a MachinePointerInfo record that refers to a GOT entry. static MachinePointerInfo getGOT(MachineFunction &MF); - /// getStack - stack pointer relative access. + /// Stack pointer relative access. static MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset); }; //===----------------------------------------------------------------------===// -/// MachineMemOperand - A description of a memory reference used in the backend. +/// A description of a memory reference used in the backend. /// Instead of holding a StoreInst or LoadInst, this class holds the address /// Value of the reference along with a byte size and offset. This allows it /// to describe lowered loads and stores. Also, the special PseudoSourceValue @@ -92,43 +88,50 @@ struct MachinePointerInfo { /// that aren't explicit in the regular LLVM IR. /// class MachineMemOperand { - MachinePointerInfo PtrInfo; - uint64_t Size; - unsigned Flags; - AAMDNodes AAInfo; - const MDNode *Ranges; - public: /// Flags values. These may be or'd together. - enum MemOperandFlags { + enum Flags : uint16_t { + // No flags set. + MONone = 0, /// The memory access reads data. - MOLoad = 1, + MOLoad = 1u << 0, /// The memory access writes data. - MOStore = 2, + MOStore = 1u << 1, /// The memory access is volatile. - MOVolatile = 4, + MOVolatile = 1u << 2, /// The memory access is non-temporal. - MONonTemporal = 8, + MONonTemporal = 1u << 3, /// The memory access is invariant. - MOInvariant = 16, - // Target hints allow target passes to annotate memory operations. - MOTargetStartBit = 5, - MOTargetNumBits = 3, - // This is the number of bits we need to represent flags. - MOMaxBits = 8 + MOInvariant = 1u << 4, + + // Reserved for use by target-specific passes. + MOTargetFlag1 = 1u << 5, + MOTargetFlag2 = 1u << 6, + MOTargetFlag3 = 1u << 7, + + LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ MOTargetFlag3) }; - /// MachineMemOperand - Construct an MachineMemOperand object with the - /// specified PtrInfo, flags, size, and base alignment. - MachineMemOperand(MachinePointerInfo PtrInfo, unsigned flags, uint64_t s, +private: + MachinePointerInfo PtrInfo; + uint64_t Size; + Flags FlagVals; + uint16_t BaseAlignLog2; // log_2(base_alignment) + 1 + AAMDNodes AAInfo; + const MDNode *Ranges; + +public: + /// Construct a MachineMemOperand object with the specified PtrInfo, flags, + /// size, and base alignment. + MachineMemOperand(MachinePointerInfo PtrInfo, Flags flags, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); const MachinePointerInfo &getPointerInfo() const { return PtrInfo; } - /// getValue - Return the base address of the memory access. This may either - /// be a normal LLVM IR Value, or one of the special values used in CodeGen. + /// Return the base address of the memory access. This may either be a normal + /// LLVM IR Value, or one of the special values used in CodeGen. /// Special values are those obtained via /// PseudoSourceValue::getFixedStack(int), PseudoSourceValue::getStack, and /// other PseudoSourceValue member functions which return objects which stand @@ -142,59 +145,58 @@ public: const void *getOpaqueValue() const { return PtrInfo.V.getOpaqueValue(); } - /// getFlags - Return the raw flags of the source value, \see MemOperandFlags. - unsigned int getFlags() const { return Flags & ((1 << MOMaxBits) - 1); } + /// Return the raw flags of the source value, \see Flags. + Flags getFlags() const { return FlagVals; } /// Bitwise OR the current flags with the given flags. - void setFlags(unsigned f) { Flags |= (f & ((1 << MOMaxBits) - 1)); } + void setFlags(Flags f) { FlagVals |= f; } - /// getOffset - For normal values, this is a byte offset added to the base - /// address. For PseudoSourceValue::FPRel values, this is the FrameIndex - /// number. + /// For normal values, this is a byte offset added to the base address. + /// For PseudoSourceValue::FPRel values, this is the FrameIndex number. int64_t getOffset() const { return PtrInfo.Offset; } unsigned getAddrSpace() const { return PtrInfo.getAddrSpace(); } - /// getSize - Return the size in bytes of the memory reference. + /// Return the size in bytes of the memory reference. uint64_t getSize() const { return Size; } - /// getAlignment - Return the minimum known alignment in bytes of the - /// actual memory reference. + /// Return the minimum known alignment in bytes of the actual memory + /// reference. uint64_t getAlignment() const; - /// getBaseAlignment - Return the minimum known alignment in bytes of the - /// base address, without the offset. - uint64_t getBaseAlignment() const { return (1u << (Flags >> MOMaxBits)) >> 1; } + /// Return the minimum known alignment in bytes of the base address, without + /// the offset. + uint64_t getBaseAlignment() const { return (1u << BaseAlignLog2) >> 1; } - /// getAAInfo - Return the AA tags for the memory reference. + /// Return the AA tags for the memory reference. AAMDNodes getAAInfo() const { return AAInfo; } - /// getRanges - Return the range tag for the memory reference. + /// Return the range tag for the memory reference. const MDNode *getRanges() const { return Ranges; } - bool isLoad() const { return Flags & MOLoad; } - bool isStore() const { return Flags & MOStore; } - bool isVolatile() const { return Flags & MOVolatile; } - bool isNonTemporal() const { return Flags & MONonTemporal; } - bool isInvariant() const { return Flags & MOInvariant; } + bool isLoad() const { return FlagVals & MOLoad; } + bool isStore() const { return FlagVals & MOStore; } + bool isVolatile() const { return FlagVals & MOVolatile; } + bool isNonTemporal() const { return FlagVals & MONonTemporal; } + bool isInvariant() const { return FlagVals & MOInvariant; } - /// isUnordered - Returns true if this memory operation doesn't have any - /// ordering constraints other than normal aliasing. Volatile and atomic - /// memory operations can't be reordered. + /// Returns true if this memory operation doesn't have any ordering + /// constraints other than normal aliasing. Volatile and atomic memory + /// operations can't be reordered. /// /// Currently, we don't model the difference between volatile and atomic /// operations. They should retain their ordering relative to all memory /// operations. bool isUnordered() const { return !isVolatile(); } - /// refineAlignment - Update this MachineMemOperand to reflect the alignment - /// of MMO, if it has a greater alignment. This must only be used when the - /// new alignment applies to all users of this MachineMemOperand. + /// Update this MachineMemOperand to reflect the alignment of MMO, if it has a + /// greater alignment. This must only be used when the new alignment applies + /// to all users of this MachineMemOperand. void refineAlignment(const MachineMemOperand *MMO); - /// setValue - Change the SourceValue for this MachineMemOperand. This - /// should only be used when an object is being relocated and all references - /// to it are being updated. + /// Change the SourceValue for this MachineMemOperand. This should only be + /// used when an object is being relocated and all references to it are being + /// updated. void setValue(const Value *NewSV) { PtrInfo.V = NewSV; } void setValue(const PseudoSourceValue *NewSV) { PtrInfo.V = NewSV; } void setOffset(int64_t NewOffset) { PtrInfo.Offset = NewOffset; } diff --git a/include/llvm/CodeGen/MachineModuleInfoImpls.h b/include/llvm/CodeGen/MachineModuleInfoImpls.h index e7472145e71f..f9fa6999073f 100644 --- a/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ b/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -23,44 +23,35 @@ class MCSymbol; /// MachineModuleInfoMachO - This is a MachineModuleInfoImpl implementation /// for MachO targets. class MachineModuleInfoMachO : public MachineModuleInfoImpl { - /// FnStubs - Darwin '$stub' stubs. The key is something like "Lfoo$stub", - /// the value is something like "_foo". - DenseMap<MCSymbol *, StubValueTy> FnStubs; - /// GVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like /// "Lfoo$non_lazy_ptr", the value is something like "_foo". The extra bit /// is true if this GV is external. DenseMap<MCSymbol *, StubValueTy> GVStubs; - /// HiddenGVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like - /// "Lfoo$non_lazy_ptr", the value is something like "_foo". Unlike GVStubs - /// these are for things with hidden visibility. The extra bit is true if - /// this GV is external. - DenseMap<MCSymbol *, StubValueTy> HiddenGVStubs; + /// ThreadLocalGVStubs - Darwin '$non_lazy_ptr' stubs. The key is something + /// like "Lfoo$non_lazy_ptr", the value is something like "_foo". The extra + /// bit is true if this GV is external. + DenseMap<MCSymbol *, StubValueTy> ThreadLocalGVStubs; virtual void anchor(); // Out of line virtual method. public: MachineModuleInfoMachO(const MachineModuleInfo &) {} - StubValueTy &getFnStubEntry(MCSymbol *Sym) { - assert(Sym && "Key cannot be null"); - return FnStubs[Sym]; - } - StubValueTy &getGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return GVStubs[Sym]; } - StubValueTy &getHiddenGVStubEntry(MCSymbol *Sym) { + StubValueTy &getThreadLocalGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); - return HiddenGVStubs[Sym]; + return ThreadLocalGVStubs[Sym]; } /// Accessor methods to return the set of stubs in sorted order. - SymbolListTy GetFnStubList() { return getSortedStubs(FnStubs); } SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } - SymbolListTy GetHiddenGVStubList() { return getSortedStubs(HiddenGVStubs); } + SymbolListTy GetThreadLocalGVStubList() { + return getSortedStubs(ThreadLocalGVStubs); + } }; /// MachineModuleInfoELF - This is a MachineModuleInfoImpl implementation diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index c43e47c36d06..ee0a9cf11e6a 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -534,6 +534,15 @@ public: Contents.MBB = MBB; } + /// Sets value of register mask operand referencing Mask. The + /// operand does not take ownership of the memory referenced by Mask, it must + /// remain valid for the lifetime of the operand. See CreateRegMask(). + /// Any physreg with a 0 bit in the mask is clobbered by the instruction. + void setRegMask(const uint32_t *RegMaskPtr) { + assert(isRegMask() && "Wrong MachineOperand mutator"); + Contents.RegMask = RegMaskPtr; + } + //===--------------------------------------------------------------------===// // Other methods. //===--------------------------------------------------------------------===// diff --git a/include/llvm/CodeGen/MachineRegisterInfo.h b/include/llvm/CodeGen/MachineRegisterInfo.h index 04191bc1b74f..07d2d016f274 100644 --- a/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/include/llvm/CodeGen/MachineRegisterInfo.h @@ -16,7 +16,10 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator_range.h" +// PointerUnion needs to have access to the full RegisterBank type. +#include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -26,6 +29,10 @@ namespace llvm { class PSetIterator; +/// Convenient type to represent either a register class or a register bank. +typedef PointerUnion<const TargetRegisterClass *, const RegisterBank *> + RegClassOrRegBank; + /// MachineRegisterInfo - Keep track of information for virtual and physical /// registers, including vreg register classes, use/def chains for registers, /// etc. @@ -40,18 +47,9 @@ public: }; private: - const MachineFunction *MF; + MachineFunction *MF; Delegate *TheDelegate; - /// IsSSA - True when the machine function is in SSA form and virtual - /// registers have a single def. - bool IsSSA; - - /// TracksLiveness - True while register liveness is being tracked accurately. - /// Basic block live-in lists, kill flags, and implicit defs may not be - /// accurate when after this flag is cleared. - bool TracksLiveness; - /// True if subregister liveness is tracked. bool TracksSubRegLiveness; @@ -59,8 +57,9 @@ private: /// /// Each element in this list contains the register class of the vreg and the /// start of the use/def list for the register. - IndexedMap<std::pair<const TargetRegisterClass*, MachineOperand*>, - VirtReg2IndexFunctor> VRegInfo; + IndexedMap<std::pair<RegClassOrRegBank, MachineOperand *>, + VirtReg2IndexFunctor> + VRegInfo; /// RegAllocHints - This vector records register allocation hints for virtual /// registers. For each virtual register, it keeps a register and hint type @@ -105,6 +104,18 @@ private: /// started. BitVector ReservedRegs; + typedef DenseMap<unsigned, unsigned> VRegToSizeMap; + /// Map generic virtual registers to their actual size. + mutable std::unique_ptr<VRegToSizeMap> VRegToSize; + + /// Accessor for VRegToSize. This accessor should only be used + /// by global-isel related work. + VRegToSizeMap &getVRegToSize() const { + if (!VRegToSize) + VRegToSize.reset(new VRegToSizeMap); + return *VRegToSize.get(); + } + /// Keep track of the physical registers that are live in to the function. /// Live in values are typically arguments in registers. LiveIn values are /// allowed to have virtual registers associated with them, stored in the @@ -114,7 +125,7 @@ private: MachineRegisterInfo(const MachineRegisterInfo&) = delete; void operator=(const MachineRegisterInfo&) = delete; public: - explicit MachineRegisterInfo(const MachineFunction *MF); + explicit MachineRegisterInfo(MachineFunction *MF); const TargetRegisterInfo *getTargetRegisterInfo() const { return MF->getSubtarget().getRegisterInfo(); @@ -148,27 +159,32 @@ public: // The TwoAddressInstructionPass and PHIElimination passes take the machine // function out of SSA form when they introduce multiple defs per virtual // register. - bool isSSA() const { return IsSSA; } + bool isSSA() const { + return MF->getProperties().hasProperty( + MachineFunctionProperties::Property::IsSSA); + } // leaveSSA - Indicates that the machine function is no longer in SSA form. - void leaveSSA() { IsSSA = false; } + void leaveSSA() { + MF->getProperties().clear(MachineFunctionProperties::Property::IsSSA); + } /// tracksLiveness - Returns true when tracking register liveness accurately. - /// - /// While this flag is true, register liveness information in basic block - /// live-in lists and machine instruction operands is accurate. This means it - /// can be used to change the code in ways that affect the values in - /// registers, for example by the register scavenger. - /// - /// When this flag is false, liveness is no longer reliable. - bool tracksLiveness() const { return TracksLiveness; } + /// (see MachineFUnctionProperties::Property description for details) + bool tracksLiveness() const { + return MF->getProperties().hasProperty( + MachineFunctionProperties::Property::TracksLiveness); + } /// invalidateLiveness - Indicates that register liveness is no longer being /// tracked accurately. /// /// This should be called by late passes that invalidate the liveness /// information. - void invalidateLiveness() { TracksLiveness = false; } + void invalidateLiveness() { + MF->getProperties().clear( + MachineFunctionProperties::Property::TracksLiveness); + } /// Returns true if liveness for register class @p RC should be tracked at /// the subregister level. @@ -375,8 +391,8 @@ public: /// specified register (it may be live-in). bool def_empty(unsigned RegNo) const { return def_begin(RegNo) == def_end(); } - /// hasOneDef - Return true if there is exactly one instruction defining the - /// specified register. + /// Return true if there is exactly one operand defining the specified + /// register. bool hasOneDef(unsigned RegNo) const { def_iterator DI = def_begin(RegNo); if (DI == def_end()) @@ -551,9 +567,47 @@ public: // Virtual Register Info //===--------------------------------------------------------------------===// - /// getRegClass - Return the register class of the specified virtual register. + /// Return the register class of the specified virtual register. + /// This shouldn't be used directly unless \p Reg has a register class. + /// \see getRegClassOrNull when this might happen. /// const TargetRegisterClass *getRegClass(unsigned Reg) const { + assert(VRegInfo[Reg].first.is<const TargetRegisterClass *>() && + "Register class not set, wrong accessor"); + return VRegInfo[Reg].first.get<const TargetRegisterClass *>(); + } + + /// Return the register class of \p Reg, or null if Reg has not been assigned + /// a register class yet. + /// + /// \note A null register class can only happen when these two + /// conditions are met: + /// 1. Generic virtual registers are created. + /// 2. The machine function has not completely been through the + /// instruction selection process. + /// None of this condition is possible without GlobalISel for now. + /// In other words, if GlobalISel is not used or if the query happens after + /// the select pass, using getRegClass is safe. + const TargetRegisterClass *getRegClassOrNull(unsigned Reg) const { + const RegClassOrRegBank &Val = VRegInfo[Reg].first; + return Val.dyn_cast<const TargetRegisterClass *>(); + } + + /// Return the register bank of \p Reg, or null if Reg has not been assigned + /// a register bank or has been assigned a register class. + /// \note It is possible to get the register bank from the register class via + /// RegisterBankInfo::getRegBankFromRegClass. + /// + const RegisterBank *getRegBankOrNull(unsigned Reg) const { + const RegClassOrRegBank &Val = VRegInfo[Reg].first; + return Val.dyn_cast<const RegisterBank *>(); + } + + /// Return the register bank or register class of \p Reg. + /// \note Before the register bank gets assigned (i.e., before the + /// RegBankSelect pass) \p Reg may not have either. + /// + const RegClassOrRegBank &getRegClassOrRegBank(unsigned Reg) const { return VRegInfo[Reg].first; } @@ -561,6 +615,10 @@ public: /// void setRegClass(unsigned Reg, const TargetRegisterClass *RC); + /// Set the register bank to \p RegBank for \p Reg. + /// + void setRegBank(unsigned Reg, const RegisterBank &RegBank); + /// constrainRegClass - Constrain the register class of the specified virtual /// register to be a common subclass of RC and the current register class, /// but only if the new class has at least MinNumRegs registers. Return the @@ -587,6 +645,19 @@ public: /// unsigned createVirtualRegister(const TargetRegisterClass *RegClass); + /// Get the size in bits of \p VReg or 0 if VReg is not a generic + /// (target independent) virtual register. + unsigned getSize(unsigned VReg) const; + + /// Set the size in bits of \p VReg to \p Size. + /// Although the size should be set at build time, mir infrastructure + /// is not yet able to do it. + void setSize(unsigned VReg, unsigned Size); + + /// Create and return a new generic virtual register with a size of \p Size. + /// \pre Size > 0. + unsigned createGenericVirtualRegister(unsigned Size); + /// getNumVirtRegs - Return the number of virtual registers created. /// unsigned getNumVirtRegs() const { return VRegInfo.size(); } @@ -632,9 +703,10 @@ public: /// Return true if the specified register is modified in this function. /// This checks that no defining machine operands exist for the register or /// any of its aliases. Definitions found on functions marked noreturn are - /// ignored. The register is also considered modified when it is set in the - /// UsedPhysRegMask. - bool isPhysRegModified(unsigned PhysReg) const; + /// ignored, to consider them pass 'true' for optional parameter + /// SkipNoReturnDef. The register is also considered modified when it is set + /// in the UsedPhysRegMask. + bool isPhysRegModified(unsigned PhysReg, bool SkipNoReturnDef = false) const; /// Return true if the specified register is modified or read in this /// function. This checks that no machine operands exist for the register or @@ -820,10 +892,10 @@ public: advance(); } while (Op && Op->getParent() == P); } else if (ByBundle) { - MachineInstr *P = getBundleStart(Op->getParent()); + MachineInstr &P = getBundleStart(*Op->getParent()); do { advance(); - } while (Op && getBundleStart(Op->getParent()) == P); + } while (Op && &getBundleStart(*Op->getParent()) == &P); } return *this; @@ -922,10 +994,10 @@ public: advance(); } while (Op && Op->getParent() == P); } else if (ByBundle) { - MachineInstr *P = getBundleStart(Op->getParent()); + MachineInstr &P = getBundleStart(*Op->getParent()); do { advance(); - } while (Op && getBundleStart(Op->getParent()) == P); + } while (Op && &getBundleStart(*Op->getParent()) == &P); } return *this; @@ -937,15 +1009,12 @@ public: // Retrieve a reference to the current operand. MachineInstr &operator*() const { assert(Op && "Cannot dereference end iterator!"); - if (ByBundle) return *(getBundleStart(Op->getParent())); + if (ByBundle) + return getBundleStart(*Op->getParent()); return *Op->getParent(); } - MachineInstr *operator->() const { - assert(Op && "Cannot dereference end iterator!"); - if (ByBundle) return getBundleStart(Op->getParent()); - return Op->getParent(); - } + MachineInstr *operator->() const { return &operator*(); } }; }; diff --git a/include/llvm/CodeGen/MachineSSAUpdater.h b/include/llvm/CodeGen/MachineSSAUpdater.h index 5f988ad86320..50a7d90bf25b 100644 --- a/include/llvm/CodeGen/MachineSSAUpdater.h +++ b/include/llvm/CodeGen/MachineSSAUpdater.h @@ -14,7 +14,6 @@ #ifndef LLVM_CODEGEN_MACHINESSAUPDATER_H #define LLVM_CODEGEN_MACHINESSAUPDATER_H -#include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" namespace llvm { diff --git a/include/llvm/CodeGen/MachineScheduler.h b/include/llvm/CodeGen/MachineScheduler.h index 358fd5a3732a..06e992179031 100644 --- a/include/llvm/CodeGen/MachineScheduler.h +++ b/include/llvm/CodeGen/MachineScheduler.h @@ -66,8 +66,6 @@ // // void <SubTarget>Subtarget:: // overrideSchedPolicy(MachineSchedPolicy &Policy, -// MachineInstr *begin, -// MachineInstr *end, // unsigned NumRegionInstrs) const { // Policy.<Flag> = true; // } @@ -81,6 +79,7 @@ #include "llvm/CodeGen/MachinePassRegistry.h" #include "llvm/CodeGen/RegisterPressure.h" #include "llvm/CodeGen/ScheduleDAGInstrs.h" +#include "llvm/CodeGen/ScheduleDAGMutation.h" #include <memory> namespace llvm { @@ -150,6 +149,9 @@ class ScheduleDAGMI; struct MachineSchedPolicy { // Allow the scheduler to disable register pressure tracking. bool ShouldTrackPressure; + /// Track LaneMasks to allow reordering of independent subregister writes + /// of the same vreg. \sa MachineSchedStrategy::shouldTrackLaneMasks() + bool ShouldTrackLaneMasks; // Allow the scheduler to force top-down or bottom-up scheduling. If neither // is true, the scheduler runs in both directions and converges. @@ -160,8 +162,8 @@ struct MachineSchedPolicy { // first. bool DisableLatencyHeuristic; - MachineSchedPolicy(): ShouldTrackPressure(false), OnlyTopDown(false), - OnlyBottomUp(false), DisableLatencyHeuristic(false) {} + MachineSchedPolicy(): ShouldTrackPressure(false), ShouldTrackLaneMasks(false), + OnlyTopDown(false), OnlyBottomUp(false), DisableLatencyHeuristic(false) {} }; /// MachineSchedStrategy - Interface to the scheduling algorithm used by @@ -185,6 +187,11 @@ public: /// initializing this strategy. Called after initPolicy. virtual bool shouldTrackPressure() const { return true; } + /// Returns true if lanemasks should be tracked. LaneMask tracking is + /// necessary to reorder independent subregister defs for the same vreg. + /// This has to be enabled in combination with shouldTrackPressure(). + virtual bool shouldTrackLaneMasks() const { return false; } + /// Initialize the strategy after building the DAG for a new region. virtual void initialize(ScheduleDAGMI *DAG) = 0; @@ -212,15 +219,6 @@ public: virtual void releaseBottomNode(SUnit *SU) = 0; }; -/// Mutate the DAG as a postpass after normal DAG building. -class ScheduleDAGMutation { - virtual void anchor(); -public: - virtual ~ScheduleDAGMutation() {} - - virtual void apply(ScheduleDAGMI *DAG) = 0; -}; - /// ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply /// schedules machine instructions according to the given MachineSchedStrategy /// without much extra book-keeping. This is the common functionality between @@ -371,6 +369,7 @@ protected: /// Register pressure in this region computed by initRegPressure. bool ShouldTrackPressure; + bool ShouldTrackLaneMasks; IntervalPressure RegPressure; RegPressureTracker RPTracker; @@ -387,13 +386,18 @@ protected: IntervalPressure BotPressure; RegPressureTracker BotRPTracker; + /// True if disconnected subregister components are already renamed. + /// The renaming is only done on demand if lane masks are tracked. + bool DisconnectedComponentsRenamed; + public: ScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S) : ScheduleDAGMI(C, std::move(S), /*RemoveKillFlags=*/false), RegClassInfo(C->RegClassInfo), DFSResult(nullptr), - ShouldTrackPressure(false), RPTracker(RegPressure), - TopRPTracker(TopPressure), BotRPTracker(BotPressure) {} + ShouldTrackPressure(false), ShouldTrackLaneMasks(false), + RPTracker(RegPressure), TopRPTracker(TopPressure), + BotRPTracker(BotPressure), DisconnectedComponentsRenamed(false) {} ~ScheduleDAGMILive() override; @@ -455,6 +459,10 @@ protected: /// bottom of the DAG region without covereing any unscheduled instruction. void buildDAGWithRegPressure(); + /// Release ExitSU predecessors and setup scheduler queues. Re-position + /// the Top RP tracker in case the region beginning has changed. + void initQueues(ArrayRef<SUnit*> TopRoots, ArrayRef<SUnit*> BotRoots); + /// Move an instruction and update register pressure. void scheduleMI(SUnit *SU, bool IsTopNode); @@ -462,7 +470,7 @@ protected: void initRegPressure(); - void updatePressureDiffs(ArrayRef<unsigned> LiveUses); + void updatePressureDiffs(ArrayRef<RegisterMaskPair> LiveUses); void updateScheduledPressure(const SUnit *SU, const std::vector<unsigned> &NewMaxPressure); @@ -753,9 +761,9 @@ class GenericSchedulerBase : public MachineSchedStrategy { public: /// Represent the type of SchedCandidate found within a single queue. /// pickNodeBidirectional depends on these listed by decreasing priority. - enum CandReason { - NoCand, PhysRegCopy, RegExcess, RegCritical, Stall, Cluster, Weak, RegMax, - ResourceReduce, ResourceDemand, BotHeightReduce, BotPathReduce, + enum CandReason : uint8_t { + NoCand, Only1, PhysRegCopy, RegExcess, RegCritical, Stall, Cluster, Weak, + RegMax, ResourceReduce, ResourceDemand, BotHeightReduce, BotPathReduce, TopDepthReduce, TopPathReduce, NextDefUse, NodeOrder}; #ifndef NDEBUG @@ -769,6 +777,15 @@ public: unsigned DemandResIdx; CandPolicy(): ReduceLatency(false), ReduceResIdx(0), DemandResIdx(0) {} + + bool operator==(const CandPolicy &RHS) const { + return ReduceLatency == RHS.ReduceLatency && + ReduceResIdx == RHS.ReduceResIdx && + DemandResIdx == RHS.DemandResIdx; + } + bool operator!=(const CandPolicy &RHS) const { + return !(*this == RHS); + } }; /// Status of an instruction's critical resource consumption. @@ -801,8 +818,8 @@ public: // The reason for this candidate. CandReason Reason; - // Set of reasons that apply to multiple candidates. - uint32_t RepeatReasonSet; + // Whether this candidate should be scheduled at top/bottom. + bool AtTop; // Register pressure values for the best candidate. RegPressureDelta RPDelta; @@ -810,8 +827,17 @@ public: // Critical resource consumption of the best candidate. SchedResourceDelta ResDelta; - SchedCandidate(const CandPolicy &policy) - : Policy(policy), SU(nullptr), Reason(NoCand), RepeatReasonSet(0) {} + SchedCandidate() { reset(CandPolicy()); } + SchedCandidate(const CandPolicy &Policy) { reset(Policy); } + + void reset(const CandPolicy &NewPolicy) { + Policy = NewPolicy; + SU = nullptr; + Reason = NoCand; + AtTop = false; + RPDelta = RegPressureDelta(); + ResDelta = SchedResourceDelta(); + } bool isValid() const { return SU; } @@ -820,13 +846,11 @@ public: assert(Best.Reason != NoCand && "uninitialized Sched candidate"); SU = Best.SU; Reason = Best.Reason; + AtTop = Best.AtTop; RPDelta = Best.RPDelta; ResDelta = Best.ResDelta; } - bool isRepeat(CandReason R) { return RepeatReasonSet & (1 << R); } - void setRepeat(CandReason R) { RepeatReasonSet |= (1 << R); } - void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel); }; @@ -858,6 +882,11 @@ class GenericScheduler : public GenericSchedulerBase { SchedBoundary Top; SchedBoundary Bot; + /// Candidate last picked from Top boundary. + SchedCandidate TopCand; + /// Candidate last picked from Bot boundary. + SchedCandidate BotCand; + MachineSchedPolicy RegionPolicy; public: GenericScheduler(const MachineSchedContext *C): @@ -874,6 +903,10 @@ public: return RegionPolicy.ShouldTrackPressure; } + bool shouldTrackLaneMasks() const override { + return RegionPolicy.ShouldTrackLaneMasks; + } + void initialize(ScheduleDAGMI *dag) override; SUnit *pickNode(bool &IsTopNode) override; @@ -882,10 +915,12 @@ public: void releaseTopNode(SUnit *SU) override { Top.releaseTopNode(SU); + TopCand.SU = nullptr; } void releaseBottomNode(SUnit *SU) override { Bot.releaseBottomNode(SU); + BotCand.SU = nullptr; } void registerRoots() override; @@ -893,15 +928,18 @@ public: protected: void checkAcyclicLatency(); + void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, + const RegPressureTracker &RPTracker, + RegPressureTracker &TempTracker); + void tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, - SchedBoundary &Zone, - const RegPressureTracker &RPTracker, - RegPressureTracker &TempTracker); + SchedBoundary *Zone); SUnit *pickNodeBidirectional(bool &IsTopNode); void pickNodeFromQueue(SchedBoundary &Zone, + const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Candidate); diff --git a/include/llvm/CodeGen/MachineTraceMetrics.h b/include/llvm/CodeGen/MachineTraceMetrics.h index bfe6e945b6da..06db17abaed9 100644 --- a/include/llvm/CodeGen/MachineTraceMetrics.h +++ b/include/llvm/CodeGen/MachineTraceMetrics.h @@ -50,6 +50,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/TargetSchedule.h" namespace llvm { @@ -275,24 +276,24 @@ public: /// Return the depth and height of MI. The depth is only valid for /// instructions in or above the trace center block. The height is only /// valid for instructions in or below the trace center block. - InstrCycles getInstrCycles(const MachineInstr *MI) const { - return TE.Cycles.lookup(MI); + InstrCycles getInstrCycles(const MachineInstr &MI) const { + return TE.Cycles.lookup(&MI); } /// Return the slack of MI. This is the number of cycles MI can be delayed /// before the critical path becomes longer. /// MI must be an instruction in the trace center block. - unsigned getInstrSlack(const MachineInstr *MI) const; + unsigned getInstrSlack(const MachineInstr &MI) const; /// Return the Depth of a PHI instruction in a trace center block successor. /// The PHI does not have to be part of the trace. - unsigned getPHIDepth(const MachineInstr *PHI) const; + unsigned getPHIDepth(const MachineInstr &PHI) const; /// A dependence is useful if the basic block of the defining instruction /// is part of the trace of the user instruction. It is assumed that DefMI /// dominates UseMI (see also isUsefulDominator). - bool isDepInTrace(const MachineInstr *DefMI, - const MachineInstr *UseMI) const; + bool isDepInTrace(const MachineInstr &DefMI, + const MachineInstr &UseMI) const; }; /// A trace ensemble is a collection of traces selected using the same diff --git a/include/llvm/CodeGen/MachineValueType.h b/include/llvm/CodeGen/MachineValueType.h index 04d6ee3be531..0bb53d1a5374 100644 --- a/include/llvm/CodeGen/MachineValueType.h +++ b/include/llvm/CodeGen/MachineValueType.h @@ -28,7 +28,7 @@ namespace llvm { /// type can be represented by an MVT. class MVT { public: - enum SimpleValueType { + enum SimpleValueType : int8_t { // INVALID_SIMPLE_VALUE_TYPE - Simple value types less than zero are // considered extended value types. INVALID_SIMPLE_VALUE_TYPE = -1, @@ -142,38 +142,38 @@ class MVT { MAX_ALLOWED_VALUETYPE = 96, // Token - A value of type llvm::TokenTy - token = 249, + token = 120, // Metadata - This is MDNode or MDString. - Metadata = 250, + Metadata = 121, // iPTRAny - An int value the size of the pointer of the current // target to any address space. This must only be used internal to // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR. - iPTRAny = 251, + iPTRAny = 122, // vAny - A vector with any length and element size. This is used // for intrinsics that have overloadings based on vector types. // This is only for tblgen's consumption! - vAny = 252, + vAny = 123, // fAny - Any floating-point or vector floating-point value. This is used // for intrinsics that have overloadings based on floating-point types. // This is only for tblgen's consumption! - fAny = 253, + fAny = 124, // iAny - An integer or vector integer value of any bit width. This is // used for intrinsics that have overloadings based on integer bit widths. // This is only for tblgen's consumption! - iAny = 254, + iAny = 125, // iPTR - An int value the size of the pointer of the current // target. This should only be used internal to tblgen! - iPTR = 255, + iPTR = 126, // Any - Any type. This is used for intrinsics that have overloadings. // This is only for tblgen's consumption! - Any = 256 + Any = 127 }; SimpleValueType SimpleTy; @@ -210,6 +210,13 @@ class MVT { SimpleTy <= MVT::LAST_INTEGER_VECTOR_VALUETYPE)); } + /// isScalarInteger - Return true if this is an integer, not including + /// vectors. + bool isScalarInteger() const { + return (SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE && + SimpleTy <= MVT::LAST_INTEGER_VALUETYPE); + } + /// isVector - Return true if this is a vector value type. bool isVector() const { return (SimpleTy >= MVT::FIRST_VECTOR_VALUETYPE && diff --git a/include/llvm/CodeGen/PBQP/Graph.h b/include/llvm/CodeGen/PBQP/Graph.h index f73383ed1000..8301ca4d8536 100644 --- a/include/llvm/CodeGen/PBQP/Graph.h +++ b/include/llvm/CodeGen/PBQP/Graph.h @@ -15,12 +15,11 @@ #ifndef LLVM_CODEGEN_PBQP_GRAPH_H #define LLVM_CODEGEN_PBQP_GRAPH_H -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" #include "llvm/Support/Debug.h" -#include <list> -#include <map> -#include <set> +#include <algorithm> +#include <cassert> +#include <limits> +#include <utility> #include <vector> namespace llvm { @@ -72,7 +71,7 @@ namespace PBQP { return std::numeric_limits<AdjEdgeIdx>::max(); } - NodeEntry(VectorPtr Costs) : Costs(Costs) {} + NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {} AdjEdgeIdx addAdjEdgeId(EdgeId EId) { AdjEdgeIdx Idx = AdjEdgeIds.size(); @@ -103,7 +102,7 @@ namespace PBQP { class EdgeEntry { public: EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs) - : Costs(Costs) { + : Costs(std::move(Costs)) { NIds[0] = N1Id; NIds[1] = N2Id; ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx(); @@ -348,7 +347,8 @@ namespace PBQP { Graph() : Solver(nullptr) {} /// @brief Construct an empty PBQP graph with the given graph metadata. - Graph(GraphMetadata Metadata) : Metadata(Metadata), Solver(nullptr) {} + Graph(GraphMetadata Metadata) + : Metadata(std::move(Metadata)), Solver(nullptr) {} /// @brief Get a reference to the graph metadata. GraphMetadata& getMetadata() { return Metadata; } diff --git a/include/llvm/CodeGen/ParallelCG.h b/include/llvm/CodeGen/ParallelCG.h index fa7002fa21fb..14ef0ec408ba 100644 --- a/include/llvm/CodeGen/ParallelCG.h +++ b/include/llvm/CodeGen/ParallelCG.h @@ -14,29 +14,34 @@ #ifndef LLVM_CODEGEN_PARALLELCG_H #define LLVM_CODEGEN_PARALLELCG_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/CodeGen.h" #include "llvm/Target/TargetMachine.h" +#include <functional> + namespace llvm { +template <typename T> class ArrayRef; class Module; class TargetOptions; class raw_pwrite_stream; -/// Split M into OSs.size() partitions, and generate code for each. Writes -/// OSs.size() output files to the output streams in OSs. The resulting output -/// files if linked together are intended to be equivalent to the single output -/// file that would have been code generated from M. +/// Split M into OSs.size() partitions, and generate code for each. Takes a +/// factory function for the TargetMachine TMFactory. Writes OSs.size() output +/// files to the output streams in OSs. The resulting output files if linked +/// together are intended to be equivalent to the single output file that would +/// have been code generated from M. +/// +/// Writes bitcode for individual partitions into output streams in BCOSs, if +/// BCOSs is not empty. /// /// \returns M if OSs.size() == 1, otherwise returns std::unique_ptr<Module>(). std::unique_ptr<Module> splitCodeGen(std::unique_ptr<Module> M, ArrayRef<raw_pwrite_stream *> OSs, - StringRef CPU, StringRef Features, const TargetOptions &Options, - Reloc::Model RM = Reloc::Default, - CodeModel::Model CM = CodeModel::Default, - CodeGenOpt::Level OL = CodeGenOpt::Default, - TargetMachine::CodeGenFileType FT = TargetMachine::CGFT_ObjectFile); + ArrayRef<llvm::raw_pwrite_stream *> BCOSs, + const std::function<std::unique_ptr<TargetMachine>()> &TMFactory, + TargetMachine::CodeGenFileType FT = TargetMachine::CGFT_ObjectFile, + bool PreserveLocals = false); } // namespace llvm diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index f45f0ed57d6b..ae9e5dfe2d65 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -15,352 +15,21 @@ #ifndef LLVM_CODEGEN_PASSES_H #define LLVM_CODEGEN_PASSES_H -#include "llvm/Pass.h" -#include "llvm/Target/TargetMachine.h" #include <functional> #include <string> namespace llvm { +class Function; +class FunctionPass; class MachineFunctionPass; -class PassConfigImpl; -class PassInfo; -class ScheduleDAGInstrs; -class TargetLowering; -class TargetLoweringBase; +class ModulePass; +class Pass; +class TargetMachine; class TargetRegisterClass; class raw_ostream; -struct MachineSchedContext; - -// The old pass manager infrastructure is hidden in a legacy namespace now. -namespace legacy { -class PassManagerBase; -} -using legacy::PassManagerBase; - -/// Discriminated union of Pass ID types. -/// -/// The PassConfig API prefers dealing with IDs because they are safer and more -/// efficient. IDs decouple configuration from instantiation. This way, when a -/// pass is overriden, it isn't unnecessarily instantiated. It is also unsafe to -/// refer to a Pass pointer after adding it to a pass manager, which deletes -/// redundant pass instances. -/// -/// However, it is convient to directly instantiate target passes with -/// non-default ctors. These often don't have a registered PassInfo. Rather than -/// force all target passes to implement the pass registry boilerplate, allow -/// the PassConfig API to handle either type. -/// -/// AnalysisID is sadly char*, so PointerIntPair won't work. -class IdentifyingPassPtr { - union { - AnalysisID ID; - Pass *P; - }; - bool IsInstance; -public: - IdentifyingPassPtr() : P(nullptr), IsInstance(false) {} - IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr), IsInstance(false) {} - IdentifyingPassPtr(Pass *InstancePtr) : P(InstancePtr), IsInstance(true) {} - - bool isValid() const { return P; } - bool isInstance() const { return IsInstance; } - - AnalysisID getID() const { - assert(!IsInstance && "Not a Pass ID"); - return ID; - } - Pass *getInstance() const { - assert(IsInstance && "Not a Pass Instance"); - return P; - } -}; - -template <> struct isPodLike<IdentifyingPassPtr> { - static const bool value = true; -}; - -/// Target-Independent Code Generator Pass Configuration Options. -/// -/// This is an ImmutablePass solely for the purpose of exposing CodeGen options -/// to the internals of other CodeGen passes. -class TargetPassConfig : public ImmutablePass { -public: - /// Pseudo Pass IDs. These are defined within TargetPassConfig because they - /// are unregistered pass IDs. They are only useful for use with - /// TargetPassConfig APIs to identify multiple occurrences of the same pass. - /// - - /// EarlyTailDuplicate - A clone of the TailDuplicate pass that runs early - /// during codegen, on SSA form. - static char EarlyTailDuplicateID; - - /// PostRAMachineLICM - A clone of the LICM pass that runs during late machine - /// optimization after regalloc. - static char PostRAMachineLICMID; - -private: - PassManagerBase *PM; - AnalysisID StartBefore, StartAfter; - AnalysisID StopAfter; - bool Started; - bool Stopped; - bool AddingMachinePasses; - -protected: - TargetMachine *TM; - PassConfigImpl *Impl; // Internal data structures - bool Initialized; // Flagged after all passes are configured. - - // Target Pass Options - // Targets provide a default setting, user flags override. - // - bool DisableVerify; - - /// Default setting for -enable-tail-merge on this target. - bool EnableTailMerge; - -public: - TargetPassConfig(TargetMachine *tm, PassManagerBase &pm); - // Dummy constructor. - TargetPassConfig(); - - ~TargetPassConfig() override; - - static char ID; - - /// Get the right type of TargetMachine for this target. - template<typename TMC> TMC &getTM() const { - return *static_cast<TMC*>(TM); - } - - // - void setInitialized() { Initialized = true; } - - CodeGenOpt::Level getOptLevel() const { return TM->getOptLevel(); } - - /// Set the StartAfter, StartBefore and StopAfter passes to allow running only - /// a portion of the normal code-gen pass sequence. - /// - /// If the StartAfter and StartBefore pass ID is zero, then compilation will - /// begin at the normal point; otherwise, clear the Started flag to indicate - /// that passes should not be added until the starting pass is seen. If the - /// Stop pass ID is zero, then compilation will continue to the end. - /// - /// This function expects that at least one of the StartAfter or the - /// StartBefore pass IDs is null. - void setStartStopPasses(AnalysisID StartBefore, AnalysisID StartAfter, - AnalysisID StopAfter) { - if (StartAfter) - assert(!StartBefore && "Start after and start before passes are given"); - this->StartBefore = StartBefore; - this->StartAfter = StartAfter; - this->StopAfter = StopAfter; - Started = (StartAfter == nullptr) && (StartBefore == nullptr); - } - - void setDisableVerify(bool Disable) { setOpt(DisableVerify, Disable); } - bool getEnableTailMerge() const { return EnableTailMerge; } - void setEnableTailMerge(bool Enable) { setOpt(EnableTailMerge, Enable); } - - /// Allow the target to override a specific pass without overriding the pass - /// pipeline. When passes are added to the standard pipeline at the - /// point where StandardID is expected, add TargetID in its place. - void substitutePass(AnalysisID StandardID, IdentifyingPassPtr TargetID); - - /// Insert InsertedPassID pass after TargetPassID pass. - void insertPass(AnalysisID TargetPassID, IdentifyingPassPtr InsertedPassID, - bool VerifyAfter = true, bool PrintAfter = true); - - /// Allow the target to enable a specific standard pass by default. - void enablePass(AnalysisID PassID) { substitutePass(PassID, PassID); } - - /// Allow the target to disable a specific standard pass by default. - void disablePass(AnalysisID PassID) { - substitutePass(PassID, IdentifyingPassPtr()); - } - - /// Return the pass substituted for StandardID by the target. - /// If no substitution exists, return StandardID. - IdentifyingPassPtr getPassSubstitution(AnalysisID StandardID) const; - - /// Return true if the optimized regalloc pipeline is enabled. - bool getOptimizeRegAlloc() const; - - /// Return true if shrink wrapping is enabled. - bool getEnableShrinkWrap() const; - - /// Return true if the default global register allocator is in use and - /// has not be overriden on the command line with '-regalloc=...' - bool usingDefaultRegAlloc() const; - - /// Add common target configurable passes that perform LLVM IR to IR - /// transforms following machine independent optimization. - virtual void addIRPasses(); - - /// Add passes to lower exception handling for the code generator. - void addPassesToHandleExceptions(); - - /// Add pass to prepare the LLVM IR for code generation. This should be done - /// before exception handling preparation passes. - virtual void addCodeGenPrepare(); - - /// Add common passes that perform LLVM IR to IR transforms in preparation for - /// instruction selection. - virtual void addISelPrepare(); - - /// addInstSelector - This method should install an instruction selector pass, - /// which converts from LLVM code to machine instructions. - virtual bool addInstSelector() { - return true; - } - - /// Add the complete, standard set of LLVM CodeGen passes. - /// Fully developed targets will not generally override this. - virtual void addMachinePasses(); - - /// Create an instance of ScheduleDAGInstrs to be run within the standard - /// MachineScheduler pass for this function and target at the current - /// optimization level. - /// - /// This can also be used to plug a new MachineSchedStrategy into an instance - /// of the standard ScheduleDAGMI: - /// return new ScheduleDAGMI(C, make_unique<MyStrategy>(C), /*RemoveKillFlags=*/false) - /// - /// Return NULL to select the default (generic) machine scheduler. - virtual ScheduleDAGInstrs * - createMachineScheduler(MachineSchedContext *C) const { - return nullptr; - } - - /// Similar to createMachineScheduler but used when postRA machine scheduling - /// is enabled. - virtual ScheduleDAGInstrs * - createPostMachineScheduler(MachineSchedContext *C) const { - return nullptr; - } - -protected: - // Helper to verify the analysis is really immutable. - void setOpt(bool &Opt, bool Val); - - /// Methods with trivial inline returns are convenient points in the common - /// codegen pass pipeline where targets may insert passes. Methods with - /// out-of-line standard implementations are major CodeGen stages called by - /// addMachinePasses. Some targets may override major stages when inserting - /// passes is insufficient, but maintaining overriden stages is more work. - /// - - /// addPreISelPasses - This method should add any "last minute" LLVM->LLVM - /// passes (which are run just before instruction selector). - virtual bool addPreISel() { - return true; - } - - /// addMachineSSAOptimization - Add standard passes that optimize machine - /// instructions in SSA form. - virtual void addMachineSSAOptimization(); - - /// Add passes that optimize instruction level parallelism for out-of-order - /// targets. These passes are run while the machine code is still in SSA - /// form, so they can use MachineTraceMetrics to control their heuristics. - /// - /// All passes added here should preserve the MachineDominatorTree, - /// MachineLoopInfo, and MachineTraceMetrics analyses. - virtual bool addILPOpts() { - return false; - } - - /// This method may be implemented by targets that want to run passes - /// immediately before register allocation. - virtual void addPreRegAlloc() { } - - /// createTargetRegisterAllocator - Create the register allocator pass for - /// this target at the current optimization level. - virtual FunctionPass *createTargetRegisterAllocator(bool Optimized); - - /// addFastRegAlloc - Add the minimum set of target-independent passes that - /// are required for fast register allocation. - virtual void addFastRegAlloc(FunctionPass *RegAllocPass); - - /// addOptimizedRegAlloc - Add passes related to register allocation. - /// LLVMTargetMachine provides standard regalloc passes for most targets. - virtual void addOptimizedRegAlloc(FunctionPass *RegAllocPass); - - /// addPreRewrite - Add passes to the optimized register allocation pipeline - /// after register allocation is complete, but before virtual registers are - /// rewritten to physical registers. - /// - /// These passes must preserve VirtRegMap and LiveIntervals, and when running - /// after RABasic or RAGreedy, they should take advantage of LiveRegMatrix. - /// When these passes run, VirtRegMap contains legal physreg assignments for - /// all virtual registers. - virtual bool addPreRewrite() { - return false; - } - - /// This method may be implemented by targets that want to run passes after - /// register allocation pass pipeline but before prolog-epilog insertion. - virtual void addPostRegAlloc() { } - - /// Add passes that optimize machine instructions after register allocation. - virtual void addMachineLateOptimization(); - - /// This method may be implemented by targets that want to run passes after - /// prolog-epilog insertion and before the second instruction scheduling pass. - virtual void addPreSched2() { } - - /// addGCPasses - Add late codegen passes that analyze code for garbage - /// collection. This should return true if GC info should be printed after - /// these passes. - virtual bool addGCPasses(); - - /// Add standard basic block placement passes. - virtual void addBlockPlacement(); - - /// This pass may be implemented by targets that want to run passes - /// immediately before machine code is emitted. - virtual void addPreEmitPass() { } - - /// Utilities for targets to add passes to the pass manager. - /// - - /// Add a CodeGen pass at this point in the pipeline after checking overrides. - /// Return the pass that was added, or zero if no pass was added. - /// @p printAfter if true and adding a machine function pass add an extra - /// machine printer pass afterwards - /// @p verifyAfter if true and adding a machine function pass add an extra - /// machine verification pass afterwards. - AnalysisID addPass(AnalysisID PassID, bool verifyAfter = true, - bool printAfter = true); - - /// Add a pass to the PassManager if that pass is supposed to be run, as - /// determined by the StartAfter and StopAfter options. Takes ownership of the - /// pass. - /// @p printAfter if true and adding a machine function pass add an extra - /// machine printer pass afterwards - /// @p verifyAfter if true and adding a machine function pass add an extra - /// machine verification pass afterwards. - void addPass(Pass *P, bool verifyAfter = true, bool printAfter = true); - - /// addMachinePasses helper to create the target-selected or overriden - /// regalloc pass. - FunctionPass *createRegAllocPass(bool Optimized); - - /// printAndVerify - Add a pass to dump then verify the machine function, if - /// those steps are enabled. - /// - void printAndVerify(const std::string &Banner); - - /// Add a pass to print the machine function if printing is enabled. - void addPrintPass(const std::string &Banner); - - /// Add a pass to perform basic verification of the machine function if - /// verification is enabled. - void addVerifyPass(const std::string &Banner); -}; -} // namespace llvm +} // End llvm namespace /// List of target independent CodeGen pass IDs. namespace llvm { @@ -457,6 +126,9 @@ namespace llvm { /// DeadMachineInstructionElim - This pass removes dead machine instructions. extern char &DeadMachineInstructionElimID; + /// This pass adds dead/undef flags after analyzing subregister lanes. + extern char &DetectDeadLanesID; + /// FastRegisterAllocation Pass - This pass register allocates as fast as /// possible. It is best suited for debug code where live ranges are short. /// @@ -480,11 +152,16 @@ namespace llvm { /// PrologEpilogCodeInserter - This pass inserts prolog and epilog code, /// and eliminates abstract frame references. extern char &PrologEpilogCodeInserterID; + MachineFunctionPass *createPrologEpilogInserterPass(const TargetMachine *TM); /// ExpandPostRAPseudos - This pass expands pseudo instructions after /// register allocation. extern char &ExpandPostRAPseudosID; + /// createPostRAHazardRecognizer - This pass runs the post-ra hazard + /// recognizer. + extern char &PostRAHazardRecognizerID; + /// createPostRAScheduler - This pass performs post register allocation /// scheduling. extern char &PostRASchedulerID; @@ -586,6 +263,13 @@ namespace llvm { /// \brief This pass lays out funclets contiguously. extern char &FuncletLayoutID; + /// This pass inserts the XRay instrumentation sleds if they are supported by + /// the target platform. + extern char &XRayInstrumentationID; + + /// \brief This pass implements the "patchable-function" attribute. + extern char &PatchableFunctionID; + /// createStackProtectorPass - This pass adds stack protectors to functions. /// FunctionPass *createStackProtectorPass(const TargetMachine *TM); @@ -654,6 +338,42 @@ namespace llvm { /// memory accesses to target specific intrinsics. /// FunctionPass *createInterleavedAccessPass(const TargetMachine *TM); + + /// LowerEmuTLS - This pass generates __emutls_[vt].xyz variables for all + /// TLS variables for the emulated TLS model. + /// + ModulePass *createLowerEmuTLSPass(const TargetMachine *TM); + + /// This pass lowers the @llvm.load.relative intrinsic to instructions. + /// This is unsafe to do earlier because a pass may combine the constant + /// initializer into the load, which may result in an overflowing evaluation. + ModulePass *createPreISelIntrinsicLoweringPass(); + + /// GlobalMerge - This pass merges internal (by default) globals into structs + /// to enable reuse of a base pointer by indexed addressing modes. + /// It can also be configured to focus on size optimizations only. + /// + Pass *createGlobalMergePass(const TargetMachine *TM, unsigned MaximalOffset, + bool OnlyOptimizeForSize = false, + bool MergeExternalByDefault = false); + + /// This pass splits the stack into a safe stack and an unsafe stack to + /// protect against stack-based overflow vulnerabilities. + FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr); + + /// This pass detects subregister lanes in a virtual register that are used + /// independently of other lanes and splits them into separate virtual + /// registers. + extern char &RenameIndependentSubregsID; + + /// This pass is executed POST-RA to collect which physical registers are + /// preserved by given machine function. + FunctionPass *createRegUsageInfoCollector(); + + /// Return a MachineFunction pass that identifies call sites + /// and propagates register usage information of callee to caller + /// if available with PysicalRegisterUsageInfo pass. + FunctionPass *createRegUsageInfoPropPass(); } // End llvm namespace /// Target machine pass initializer for passes with dependencies. Use with @@ -662,15 +382,18 @@ namespace llvm { /// Target machine pass initializer for passes with dependencies. Use with /// INITIALIZE_TM_PASS_BEGIN. -#define INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis, \ - PassInfo::TargetMachineCtor_t(callTargetMachineCtor< passName >)); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis, \ + PassInfo::TargetMachineCtor_t(callTargetMachineCtor<passName>)); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } /// This initializer registers TargetMachine constructor, so the pass being @@ -678,8 +401,8 @@ namespace llvm { /// macro to be together with INITIALIZE_PASS, which is a complete target /// independent initializer, and we don't want to make libScalarOpts depend /// on libCodeGen. -#define INITIALIZE_TM_PASS(passName, arg, name, cfg, analysis) \ - INITIALIZE_TM_PASS_BEGIN(passName, arg, name, cfg, analysis) \ - INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) +#define INITIALIZE_TM_PASS(passName, arg, name, cfg, analysis) \ + INITIALIZE_TM_PASS_BEGIN(passName, arg, name, cfg, analysis) \ + INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) #endif diff --git a/include/llvm/CodeGen/PreISelIntrinsicLowering.h b/include/llvm/CodeGen/PreISelIntrinsicLowering.h new file mode 100644 index 000000000000..765ca085244a --- /dev/null +++ b/include/llvm/CodeGen/PreISelIntrinsicLowering.h @@ -0,0 +1,26 @@ +//===--- PreISelIntrinsicLowering.h - Pre-ISel intrinsic lowering pass ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass implements IR lowering for the llvm.load.relative intrinsic. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CODEGEN_PREISELINTRINSICLOWERING_H +#define LLVM_CODEGEN_PREISELINTRINSICLOWERING_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct PreISelIntrinsicLoweringPass + : PassInfoMixin<PreISelIntrinsicLoweringPass> { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; +} + +#endif // LLVM_CODEGEN_PREISELINTRINSICLOWERING_H diff --git a/include/llvm/CodeGen/PseudoSourceValue.h b/include/llvm/CodeGen/PseudoSourceValue.h index f67552030db4..c3f6fde9fb3f 100644 --- a/include/llvm/CodeGen/PseudoSourceValue.h +++ b/include/llvm/CodeGen/PseudoSourceValue.h @@ -27,6 +27,8 @@ class MachineMemOperand; class raw_ostream; raw_ostream &operator<<(raw_ostream &OS, const MachineMemOperand &MMO); +class PseudoSourceValue; +raw_ostream &operator<<(raw_ostream &OS, const PseudoSourceValue* PSV); /// Special value supplied for machine level alias analysis. It indicates that /// a memory access references the functions stack frame (e.g., a spill slot), @@ -45,6 +47,8 @@ public: private: PSVKind Kind; + friend raw_ostream &llvm::operator<<(raw_ostream &OS, + const PseudoSourceValue* PSV); friend class MachineMemOperand; // For printCustom(). diff --git a/include/llvm/CodeGen/RegAllocPBQP.h b/include/llvm/CodeGen/RegAllocPBQP.h index 4122811a9e5c..21952272ffdb 100644 --- a/include/llvm/CodeGen/RegAllocPBQP.h +++ b/include/llvm/CodeGen/RegAllocPBQP.h @@ -21,6 +21,7 @@ #include "llvm/CodeGen/PBQP/ReductionRules.h" #include "llvm/CodeGen/PBQPRAConstraint.h" #include "llvm/Support/ErrorHandling.h" +#include <set> namespace llvm { diff --git a/include/llvm/CodeGen/RegisterPressure.h b/include/llvm/CodeGen/RegisterPressure.h index 9bbdf3e071bd..aaddac40ca76 100644 --- a/include/llvm/CodeGen/RegisterPressure.h +++ b/include/llvm/CodeGen/RegisterPressure.h @@ -26,14 +26,22 @@ class LiveRange; class RegisterClassInfo; class MachineInstr; +struct RegisterMaskPair { + unsigned RegUnit; ///< Virtual register or register unit. + LaneBitmask LaneMask; + + RegisterMaskPair(unsigned RegUnit, LaneBitmask LaneMask) + : RegUnit(RegUnit), LaneMask(LaneMask) {} +}; + /// Base class for register pressure results. struct RegisterPressure { /// Map of max reg pressure indexed by pressure set ID, not class ID. std::vector<unsigned> MaxSetPressure; /// List of live in virtual registers or physical register units. - SmallVector<unsigned,8> LiveInRegs; - SmallVector<unsigned,8> LiveOutRegs; + SmallVector<RegisterMaskPair,8> LiveInRegs; + SmallVector<RegisterMaskPair,8> LiveOutRegs; void dump(const TargetRegisterInfo *TRI) const; }; @@ -144,23 +152,32 @@ public: /// List of registers defined and used by a machine instruction. class RegisterOperands { public: - /// List of virtual regiserts and register units read by the instruction. - SmallVector<unsigned, 8> Uses; + /// List of virtual registers and register units read by the instruction. + SmallVector<RegisterMaskPair, 8> Uses; /// \brief List of virtual registers and register units defined by the /// instruction which are not dead. - SmallVector<unsigned, 8> Defs; + SmallVector<RegisterMaskPair, 8> Defs; /// \brief List of virtual registers and register units defined by the /// instruction but dead. - SmallVector<unsigned, 8> DeadDefs; + SmallVector<RegisterMaskPair, 8> DeadDefs; /// Analyze the given instruction \p MI and fill in the Uses, Defs and /// DeadDefs list based on the MachineOperand flags. void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI, - const MachineRegisterInfo &MRI, bool IgnoreDead = false); + const MachineRegisterInfo &MRI, bool TrackLaneMasks, + bool IgnoreDead); /// Use liveness information to find dead defs not marked with a dead flag /// and move them to the DeadDefs vector. void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS); + + /// Use liveness information to find out which uses/defs are partially + /// undefined/dead and adjust the RegisterMaskPairs accordingly. + /// If \p AddFlagsMI is given then missing read-undef and dead flags will be + /// added to the instruction. + void adjustLaneLiveness(const LiveIntervals &LIS, + const MachineRegisterInfo &MRI, SlotIndex Pos, + MachineInstr *AddFlagsMI = nullptr); }; /// Array of PressureDiffs. @@ -225,7 +242,20 @@ struct RegPressureDelta { /// and virtual register indexes to an index usable by the sparse set. class LiveRegSet { private: - SparseSet<unsigned> Regs; + struct IndexMaskPair { + unsigned Index; + LaneBitmask LaneMask; + + IndexMaskPair(unsigned Index, LaneBitmask LaneMask) + : Index(Index), LaneMask(LaneMask) {} + + unsigned getSparseSetIndex() const { + return Index; + } + }; + + typedef SparseSet<IndexMaskPair> RegSet; + RegSet Regs; unsigned NumRegUnits; unsigned getSparseIndexFromReg(unsigned Reg) const { @@ -244,19 +274,37 @@ public: void clear(); void init(const MachineRegisterInfo &MRI); - bool contains(unsigned Reg) const { + LaneBitmask contains(unsigned Reg) const { unsigned SparseIndex = getSparseIndexFromReg(Reg); - return Regs.count(SparseIndex); + RegSet::const_iterator I = Regs.find(SparseIndex); + if (I == Regs.end()) + return 0; + return I->LaneMask; } - bool insert(unsigned Reg) { - unsigned SparseIndex = getSparseIndexFromReg(Reg); - return Regs.insert(SparseIndex).second; + /// Mark the \p Pair.LaneMask lanes of \p Pair.Reg as live. + /// Returns the previously live lanes of \p Pair.Reg. + LaneBitmask insert(RegisterMaskPair Pair) { + unsigned SparseIndex = getSparseIndexFromReg(Pair.RegUnit); + auto InsertRes = Regs.insert(IndexMaskPair(SparseIndex, Pair.LaneMask)); + if (!InsertRes.second) { + unsigned PrevMask = InsertRes.first->LaneMask; + InsertRes.first->LaneMask |= Pair.LaneMask; + return PrevMask; + } + return 0; } - bool erase(unsigned Reg) { - unsigned SparseIndex = getSparseIndexFromReg(Reg); - return Regs.erase(SparseIndex); + /// Clears the \p Pair.LaneMask lanes of \p Pair.Reg (mark them as dead). + /// Returns the previously live lanes of \p Pair.Reg. + LaneBitmask erase(RegisterMaskPair Pair) { + unsigned SparseIndex = getSparseIndexFromReg(Pair.RegUnit); + RegSet::iterator I = Regs.find(SparseIndex); + if (I == Regs.end()) + return 0; + unsigned PrevMask = I->LaneMask; + I->LaneMask &= ~Pair.LaneMask; + return PrevMask; } size_t size() const { @@ -265,9 +313,10 @@ public: template<typename ContainerT> void appendTo(ContainerT &To) const { - for (unsigned I : Regs) { - unsigned Reg = getRegFromSparseIndex(I); - To.push_back(Reg); + for (const IndexMaskPair &P : Regs) { + unsigned Reg = getRegFromSparseIndex(P.Index); + if (P.LaneMask != 0) + To.push_back(RegisterMaskPair(Reg, P.LaneMask)); } } }; @@ -308,6 +357,9 @@ class RegPressureTracker { /// True if UntiedDefs will be populated. bool TrackUntiedDefs; + /// True if lanemasks should be tracked. + bool TrackLaneMasks; + /// Register pressure corresponds to liveness before this instruction /// iterator. It may point to the end of the block or a DebugValue rather than /// an instruction. @@ -327,23 +379,23 @@ class RegPressureTracker { public: RegPressureTracker(IntervalPressure &rp) : MF(nullptr), TRI(nullptr), RCI(nullptr), LIS(nullptr), MBB(nullptr), P(rp), - RequireIntervals(true), TrackUntiedDefs(false) {} + RequireIntervals(true), TrackUntiedDefs(false), TrackLaneMasks(false) {} RegPressureTracker(RegionPressure &rp) : MF(nullptr), TRI(nullptr), RCI(nullptr), LIS(nullptr), MBB(nullptr), P(rp), - RequireIntervals(false), TrackUntiedDefs(false) {} + RequireIntervals(false), TrackUntiedDefs(false), TrackLaneMasks(false) {} void reset(); void init(const MachineFunction *mf, const RegisterClassInfo *rci, const LiveIntervals *lis, const MachineBasicBlock *mbb, MachineBasicBlock::const_iterator pos, - bool ShouldTrackUntiedDefs = false); + bool TrackLaneMasks, bool TrackUntiedDefs); /// Force liveness of virtual registers or physical register /// units. Particularly useful to initialize the livein/out state of the /// tracker before the first call to advance/recede. - void addLiveRegs(ArrayRef<unsigned> Regs); + void addLiveRegs(ArrayRef<RegisterMaskPair> Regs); /// Get the MI position corresponding to this register pressure. MachineBasicBlock::const_iterator getPos() const { return CurrPos; } @@ -355,14 +407,14 @@ public: void setPos(MachineBasicBlock::const_iterator Pos) { CurrPos = Pos; } /// Recede across the previous instruction. - void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr); + void recede(SmallVectorImpl<RegisterMaskPair> *LiveUses = nullptr); /// Recede across the previous instruction. /// This "low-level" variant assumes that recedeSkipDebugValues() was /// called previously and takes precomputed RegisterOperands for the /// instruction. void recede(const RegisterOperands &RegOpers, - SmallVectorImpl<unsigned> *LiveUses = nullptr); + SmallVectorImpl<RegisterMaskPair> *LiveUses = nullptr); /// Recede until we find an instruction which is not a DebugValue. void recedeSkipDebugValues(); @@ -370,6 +422,11 @@ public: /// Advance across the current instruction. void advance(); + /// Advance across the current instruction. + /// This is a "low-level" variant of advance() which takes precomputed + /// RegisterOperands of the instruction. + void advance(const RegisterOperands &RegOpers); + /// Finalize the region boundaries and recored live ins and live outs. void closeRegion(); @@ -469,18 +526,31 @@ public: void dump() const; protected: - void discoverLiveOut(unsigned Reg); - void discoverLiveIn(unsigned Reg); + /// Add Reg to the live out set and increase max pressure. + void discoverLiveOut(RegisterMaskPair Pair); + /// Add Reg to the live in set and increase max pressure. + void discoverLiveIn(RegisterMaskPair Pair); /// \brief Get the SlotIndex for the first nondebug instruction including or /// after the current position. SlotIndex getCurrSlot() const; - void increaseRegPressure(ArrayRef<unsigned> Regs); - void decreaseRegPressure(ArrayRef<unsigned> Regs); + void increaseRegPressure(unsigned RegUnit, LaneBitmask PreviousMask, + LaneBitmask NewMask); + void decreaseRegPressure(unsigned RegUnit, LaneBitmask PreviousMask, + LaneBitmask NewMask); + + void bumpDeadDefs(ArrayRef<RegisterMaskPair> DeadDefs); void bumpUpwardPressure(const MachineInstr *MI); void bumpDownwardPressure(const MachineInstr *MI); + + void discoverLiveInOrOut(RegisterMaskPair Pair, + SmallVectorImpl<RegisterMaskPair> &LiveInOrOut); + + LaneBitmask getLastUsedLanes(unsigned RegUnit, SlotIndex Pos) const; + LaneBitmask getLiveLanesAt(unsigned RegUnit, SlotIndex Pos) const; + LaneBitmask getLiveThroughAt(unsigned RegUnit, SlotIndex Pos) const; }; void dumpRegSetPressure(ArrayRef<unsigned> SetPressure, diff --git a/include/llvm/CodeGen/RegisterScavenging.h b/include/llvm/CodeGen/RegisterScavenging.h index 122c78534253..efe1a3c6d0f7 100644 --- a/include/llvm/CodeGen/RegisterScavenging.h +++ b/include/llvm/CodeGen/RegisterScavenging.h @@ -7,10 +7,11 @@ // //===----------------------------------------------------------------------===// // -// This file declares the machine register scavenger class. It can provide -// information such as unused register at any point in a machine basic block. -// It also provides a mechanism to make registers available by evicting them -// to spill slots. +/// \file +/// This file declares the machine register scavenger class. It can provide +/// information such as unused register at any point in a machine basic block. +/// It also provides a mechanism to make registers available by evicting them +/// to spill slots. // //===----------------------------------------------------------------------===// @@ -71,8 +72,8 @@ public: RegScavenger() : MBB(nullptr), NumRegUnits(0), Tracking(false) {} - /// Start tracking liveness from the begin of the specific basic block. - void enterBasicBlock(MachineBasicBlock *mbb); + /// Start tracking liveness from the begin of basic block \p MBB. + void enterBasicBlock(MachineBasicBlock &MBB); /// Move the internal MBB iterator and update register states. void forward(); diff --git a/include/llvm/CodeGen/RegisterUsageInfo.h b/include/llvm/CodeGen/RegisterUsageInfo.h new file mode 100644 index 000000000000..3f88032cb638 --- /dev/null +++ b/include/llvm/CodeGen/RegisterUsageInfo.h @@ -0,0 +1,75 @@ +//==- RegisterUsageInfo.h - Register Usage Informartion Storage -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This pass is required to take advantage of the interprocedural register +/// allocation infrastructure. +/// +/// This pass is simple immutable pass which keeps RegMasks (calculated based on +/// actual register allocation) for functions in a module and provides simple +/// API to query this information. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PHYSICALREGISTERUSAGEINFO_H +#define LLVM_CODEGEN_PHYSICALREGISTERUSAGEINFO_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class PhysicalRegisterUsageInfo : public ImmutablePass { + virtual void anchor(); + +public: + static char ID; + + PhysicalRegisterUsageInfo() : ImmutablePass(ID) { + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializePhysicalRegisterUsageInfoPass(Registry); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + /// To set TargetMachine *, which is used to print + /// analysis when command line option -print-regusage is used. + void setTargetMachine(const TargetMachine *TM_) { TM = TM_; } + + bool doInitialization(Module &M) override; + + bool doFinalization(Module &M) override; + + /// To store RegMask for given Function *. + void storeUpdateRegUsageInfo(const Function *FP, + std::vector<uint32_t> RegMask); + + /// To query stored RegMask for given Function *, it will return nullptr if + /// function is not known. + const std::vector<uint32_t> *getRegUsageInfo(const Function *FP); + + void print(raw_ostream &OS, const Module *M = nullptr) const override; + +private: + /// A Dense map from Function * to RegMask. + /// In RegMask 0 means register used (clobbered) by function. + /// and 1 means content of register will be preserved around function call. + DenseMap<const Function *, std::vector<uint32_t>> RegMasks; + + const TargetMachine *TM; +}; +} + +#endif diff --git a/include/llvm/CodeGen/ResourcePriorityQueue.h b/include/llvm/CodeGen/ResourcePriorityQueue.h index 0097e0472e5c..9c8f5f487d38 100644 --- a/include/llvm/CodeGen/ResourcePriorityQueue.h +++ b/include/llvm/CodeGen/ResourcePriorityQueue.h @@ -72,7 +72,7 @@ namespace llvm { /// Heuristics for estimating register pressure. unsigned ParallelLiveRanges; - signed HorizontalVerticalBalance; + int HorizontalVerticalBalance; public: ResourcePriorityQueue(SelectionDAGISel *IS); @@ -103,14 +103,14 @@ namespace llvm { /// Single cost function reflecting benefit of scheduling SU /// in the current cycle. - signed SUSchedulingCost (SUnit *SU); + int SUSchedulingCost (SUnit *SU); /// InitNumRegDefsLeft - Determine the # of regs defined by this node. /// void initNumRegDefsLeft(SUnit *SU); void updateNumRegDefsLeft(SUnit *SU); - signed regPressureDelta(SUnit *SU, bool RawPressure = false); - signed rawRegPressureDelta (SUnit *SU, unsigned RCId); + int regPressureDelta(SUnit *SU, bool RawPressure = false); + int rawRegPressureDelta (SUnit *SU, unsigned RCId); bool empty() const override { return Queue.empty(); } diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index 7db03459f9bf..16d305c7297f 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -215,6 +215,8 @@ namespace RTLIB { FMAX_PPCF128, // CONVERSION + FPEXT_F32_PPCF128, + FPEXT_F64_PPCF128, FPEXT_F64_F128, FPEXT_F32_F128, FPEXT_F32_F64, @@ -296,27 +298,35 @@ namespace RTLIB { OEQ_F32, OEQ_F64, OEQ_F128, + OEQ_PPCF128, UNE_F32, UNE_F64, UNE_F128, + UNE_PPCF128, OGE_F32, OGE_F64, OGE_F128, + OGE_PPCF128, OLT_F32, OLT_F64, OLT_F128, + OLT_PPCF128, OLE_F32, OLE_F64, OLE_F128, + OLE_PPCF128, OGT_F32, OGT_F64, OGT_F128, + OGT_PPCF128, UO_F32, UO_F64, UO_F128, + UO_PPCF128, O_F32, O_F64, O_F128, + O_PPCF128, // MEMORY MEMCPY, @@ -326,7 +336,11 @@ namespace RTLIB { // EXCEPTION HANDLING UNWIND_RESUME, - // Family ATOMICs + // Note: there's two sets of atomics libcalls; see + // <http://llvm.org/docs/Atomics.html> for more info on the + // difference between them. + + // Atomic '__sync_*' libcalls. SYNC_VAL_COMPARE_AND_SWAP_1, SYNC_VAL_COMPARE_AND_SWAP_2, SYNC_VAL_COMPARE_AND_SWAP_4, @@ -388,9 +402,77 @@ namespace RTLIB { SYNC_FETCH_AND_UMIN_8, SYNC_FETCH_AND_UMIN_16, + // Atomic '__atomic_*' libcalls. + ATOMIC_LOAD, + ATOMIC_LOAD_1, + ATOMIC_LOAD_2, + ATOMIC_LOAD_4, + ATOMIC_LOAD_8, + ATOMIC_LOAD_16, + + ATOMIC_STORE, + ATOMIC_STORE_1, + ATOMIC_STORE_2, + ATOMIC_STORE_4, + ATOMIC_STORE_8, + ATOMIC_STORE_16, + + ATOMIC_EXCHANGE, + ATOMIC_EXCHANGE_1, + ATOMIC_EXCHANGE_2, + ATOMIC_EXCHANGE_4, + ATOMIC_EXCHANGE_8, + ATOMIC_EXCHANGE_16, + + ATOMIC_COMPARE_EXCHANGE, + ATOMIC_COMPARE_EXCHANGE_1, + ATOMIC_COMPARE_EXCHANGE_2, + ATOMIC_COMPARE_EXCHANGE_4, + ATOMIC_COMPARE_EXCHANGE_8, + ATOMIC_COMPARE_EXCHANGE_16, + + ATOMIC_FETCH_ADD_1, + ATOMIC_FETCH_ADD_2, + ATOMIC_FETCH_ADD_4, + ATOMIC_FETCH_ADD_8, + ATOMIC_FETCH_ADD_16, + + ATOMIC_FETCH_SUB_1, + ATOMIC_FETCH_SUB_2, + ATOMIC_FETCH_SUB_4, + ATOMIC_FETCH_SUB_8, + ATOMIC_FETCH_SUB_16, + + ATOMIC_FETCH_AND_1, + ATOMIC_FETCH_AND_2, + ATOMIC_FETCH_AND_4, + ATOMIC_FETCH_AND_8, + ATOMIC_FETCH_AND_16, + + ATOMIC_FETCH_OR_1, + ATOMIC_FETCH_OR_2, + ATOMIC_FETCH_OR_4, + ATOMIC_FETCH_OR_8, + ATOMIC_FETCH_OR_16, + + ATOMIC_FETCH_XOR_1, + ATOMIC_FETCH_XOR_2, + ATOMIC_FETCH_XOR_4, + ATOMIC_FETCH_XOR_8, + ATOMIC_FETCH_XOR_16, + + ATOMIC_FETCH_NAND_1, + ATOMIC_FETCH_NAND_2, + ATOMIC_FETCH_NAND_4, + ATOMIC_FETCH_NAND_8, + ATOMIC_FETCH_NAND_16, + // Stack Protector Fail. STACKPROTECTOR_CHECK_FAIL, + // Deoptimization. + DEOPTIMIZE, + UNKNOWN_LIBCALL }; @@ -420,7 +502,7 @@ namespace RTLIB { /// Return the SYNC_FETCH_AND_* value for the given opcode and type, or /// UNKNOWN_LIBCALL if there is none. - Libcall getATOMIC(unsigned Opc, MVT VT); + Libcall getSYNC(unsigned Opc, MVT VT); } } diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h index bda9dbd51fff..6469cabd3de1 100644 --- a/include/llvm/CodeGen/ScheduleDAG.h +++ b/include/llvm/CodeGen/ScheduleDAG.h @@ -396,6 +396,17 @@ namespace llvm { /// specified node. bool addPred(const SDep &D, bool Required = true); + /// addPredBarrier - This adds a barrier edge to SU by calling + /// addPred(), with latency 0 generally or latency 1 for a store + /// followed by a load. + bool addPredBarrier(SUnit *SU) { + SDep Dep(SU, SDep::Barrier); + unsigned TrueMemOrderLatency = + ((SU->getInstr()->mayStore() && this->getInstr()->mayLoad()) ? 1 : 0); + Dep.setLatency(TrueMemOrderLatency); + return addPred(Dep); + } + /// removePred - This removes the specified edge as a pred of the current /// node if it exists. It also removes the current node as a successor of /// the specified node. diff --git a/include/llvm/CodeGen/ScheduleDAGInstrs.h b/include/llvm/CodeGen/ScheduleDAGInstrs.h index c574df094911..12124ecc4b3e 100644 --- a/include/llvm/CodeGen/ScheduleDAGInstrs.h +++ b/include/llvm/CodeGen/ScheduleDAGInstrs.h @@ -15,12 +15,14 @@ #ifndef LLVM_CODEGEN_SCHEDULEDAGINSTRS_H #define LLVM_CODEGEN_SCHEDULEDAGINSTRS_H +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/SparseMultiSet.h" #include "llvm/ADT/SparseSet.h" #include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CodeGen/TargetSchedule.h" #include "llvm/Support/Compiler.h" #include "llvm/Target/TargetRegisterInfo.h" +#include <list> namespace llvm { class MachineFrameInfo; @@ -84,6 +86,15 @@ namespace llvm { typedef SparseMultiSet<VReg2SUnitOperIdx, VirtReg2IndexFunctor> VReg2SUnitOperIdxMultiMap; + typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType; + struct UnderlyingObject : PointerIntPair<ValueType, 1, bool> { + UnderlyingObject(ValueType V, bool MayAlias) + : PointerIntPair<ValueType, 1, bool>(V, MayAlias) {} + ValueType getValue() const { return getPointer(); } + bool mayAlias() const { return getInt(); } + }; + typedef SmallVector<UnderlyingObject, 4> UnderlyingObjectsVector; + /// ScheduleDAGInstrs - A ScheduleDAG subclass for scheduling lists of /// MachineInstrs. class ScheduleDAGInstrs : public ScheduleDAG { @@ -149,10 +160,66 @@ namespace llvm { /// Tracks the last instructions in this region using each virtual register. VReg2SUnitOperIdxMultiMap CurrentVRegUses; - /// PendingLoads - Remember where unknown loads are after the most recent - /// unknown store, as we iterate. As with Defs and Uses, this is here - /// to minimize construction/destruction. - std::vector<SUnit *> PendingLoads; + AliasAnalysis *AAForDep; + + /// Remember a generic side-effecting instruction as we proceed. + /// No other SU ever gets scheduled around it (except in the special + /// case of a huge region that gets reduced). + SUnit *BarrierChain; + + public: + + /// A list of SUnits, used in Value2SUsMap, during DAG construction. + /// Note: to gain speed it might be worth investigating an optimized + /// implementation of this data structure, such as a singly linked list + /// with a memory pool (SmallVector was tried but slow and SparseSet is not + /// applicable). + typedef std::list<SUnit *> SUList; + protected: + /// A map from ValueType to SUList, used during DAG construction, + /// as a means of remembering which SUs depend on which memory + /// locations. + class Value2SUsMap; + + /// Remove in FIFO order some SUs from huge maps. + void reduceHugeMemNodeMaps(Value2SUsMap &stores, + Value2SUsMap &loads, unsigned N); + + /// Add a chain edge between SUa and SUb, but only if both AliasAnalysis + /// and Target fail to deny the dependency. + void addChainDependency(SUnit *SUa, SUnit *SUb, + unsigned Latency = 0); + + /// Add dependencies as needed from all SUs in list to SU. + void addChainDependencies(SUnit *SU, SUList &sus, unsigned Latency) { + for (auto *su : sus) + addChainDependency(SU, su, Latency); + } + + /// Add dependencies as needed from all SUs in map, to SU. + void addChainDependencies(SUnit *SU, Value2SUsMap &Val2SUsMap); + + /// Add dependencies as needed to SU, from all SUs mapped to V. + void addChainDependencies(SUnit *SU, Value2SUsMap &Val2SUsMap, + ValueType V); + + /// Add barrier chain edges from all SUs in map, and then clear + /// the map. This is equivalent to insertBarrierChain(), but + /// optimized for the common case where the new BarrierChain (a + /// global memory object) has a higher NodeNum than all SUs in + /// map. It is assumed BarrierChain has been set before calling + /// this. + void addBarrierChain(Value2SUsMap &map); + + /// Insert a barrier chain in a huge region, far below current + /// SU. Add barrier chain edges from all SUs in map with higher + /// NodeNums than this new BarrierChain, and remove them from + /// map. It is assumed BarrierChain has been set before calling + /// this. + void insertBarrierChain(Value2SUsMap &map); + + /// For an unanalyzable memory access, this Value is used in maps. + UndefValue *UnknownValue; /// DbgValues - Remember instruction that precedes DBG_VALUE. /// These are generated by buildSchedGraph but persist so they can be @@ -214,6 +281,7 @@ namespace llvm { void buildSchedGraph(AliasAnalysis *AA, RegPressureTracker *RPTracker = nullptr, PressureDiffs *PDiffs = nullptr, + LiveIntervals *LIS = nullptr, bool TrackLaneMasks = false); /// addSchedBarrierDeps - Add dependencies from instructions in the current diff --git a/include/llvm/CodeGen/ScheduleDAGMutation.h b/include/llvm/CodeGen/ScheduleDAGMutation.h new file mode 100644 index 000000000000..02fe2294815c --- /dev/null +++ b/include/llvm/CodeGen/ScheduleDAGMutation.h @@ -0,0 +1,31 @@ +//==- ScheduleDAGMutation.h - MachineInstr Scheduling ------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ScheduleDAGMutation class, which represents +// a target-specific mutation of the dependency graph for scheduling. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SCHEDULEDAGMUTATION_H +#define LLVM_CODEGEN_SCHEDULEDAGMUTATION_H + +namespace llvm { + class ScheduleDAGInstrs; + + /// Mutate the DAG as a postpass after normal DAG building. + class ScheduleDAGMutation { + virtual void anchor(); + public: + virtual ~ScheduleDAGMutation() {} + + virtual void apply(ScheduleDAGInstrs *DAG) = 0; + }; +} + +#endif diff --git a/include/llvm/CodeGen/ScheduleHazardRecognizer.h b/include/llvm/CodeGen/ScheduleHazardRecognizer.h index 8a40e7212ff6..214be2794ba3 100644 --- a/include/llvm/CodeGen/ScheduleHazardRecognizer.h +++ b/include/llvm/CodeGen/ScheduleHazardRecognizer.h @@ -17,6 +17,7 @@ namespace llvm { +class MachineInstr; class SUnit; /// HazardRecognizer - This determines whether or not an instruction can be @@ -70,6 +71,10 @@ public: /// emitted, to advance the hazard state. virtual void EmitInstruction(SUnit *) {} + /// This overload will be used when the hazard recognizer is being used + /// by a non-scheduling pass, which does not use SUnits. + virtual void EmitInstruction(MachineInstr *) {} + /// PreEmitNoops - This callback is invoked prior to emitting an instruction. /// It should return the number of noops to emit prior to the provided /// instruction. @@ -79,6 +84,12 @@ public: return 0; } + /// This overload will be used when the hazard recognizer is being used + /// by a non-scheduling pass, which does not use SUnits. + virtual unsigned PreEmitNoops(MachineInstr *) { + return 0; + } + /// ShouldPreferAnother - This callback may be invoked if getHazardType /// returns NoHazard. If, even though there is no hazard, it would be better to /// schedule another available instruction, this callback should return true. diff --git a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h index ab14c2de32b0..e0c30fe4d82a 100644 --- a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h +++ b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h @@ -83,11 +83,9 @@ class ScoreboardHazardRecognizer : public ScheduleHazardRecognizer { void dump() const; }; -#ifndef NDEBUG // Support for tracing ScoreboardHazardRecognizer as a component within - // another module. Follows the current thread-unsafe model of tracing. - static const char *DebugType; -#endif + // another module. + const char *DebugType; // Itinerary data for the target. const InstrItineraryData *ItinData; diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index a21e9ae881a7..29cce873c2f3 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -23,6 +23,7 @@ #include "llvm/CodeGen/DAGCombine.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/Support/ArrayRecycler.h" #include "llvm/Support/RecyclingAllocator.h" #include "llvm/Target/TargetMachine.h" #include <cassert> @@ -37,7 +38,7 @@ class MachineFunction; class MDNode; class SDDbgValue; class TargetLowering; -class TargetSelectionDAGInfo; +class SelectionDAGTargetInfo; class SDVTListNode : public FoldingSetNode { friend struct FoldingSetTrait<SDVTListNode>; @@ -178,7 +179,7 @@ void checkForCycles(const SelectionDAG *DAG, bool force = false); /// class SelectionDAG { const TargetMachine &TM; - const TargetSelectionDAGInfo *TSI; + const SelectionDAGTargetInfo *TSI; const TargetLowering *TLI; MachineFunction *MF; LLVMContext *Context; @@ -208,6 +209,7 @@ class SelectionDAG { /// Pool allocation for machine-opcode SDNode operands. BumpPtrAllocator OperandAllocator; + ArrayRecycler<SDUse> OperandRecycler; /// Pool allocation for misc. objects that are created once per SelectionDAG. BumpPtrAllocator Allocator; @@ -247,6 +249,14 @@ public: virtual void NodeUpdated(SDNode *N); }; + struct DAGNodeDeletedListener : public DAGUpdateListener { + std::function<void(SDNode *, SDNode *)> Callback; + DAGNodeDeletedListener(SelectionDAG &DAG, + std::function<void(SDNode *, SDNode *)> Callback) + : DAGUpdateListener(DAG), Callback(Callback) {} + void NodeDeleted(SDNode *N, SDNode *E) override { Callback(N, E); } + }; + /// When true, additional steps are taken to /// ensure that getConstant() and similar functions return DAG nodes that /// have legal types. This is important after type legalization since @@ -268,6 +278,36 @@ private: DenseSet<SDNode *> &visited, int level, bool &printed); + template <typename SDNodeT, typename... ArgTypes> + SDNodeT *newSDNode(ArgTypes &&... Args) { + return new (NodeAllocator.template Allocate<SDNodeT>()) + SDNodeT(std::forward<ArgTypes>(Args)...); + } + + void createOperands(SDNode *Node, ArrayRef<SDValue> Vals) { + assert(!Node->OperandList && "Node already has operands"); + SDUse *Ops = OperandRecycler.allocate( + ArrayRecycler<SDUse>::Capacity::get(Vals.size()), OperandAllocator); + + for (unsigned I = 0; I != Vals.size(); ++I) { + Ops[I].setUser(Node); + Ops[I].setInitial(Vals[I]); + } + Node->NumOperands = Vals.size(); + Node->OperandList = Ops; + checkForCycles(Node); + } + + void removeOperands(SDNode *Node) { + if (!Node->OperandList) + return; + OperandRecycler.deallocate( + ArrayRecycler<SDUse>::Capacity::get(Node->NumOperands), + Node->OperandList); + Node->NumOperands = 0; + Node->OperandList = nullptr; + } + void operator=(const SelectionDAG&) = delete; SelectionDAG(const SelectionDAG&) = delete; @@ -287,7 +327,7 @@ public: const TargetMachine &getTarget() const { return TM; } const TargetSubtargetInfo &getSubtarget() const { return MF->getSubtarget(); } const TargetLowering &getTargetLoweringInfo() const { return *TLI; } - const TargetSelectionDAGInfo &getSelectionDAGInfo() const { return *TSI; } + const SelectionDAGTargetInfo &getSelectionDAGInfo() const { return *TSI; } LLVMContext *getContext() const {return Context; } /// Pop up a GraphViz/gv window with the DAG rendered using 'dot'. @@ -427,45 +467,64 @@ public: //===--------------------------------------------------------------------===// // Node creation methods. // - SDValue getConstant(uint64_t Val, SDLoc DL, EVT VT, bool isTarget = false, - bool isOpaque = false); - SDValue getConstant(const APInt &Val, SDLoc DL, EVT VT, bool isTarget = false, - bool isOpaque = false); - SDValue getConstant(const ConstantInt &Val, SDLoc DL, EVT VT, + + /// \brief Create a ConstantSDNode wrapping a constant value. + /// If VT is a vector type, the constant is splatted into a BUILD_VECTOR. + /// + /// If only legal types can be produced, this does the necessary + /// transformations (e.g., if the vector element type is illegal). + /// @{ + SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, + bool isTarget = false, bool isOpaque = false); + SDValue getConstant(const APInt &Val, const SDLoc &DL, EVT VT, bool isTarget = false, bool isOpaque = false); - SDValue getIntPtrConstant(uint64_t Val, SDLoc DL, bool isTarget = false); - SDValue getTargetConstant(uint64_t Val, SDLoc DL, EVT VT, + SDValue getConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT, + bool isTarget = false, bool isOpaque = false); + SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, + bool isTarget = false); + SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } - SDValue getTargetConstant(const APInt &Val, SDLoc DL, EVT VT, + SDValue getTargetConstant(const APInt &Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } - SDValue getTargetConstant(const ConstantInt &Val, SDLoc DL, EVT VT, + SDValue getTargetConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } - // The forms below that take a double should only be used for simple - // constants that can be exactly represented in VT. No checks are made. - SDValue getConstantFP(double Val, SDLoc DL, EVT VT, bool isTarget = false); - SDValue getConstantFP(const APFloat& Val, SDLoc DL, EVT VT, + /// @} + + /// \brief Create a ConstantFPSDNode wrapping a constant value. + /// If VT is a vector type, the constant is splatted into a BUILD_VECTOR. + /// + /// If only legal types can be produced, this does the necessary + /// transformations (e.g., if the vector element type is illegal). + /// The forms that take a double should only be used for simple constants + /// that can be exactly represented in VT. No checks are made. + /// @{ + SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget = false); - SDValue getConstantFP(const ConstantFP &CF, SDLoc DL, EVT VT, + SDValue getConstantFP(const APFloat &Val, const SDLoc &DL, EVT VT, bool isTarget = false); - SDValue getTargetConstantFP(double Val, SDLoc DL, EVT VT) { + SDValue getConstantFP(const ConstantFP &CF, const SDLoc &DL, EVT VT, + bool isTarget = false); + SDValue getTargetConstantFP(double Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } - SDValue getTargetConstantFP(const APFloat& Val, SDLoc DL, EVT VT) { + SDValue getTargetConstantFP(const APFloat &Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } - SDValue getTargetConstantFP(const ConstantFP &Val, SDLoc DL, EVT VT) { + SDValue getTargetConstantFP(const ConstantFP &Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } - SDValue getGlobalAddress(const GlobalValue *GV, SDLoc DL, EVT VT, + /// @} + + SDValue getGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset = 0, bool isTargetGA = false, unsigned char TargetFlags = 0); - SDValue getTargetGlobalAddress(const GlobalValue *GV, SDLoc DL, EVT VT, + SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset = 0, unsigned char TargetFlags = 0) { return getGlobalAddress(GV, DL, VT, offset, true, TargetFlags); @@ -502,7 +561,7 @@ public: SDValue getBasicBlock(MachineBasicBlock *MBB); SDValue getBasicBlock(MachineBasicBlock *MBB, SDLoc dl); SDValue getExternalSymbol(const char *Sym, EVT VT); - SDValue getExternalSymbol(const char *Sym, SDLoc dl, EVT VT); + SDValue getExternalSymbol(const char *Sym, const SDLoc &dl, EVT VT); SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned char TargetFlags = 0); SDValue getMCSymbol(MCSymbol *Sym, EVT VT); @@ -510,7 +569,7 @@ public: SDValue getValueType(EVT); SDValue getRegister(unsigned Reg, EVT VT); SDValue getRegisterMask(const uint32_t *RegMask); - SDValue getEHLabel(SDLoc dl, SDValue Root, MCSymbol *Label); + SDValue getEHLabel(const SDLoc &dl, SDValue Root, MCSymbol *Label); SDValue getBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset = 0, bool isTarget = false, unsigned char TargetFlags = 0); @@ -520,7 +579,8 @@ public: return getBlockAddress(BA, VT, Offset, true, TargetFlags); } - SDValue getCopyToReg(SDValue Chain, SDLoc dl, unsigned Reg, SDValue N) { + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, + SDValue N) { return getNode(ISD::CopyToReg, dl, MVT::Other, Chain, getRegister(Reg, N.getValueType()), N); } @@ -528,7 +588,7 @@ public: // This version of the getCopyToReg method takes an extra operand, which // indicates that there is potentially an incoming glue value (if Glue is not // null) and that there should be a glue result. - SDValue getCopyToReg(SDValue Chain, SDLoc dl, unsigned Reg, SDValue N, + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, SDValue N, SDValue Glue) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, getRegister(Reg, N.getValueType()), N, Glue }; @@ -537,15 +597,15 @@ public: } // Similar to last getCopyToReg() except parameter Reg is a SDValue - SDValue getCopyToReg(SDValue Chain, SDLoc dl, SDValue Reg, SDValue N, - SDValue Glue) { + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, SDValue Reg, SDValue N, + SDValue Glue) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Reg, N, Glue }; return getNode(ISD::CopyToReg, dl, VTs, makeArrayRef(Ops, Glue.getNode() ? 4 : 3)); } - SDValue getCopyFromReg(SDValue Chain, SDLoc dl, unsigned Reg, EVT VT) { + SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT) { SDVTList VTs = getVTList(VT, MVT::Other); SDValue Ops[] = { Chain, getRegister(Reg, VT) }; return getNode(ISD::CopyFromReg, dl, VTs, Ops); @@ -554,8 +614,8 @@ public: // This version of the getCopyFromReg method takes an extra operand, which // indicates that there is potentially an incoming glue value (if Glue is not // null) and that there should be a glue result. - SDValue getCopyFromReg(SDValue Chain, SDLoc dl, unsigned Reg, EVT VT, - SDValue Glue) { + SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT, + SDValue Glue) { SDVTList VTs = getVTList(VT, MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, getRegister(Reg, VT), Glue }; return getNode(ISD::CopyFromReg, dl, VTs, @@ -566,20 +626,46 @@ public: /// Returns the ConvertRndSat Note: Avoid using this node because it may /// disappear in the future and most targets don't support it. - SDValue getConvertRndSat(EVT VT, SDLoc dl, SDValue Val, SDValue DTy, - SDValue STy, - SDValue Rnd, SDValue Sat, ISD::CvtCode Code); + SDValue getConvertRndSat(EVT VT, const SDLoc &dl, SDValue Val, SDValue DTy, + SDValue STy, SDValue Rnd, SDValue Sat, + ISD::CvtCode Code); /// Return an ISD::VECTOR_SHUFFLE node. The number of elements in VT, /// which must be a vector type, must match the number of mask elements /// NumElts. An integer mask element equal to -1 is treated as undefined. - SDValue getVectorShuffle(EVT VT, SDLoc dl, SDValue N1, SDValue N2, - const int *MaskElts); - SDValue getVectorShuffle(EVT VT, SDLoc dl, SDValue N1, SDValue N2, - ArrayRef<int> MaskElts) { - assert(VT.getVectorNumElements() == MaskElts.size() && - "Must have the same number of vector elements as mask elements!"); - return getVectorShuffle(VT, dl, N1, N2, MaskElts.data()); + SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, + ArrayRef<int> Mask); + + /// Return an ISD::BUILD_VECTOR node. The number of elements in VT, + /// which must be a vector type, must match the number of operands in Ops. + /// The operands must have the same type as (or, for integers, a type wider + /// than) VT's element type. + SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef<SDValue> Ops) { + // VerifySDNode (via InsertNode) checks BUILD_VECTOR later. + return getNode(ISD::BUILD_VECTOR, DL, VT, Ops); + } + + /// Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all + /// elements. VT must be a vector type. Op's type must be the same as (or, + /// for integers, a type wider than) VT's element type. + SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op) { + // VerifySDNode (via InsertNode) checks BUILD_VECTOR later. + if (Op.getOpcode() == ISD::UNDEF) { + assert((VT.getVectorElementType() == Op.getValueType() || + (VT.isInteger() && + VT.getVectorElementType().bitsLE(Op.getValueType()))) && + "A splatted value must have a width equal or (for integers) " + "greater than the vector element type!"); + return getNode(ISD::UNDEF, SDLoc(), VT); + } + + SmallVector<SDValue, 16> Ops(VT.getVectorNumElements(), Op); + return getNode(ISD::BUILD_VECTOR, DL, VT, Ops); + } + + /// Return a splat ISD::BUILD_VECTOR node, but with Op's SDLoc. + SDValue getSplatBuildVector(EVT VT, SDValue Op) { + return getSplatBuildVector(VT, SDLoc(Op), Op); } /// \brief Returns an ISD::VECTOR_SHUFFLE node semantically equivalent to @@ -590,52 +676,52 @@ public: /// Convert Op, which must be of integer type, to the /// integer type VT, by either any-extending or truncating it. - SDValue getAnyExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the /// integer type VT, by either sign-extending or truncating it. - SDValue getSExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getSExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the /// integer type VT, by either zero-extending or truncating it. - SDValue getZExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Return the expression required to zero extend the Op /// value assuming it was the smaller SrcTy value. - SDValue getZeroExtendInReg(SDValue Op, SDLoc DL, EVT SrcTy); + SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT SrcTy); /// Return an operation which will any-extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by any-extending the low four /// lanes of the operand from i8 to i32. - SDValue getAnyExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getAnyExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Return an operation which will sign extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by sign extending the low four /// lanes of the operand from i8 to i32. - SDValue getSignExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getSignExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Return an operation which will zero extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by zero extending the low four /// lanes of the operand from i8 to i32. - SDValue getZeroExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getZeroExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the integer type VT, /// by using an extension appropriate for the target's /// BooleanContent for type OpVT or truncating it. - SDValue getBoolExtOrTrunc(SDValue Op, SDLoc SL, EVT VT, EVT OpVT); + SDValue getBoolExtOrTrunc(SDValue Op, const SDLoc &SL, EVT VT, EVT OpVT); /// Create a bitwise NOT operation as (XOR Val, -1). - SDValue getNOT(SDLoc DL, SDValue Val, EVT VT); + SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT); /// \brief Create a logical NOT operation as (XOR Val, BooleanOne). - SDValue getLogicalNOT(SDLoc DL, SDValue Val, EVT VT); + SDValue getLogicalNOT(const SDLoc &DL, SDValue Val, EVT VT); /// Return a new CALLSEQ_START node, which always must have a glue result /// (to ensure it's not CSE'd). CALLSEQ_START does not have a useful SDLoc. - SDValue getCALLSEQ_START(SDValue Chain, SDValue Op, SDLoc DL) { + SDValue getCALLSEQ_START(SDValue Chain, SDValue Op, const SDLoc &DL) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Op }; return getNode(ISD::CALLSEQ_START, DL, VTs, Ops); @@ -645,7 +731,7 @@ public: /// glue result (to ensure it's not CSE'd). /// CALLSEQ_END does not have a useful SDLoc. SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, - SDValue InGlue, SDLoc DL) { + SDValue InGlue, const SDLoc &DL) { SDVTList NodeTys = getVTList(MVT::Other, MVT::Glue); SmallVector<SDValue, 4> Ops; Ops.push_back(Chain); @@ -668,38 +754,38 @@ public: /// Gets or creates the specified node. /// - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef<SDUse> Ops); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef<SDValue> Ops, const SDNodeFlags *Flags = nullptr); - SDValue getNode(unsigned Opcode, SDLoc DL, ArrayRef<EVT> ResultTys, + SDValue getNode(unsigned Opcode, const SDLoc &DL, ArrayRef<EVT> ResultTys, ArrayRef<SDValue> Ops); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, ArrayRef<SDValue> Ops); // Specialize based on number of operands. - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - const SDNodeFlags *Flags = nullptr); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3, SDValue N4); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3, SDValue N4, SDValue N5); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, const SDNodeFlags *Flags = nullptr); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3, SDValue N4); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3, SDValue N4, SDValue N5); // Specialize again based on number of operands for nodes with a VTList // rather than a single VT. - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs); + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N); + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3, SDValue N4); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3, SDValue N4, SDValue N5); /// Compute a TokenFactor to force all the incoming stack arguments to be @@ -707,24 +793,24 @@ public: /// stack arguments from being clobbered. SDValue getStackArgumentTokenFactor(SDValue Chain); - SDValue getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool AlwaysInline, bool isTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo); - SDValue getMemmove(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemmove(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool isTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo); - SDValue getMemset(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemset(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool isTailCall, MachinePointerInfo DstPtrInfo); /// Helper function to make it easier to build SetCC's if you just /// have an ISD::CondCode instead of an SDValue. /// - SDValue getSetCC(SDLoc DL, EVT VT, SDValue LHS, SDValue RHS, + SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond) { assert(LHS.getValueType().isVector() == RHS.getValueType().isVector() && "Cannot compare scalars to vectors"); @@ -737,8 +823,8 @@ public: /// Helper function to make it easier to build Select's if you just /// have operands and don't want to check for vector. - SDValue getSelect(SDLoc DL, EVT VT, SDValue Cond, - SDValue LHS, SDValue RHS) { + SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, + SDValue RHS) { assert(LHS.getValueType() == RHS.getValueType() && "Cannot use select on differing types"); assert(VT.isVector() == LHS.getValueType().isVector() && @@ -750,139 +836,145 @@ public: /// Helper function to make it easier to build SelectCC's if you /// just have an ISD::CondCode instead of an SDValue. /// - SDValue getSelectCC(SDLoc DL, SDValue LHS, SDValue RHS, - SDValue True, SDValue False, ISD::CondCode Cond) { + SDValue getSelectCC(const SDLoc &DL, SDValue LHS, SDValue RHS, SDValue True, + SDValue False, ISD::CondCode Cond) { return getNode(ISD::SELECT_CC, DL, True.getValueType(), LHS, RHS, True, False, getCondCode(Cond)); } /// VAArg produces a result and token chain, and takes a pointer /// and a source value as input. - SDValue getVAArg(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getVAArg(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue SV, unsigned Align); /// Gets a node for an atomic cmpxchg op. There are two /// valid Opcodes. ISD::ATOMIC_CMO_SWAP produces the value loaded and a /// chain result. ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS produces the value loaded, /// a success flag (initially i1), and a chain. - SDValue getAtomicCmpSwap(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTs, - SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, - MachinePointerInfo PtrInfo, unsigned Alignment, - AtomicOrdering SuccessOrdering, + SDValue getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTs, SDValue Chain, SDValue Ptr, + SDValue Cmp, SDValue Swp, MachinePointerInfo PtrInfo, + unsigned Alignment, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); - SDValue getAtomicCmpSwap(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTs, - SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, - MachineMemOperand *MMO, + SDValue getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTs, SDValue Chain, SDValue Ptr, + SDValue Cmp, SDValue Swp, MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result (if relevant) /// and chain and takes 2 operands. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDValue Chain, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Val, const Value *PtrVal, unsigned Alignment, AtomicOrdering Ordering, SynchronizationScope SynchScope); - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDValue Chain, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Val, MachineMemOperand *MMO, - AtomicOrdering Ordering, - SynchronizationScope SynchScope); + AtomicOrdering Ordering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result and chain and /// takes 1 operand. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, EVT VT, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, EVT VT, SDValue Chain, SDValue Ptr, MachineMemOperand *MMO, - AtomicOrdering Ordering, - SynchronizationScope SynchScope); + AtomicOrdering Ordering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result and chain and takes N /// operands. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTList, - ArrayRef<SDValue> Ops, MachineMemOperand *MMO, - AtomicOrdering SuccessOrdering, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTList, ArrayRef<SDValue> Ops, + MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTList, - ArrayRef<SDValue> Ops, MachineMemOperand *MMO, - AtomicOrdering Ordering, SynchronizationScope SynchScope); + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTList, ArrayRef<SDValue> Ops, + MachineMemOperand *MMO, AtomicOrdering Ordering, + SynchronizationScope SynchScope); /// Creates a MemIntrinsicNode that may produce a /// result and takes a list of operands. Opcode may be INTRINSIC_VOID, /// INTRINSIC_W_CHAIN, or a target-specific opcode with a value not /// less than FIRST_TARGET_MEMORY_OPCODE. - SDValue getMemIntrinsicNode(unsigned Opcode, SDLoc dl, SDVTList VTList, - ArrayRef<SDValue> Ops, - EVT MemVT, MachinePointerInfo PtrInfo, - unsigned Align = 0, bool Vol = false, - bool ReadMem = true, bool WriteMem = true, - unsigned Size = 0); + SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, + ArrayRef<SDValue> Ops, EVT MemVT, + MachinePointerInfo PtrInfo, unsigned Align = 0, + bool Vol = false, bool ReadMem = true, + bool WriteMem = true, unsigned Size = 0); - SDValue getMemIntrinsicNode(unsigned Opcode, SDLoc dl, SDVTList VTList, - ArrayRef<SDValue> Ops, - EVT MemVT, MachineMemOperand *MMO); + SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, + ArrayRef<SDValue> Ops, EVT MemVT, + MachineMemOperand *MMO); /// Create a MERGE_VALUES node from the given operands. - SDValue getMergeValues(ArrayRef<SDValue> Ops, SDLoc dl); + SDValue getMergeValues(ArrayRef<SDValue> Ops, const SDLoc &dl); /// Loads are not normal binary operators: their result type is not /// determined by their operands, and they produce a value AND a token chain. /// - SDValue getLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, - MachinePointerInfo PtrInfo, bool isVolatile, - bool isNonTemporal, bool isInvariant, unsigned Alignment, + /// This function will set the MOLoad flag on MMOFlags, but you can set it if + /// you want. The MOStore flag must not be set. + SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, + MachinePointerInfo PtrInfo, unsigned Alignment = 0, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); - SDValue getLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachineMemOperand *MMO); - SDValue getExtLoad(ISD::LoadExtType ExtType, SDLoc dl, EVT VT, - SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, - EVT MemVT, bool isVolatile, - bool isNonTemporal, bool isInvariant, unsigned Alignment, - const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getExtLoad(ISD::LoadExtType ExtType, SDLoc dl, EVT VT, + SDValue + getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, + SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, + unsigned Alignment = 0, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const AAMDNodes &AAInfo = AAMDNodes()); + SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, EVT MemVT, MachineMemOperand *MMO); - SDValue getIndexedLoad(SDValue OrigLoad, SDLoc dl, SDValue Base, + SDValue getIndexedLoad(SDValue OrigLoad, const SDLoc &dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM); - SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, - EVT VT, SDLoc dl, - SDValue Chain, SDValue Ptr, SDValue Offset, - MachinePointerInfo PtrInfo, EVT MemVT, - bool isVolatile, bool isNonTemporal, bool isInvariant, - unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes(), + SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, + MachinePointerInfo PtrInfo, EVT MemVT, unsigned Alignment = 0, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); - SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, - EVT VT, SDLoc dl, - SDValue Chain, SDValue Ptr, SDValue Offset, + SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, EVT MemVT, MachineMemOperand *MMO); /// Helper function to build ISD::STORE nodes. - SDValue getStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, - MachinePointerInfo PtrInfo, bool isVolatile, - bool isNonTemporal, unsigned Alignment, - const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, + /// + /// This function will set the MOStore flag on MMOFlags, but you can set it if + /// you want. The MOLoad and MOInvariant flags must not be set. + SDValue + getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, + MachinePointerInfo PtrInfo, unsigned Alignment = 0, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const AAMDNodes &AAInfo = AAMDNodes()); + SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachineMemOperand *MMO); - SDValue getTruncStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, - MachinePointerInfo PtrInfo, EVT TVT, - bool isNonTemporal, bool isVolatile, - unsigned Alignment, - const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getTruncStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, - EVT TVT, MachineMemOperand *MMO); - SDValue getIndexedStore(SDValue OrigStoe, SDLoc dl, SDValue Base, - SDValue Offset, ISD::MemIndexedMode AM); - - SDValue getMaskedLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue + getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, + MachinePointerInfo PtrInfo, EVT TVT, unsigned Alignment = 0, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const AAMDNodes &AAInfo = AAMDNodes()); + SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, + SDValue Ptr, EVT TVT, MachineMemOperand *MMO); + SDValue getIndexedStore(SDValue OrigStoe, const SDLoc &dl, SDValue Base, + SDValue Offset, ISD::MemIndexedMode AM); + + /// Returns sum of the base pointer and offset. + SDValue getMemBasePlusOffset(SDValue Base, unsigned Offset, const SDLoc &DL); + + SDValue getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Mask, SDValue Src0, EVT MemVT, MachineMemOperand *MMO, ISD::LoadExtType); - SDValue getMaskedStore(SDValue Chain, SDLoc dl, SDValue Val, + SDValue getMaskedStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, SDValue Mask, EVT MemVT, MachineMemOperand *MMO, bool IsTrunc); - SDValue getMaskedGather(SDVTList VTs, EVT VT, SDLoc dl, + SDValue getMaskedGather(SDVTList VTs, EVT VT, const SDLoc &dl, ArrayRef<SDValue> Ops, MachineMemOperand *MMO); - SDValue getMaskedScatter(SDVTList VTs, EVT VT, SDLoc dl, + SDValue getMaskedScatter(SDVTList VTs, EVT VT, const SDLoc &dl, ArrayRef<SDValue> Ops, MachineMemOperand *MMO); /// Construct a node to track a Value* through the backend. SDValue getSrcValue(const Value *v); @@ -895,8 +987,8 @@ public: SDValue getBitcast(EVT VT, SDValue V); /// Return an AddrSpaceCastSDNode. - SDValue getAddrSpaceCast(SDLoc dl, EVT VT, SDValue Ptr, - unsigned SrcAS, unsigned DestAS); + SDValue getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr, unsigned SrcAS, + unsigned DestAS); /// Return the specified value casted to /// the target's desired shift amount type. @@ -965,45 +1057,46 @@ public: /// Note that getMachineNode returns the resultant node. If there is already /// a node of the specified opcode and operands, it returns that node instead /// of the current one. - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, - SDValue Op1); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, - SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, - SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, - ArrayRef<SDValue> Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, ArrayRef<SDValue> Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, SDValue Op1, SDValue Op2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1, SDValue Op2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1, SDValue Op2, SDValue Op3); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, ArrayRef<SDValue> Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, SDValue Op1, SDValue Op2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, ArrayRef<SDValue> Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, EVT VT4, ArrayRef<SDValue> Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, - ArrayRef<EVT> ResultTys, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, ArrayRef<SDValue> Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, EVT VT4, ArrayRef<SDValue> Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, SDVTList VTs, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, + ArrayRef<EVT> ResultTys, ArrayRef<SDValue> Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, SDVTList VTs, ArrayRef<SDValue> Ops); /// A convenience function for creating TargetInstrInfo::EXTRACT_SUBREG nodes. - SDValue getTargetExtractSubreg(int SRIdx, SDLoc DL, EVT VT, + SDValue getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand); /// A convenience function for creating TargetInstrInfo::INSERT_SUBREG nodes. - SDValue getTargetInsertSubreg(int SRIdx, SDLoc DL, EVT VT, + SDValue getTargetInsertSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand, SDValue Subreg); /// Get the specified node if it's already available, or else return NULL. @@ -1012,16 +1105,17 @@ public: /// Creates a SDDbgValue node. SDDbgValue *getDbgValue(MDNode *Var, MDNode *Expr, SDNode *N, unsigned R, - bool IsIndirect, uint64_t Off, DebugLoc DL, + bool IsIndirect, uint64_t Off, const DebugLoc &DL, unsigned O); /// Constant SDDbgValue *getConstantDbgValue(MDNode *Var, MDNode *Expr, const Value *C, - uint64_t Off, DebugLoc DL, unsigned O); + uint64_t Off, const DebugLoc &DL, unsigned O); /// FrameIndex SDDbgValue *getFrameIndexDbgValue(MDNode *Var, MDNode *Expr, unsigned FI, - uint64_t Off, DebugLoc DL, unsigned O); + uint64_t Off, const DebugLoc &DL, + unsigned O); /// Remove the specified node from the system. If any of its /// operands then becomes dead, remove them as well. Inform UpdateListener @@ -1129,9 +1223,11 @@ public: return DbgInfo->getSDDbgValues(SD); } - /// Transfer SDDbgValues. +private: + /// Transfer SDDbgValues. Called via ReplaceAllUses{OfValue}?With void TransferDbgValues(SDValue From, SDValue To); +public: /// Return true if there are any SDDbgValue nodes associated /// with this SelectionDAG. bool hasDebugValues() const { return !DbgInfo->empty(); } @@ -1147,29 +1243,32 @@ public: void dump() const; - /// Create a stack temporary, suitable for holding the - /// specified value type. If minAlign is specified, the slot size will have - /// at least that alignment. + /// Create a stack temporary, suitable for holding the specified value type. + /// If minAlign is specified, the slot size will have at least that alignment. SDValue CreateStackTemporary(EVT VT, unsigned minAlign = 1); - /// Create a stack temporary suitable for holding - /// either of the specified value types. + /// Create a stack temporary suitable for holding either of the specified + /// value types. SDValue CreateStackTemporary(EVT VT1, EVT VT2); - SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT, + SDValue FoldSymbolOffset(unsigned Opcode, EVT VT, + const GlobalAddressSDNode *GA, + const SDNode *N2); + + SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, SDNode *Cst1, SDNode *Cst2); - SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT, + SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, const ConstantSDNode *Cst1, const ConstantSDNode *Cst2); - SDValue FoldConstantVectorArithmetic(unsigned Opcode, SDLoc DL, - EVT VT, ArrayRef<SDValue> Ops, + SDValue FoldConstantVectorArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, + ArrayRef<SDValue> Ops, const SDNodeFlags *Flags = nullptr); /// Constant fold a setcc to true or false. - SDValue FoldSetCC(EVT VT, SDValue N1, - SDValue N2, ISD::CondCode Cond, SDLoc dl); + SDValue FoldSetCC(EVT VT, SDValue N1, SDValue N2, ISD::CondCode Cond, + const SDLoc &dl); /// Return true if the sign bit of Op is known to be zero. /// We use this predicate to simplify operations downstream. @@ -1188,27 +1287,32 @@ public: void computeKnownBits(SDValue Op, APInt &KnownZero, APInt &KnownOne, unsigned Depth = 0) const; - /// Return the number of times the sign bit of the - /// register is replicated into the other bits. We know that at least 1 bit - /// is always equal to the sign bit (itself), but other cases can give us - /// information. For example, immediately after an "SRA X, 2", we know that - /// the top 3 bits are all equal to each other, so we return 3. Targets can - /// implement the ComputeNumSignBitsForTarget method in the TargetLowering - /// class to allow target nodes to be understood. + /// Test if the given value is known to have exactly one bit set. This differs + /// from computeKnownBits in that it doesn't necessarily determine which bit + /// is set. + bool isKnownToBeAPowerOfTwo(SDValue Val) const; + + /// Return the number of times the sign bit of the register is replicated into + /// the other bits. We know that at least 1 bit is always equal to the sign + /// bit (itself), but other cases can give us information. For example, + /// immediately after an "SRA X, 2", we know that the top 3 bits are all equal + /// to each other, so we return 3. Targets can implement the + /// ComputeNumSignBitsForTarget method in the TargetLowering class to allow + /// target nodes to be understood. unsigned ComputeNumSignBits(SDValue Op, unsigned Depth = 0) const; - /// Return true if the specified operand is an - /// ISD::ADD with a ConstantSDNode on the right-hand side, or if it is an - /// ISD::OR with a ConstantSDNode that is guaranteed to have the same - /// semantics as an ADD. This handles the equivalence: + /// Return true if the specified operand is an ISD::ADD with a ConstantSDNode + /// on the right-hand side, or if it is an ISD::OR with a ConstantSDNode that + /// is guaranteed to have the same semantics as an ADD. This handles the + /// equivalence: /// X|Cst == X+Cst iff X&Cst = 0. bool isBaseWithConstantOffset(SDValue Op) const; /// Test whether the given SDValue is known to never be NaN. bool isKnownNeverNaN(SDValue Op) const; - /// Test whether the given SDValue is known to never be - /// positive or negative Zero. + /// Test whether the given SDValue is known to never be positive or negative + /// zero. bool isKnownNeverZero(SDValue Op) const; /// Test whether two SDValues are known to compare equal. This @@ -1228,10 +1332,12 @@ public: /// vector op and fill the end of the resulting vector with UNDEFS. SDValue UnrollVectorOp(SDNode *N, unsigned ResNE = 0); - /// Return true if LD is loading 'Bytes' bytes from a location that is 'Dist' - /// units away from the location that the 'Base' load is loading from. - bool isConsecutiveLoad(LoadSDNode *LD, LoadSDNode *Base, - unsigned Bytes, int Dist) const; + /// Return true if loads are next to each other and can be + /// merged. Check that both are nonvolatile and if LD is loading + /// 'Bytes' bytes from a location that is 'Dist' units away from the + /// location that the 'Base' load is loading from. + bool areNonVolatileConsecutiveLoads(LoadSDNode *LD, LoadSDNode *Base, + unsigned Bytes, int Dist) const; /// Infer alignment of a load / store address. Return 0 if /// it cannot be inferred. @@ -1265,8 +1371,12 @@ public: void ExtractVectorElements(SDValue Op, SmallVectorImpl<SDValue> &Args, unsigned Start = 0, unsigned Count = 0); + /// Compute the default alignment value for the given type. unsigned getEVTAlignment(EVT MemoryVT) const; + /// Test whether the given value is a constant int or similar node. + SDNode *isConstantIntBuildVectorOrConstantInt(SDValue N); + private: void InsertNode(SDNode *N); bool RemoveNodeFromCSEMaps(SDNode *N); @@ -1276,16 +1386,16 @@ private: void *&InsertPos); SDNode *FindModifiedNodeSlot(SDNode *N, ArrayRef<SDValue> Ops, void *&InsertPos); - SDNode *UpdadeSDLocOnMergedSDNode(SDNode *N, SDLoc loc); + SDNode *UpdadeSDLocOnMergedSDNode(SDNode *N, const SDLoc &loc); void DeleteNodeNotInCSEMaps(SDNode *N); void DeallocateNode(SDNode *N); void allnodes_clear(); - BinarySDNode *GetBinarySDNode(unsigned Opcode, SDLoc DL, SDVTList VTs, - SDValue N1, SDValue N2, - const SDNodeFlags *Flags = nullptr); + SDNode *GetBinarySDNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, + SDValue N1, SDValue N2, + const SDNodeFlags *Flags = nullptr); /// Look up the node specified by ID in CSEMap. If it exists, return it. If /// not, return the insertion token that will make insertion faster. This @@ -1296,7 +1406,7 @@ private: /// Look up the node specified by ID in CSEMap. If it exists, return it. If /// not, return the insertion token that will make insertion faster. Performs /// additional processing for constant nodes. - SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, DebugLoc DL, + SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, const SDLoc &DL, void *&InsertPos); /// List of non-single value types. diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index a011e4c338c4..7f4549d3058f 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -76,8 +76,8 @@ public: /// right after selection. virtual void PostprocessISelDAG() {} - /// Select - Main hook targets implement to select a node. - virtual SDNode *Select(SDNode *N) = 0; + /// Main hook for targets to transform nodes into machine nodes. + virtual void Select(SDNode *N) = 0; /// SelectInlineAsmMemoryOperand - Select the specified address as a target /// addressing mode, according to the specified constraint. If this does @@ -111,6 +111,8 @@ public: OPC_RecordMemRef, OPC_CaptureGlueInput, OPC_MoveChild, + OPC_MoveChild0, OPC_MoveChild1, OPC_MoveChild2, OPC_MoveChild3, + OPC_MoveChild4, OPC_MoveChild5, OPC_MoveChild6, OPC_MoveChild7, OPC_MoveParent, OPC_CheckSame, OPC_CheckChild0Same, OPC_CheckChild1Same, @@ -140,11 +142,15 @@ public: OPC_EmitMergeInputChains, OPC_EmitMergeInputChains1_0, OPC_EmitMergeInputChains1_1, + OPC_EmitMergeInputChains1_2, OPC_EmitCopyToReg, OPC_EmitNodeXForm, OPC_EmitNode, + // Space-optimized forms that implicitly encode number of result VTs. + OPC_EmitNode0, OPC_EmitNode1, OPC_EmitNode2, OPC_MorphNodeTo, - OPC_MarkGlueResults, + // Space-optimized forms that implicitly encode number of result VTs. + OPC_MorphNodeTo0, OPC_MorphNodeTo1, OPC_MorphNodeTo2, OPC_CompleteMatch }; @@ -196,11 +202,16 @@ protected: CurDAG->ReplaceAllUsesWith(F, T); } + /// Replace all uses of \c F with \c T, then remove \c F from the DAG. + void ReplaceNode(SDNode *F, SDNode *T) { + CurDAG->ReplaceAllUsesWith(F, T); + CurDAG->RemoveDeadNode(F); + } /// SelectInlineAsmMemoryOperands - Calls to this are automatically generated /// by tblgen. Others should not call it. - void SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops, SDLoc DL); - + void SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops, + const SDLoc &DL); public: // Calls to these predicates are generated by tblgen. @@ -236,9 +247,8 @@ public: llvm_unreachable("Tblgen should generate this!"); } - SDNode *SelectCodeCommon(SDNode *NodeToMatch, - const unsigned char *MatcherTable, - unsigned TableSize); + void SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, + unsigned TableSize); /// \brief Return true if complex patterns for this target can mutate the /// DAG. @@ -249,10 +259,10 @@ public: private: // Calls to these functions are generated by tblgen. - SDNode *Select_INLINEASM(SDNode *N); - SDNode *Select_READ_REGISTER(SDNode *N); - SDNode *Select_WRITE_REGISTER(SDNode *N); - SDNode *Select_UNDEF(SDNode *N); + void Select_INLINEASM(SDNode *N); + void Select_READ_REGISTER(SDNode *N); + void Select_WRITE_REGISTER(SDNode *N); + void Select_UNDEF(SDNode *N); void CannotYetSelect(SDNode *N); private: @@ -294,11 +304,9 @@ private: /// state machines that start with a OPC_SwitchOpcode node. std::vector<unsigned> OpcodeOffset; - void UpdateChainsAndGlue(SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl<SDNode*> &ChainNodesMatched, - SDValue InputGlue, const SmallVectorImpl<SDNode*> &F, - bool isMorphNodeTo); - + void UpdateChains(SDNode *NodeToMatch, SDValue InputChain, + const SmallVectorImpl<SDNode *> &ChainNodesMatched, + bool isMorphNodeTo); }; } diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 536fc656e8e2..cfcc4117f93b 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -44,7 +44,7 @@ class GlobalValue; class MachineBasicBlock; class MachineConstantPoolValue; class SDNode; -class BinaryWithFlagsSDNode; +class HandleSDNode; class Value; class MCSymbol; template <typename T> struct DenseMapInfo; @@ -66,24 +66,28 @@ struct SDVTList { namespace ISD { /// Node predicates - /// Return true if the specified node is a - /// BUILD_VECTOR where all of the elements are ~0 or undef. + /// If N is a BUILD_VECTOR node whose elements are all the same constant or + /// undefined, return true and return the constant value in \p SplatValue. + bool isConstantSplatVector(const SDNode *N, APInt &SplatValue); + + /// Return true if the specified node is a BUILD_VECTOR where all of the + /// elements are ~0 or undef. bool isBuildVectorAllOnes(const SDNode *N); - /// Return true if the specified node is a - /// BUILD_VECTOR where all of the elements are 0 or undef. + /// Return true if the specified node is a BUILD_VECTOR where all of the + /// elements are 0 or undef. bool isBuildVectorAllZeros(const SDNode *N); - /// \brief Return true if the specified node is a BUILD_VECTOR node of - /// all ConstantSDNode or undef. + /// Return true if the specified node is a BUILD_VECTOR node of all + /// ConstantSDNode or undef. bool isBuildVectorOfConstantSDNodes(const SDNode *N); - /// \brief Return true if the specified node is a BUILD_VECTOR node of - /// all ConstantFPSDNode or undef. + /// Return true if the specified node is a BUILD_VECTOR node of all + /// ConstantFPSDNode or undef. bool isBuildVectorOfConstantFPSDNodes(const SDNode *N); - /// Return true if the node has at least one operand - /// and all operands of the specified node are ISD::UNDEF. + /// Return true if the node has at least one operand and all operands of the + /// specified node are ISD::UNDEF. bool allOperandsUndef(const SDNode *N); } // end llvm:ISD namespace @@ -280,6 +284,8 @@ public: private: friend class SelectionDAG; friend class SDNode; + // TODO: unfriend HandleSDNode once we fix its operand handling. + friend class HandleSDNode; void setUser(SDNode *p) { User = p; } @@ -328,6 +334,7 @@ private: bool NoInfs : 1; bool NoSignedZeros : 1; bool AllowReciprocal : 1; + bool VectorReduction : 1; public: /// Default constructor turns off all optimization flags. @@ -340,6 +347,7 @@ public: NoInfs = false; NoSignedZeros = false; AllowReciprocal = false; + VectorReduction = false; } // These are mutators for each flag. @@ -351,6 +359,7 @@ public: void setNoInfs(bool b) { NoInfs = b; } void setNoSignedZeros(bool b) { NoSignedZeros = b; } void setAllowReciprocal(bool b) { AllowReciprocal = b; } + void setVectorReduction(bool b) { VectorReduction = b; } // These are accessors for each flag. bool hasNoUnsignedWrap() const { return NoUnsignedWrap; } @@ -361,6 +370,7 @@ public: bool hasNoInfs() const { return NoInfs; } bool hasNoSignedZeros() const { return NoSignedZeros; } bool hasAllowReciprocal() const { return AllowReciprocal; } + bool hasVectorReduction() const { return VectorReduction; } /// Return a raw encoding of the flags. /// This function should only be used to add data to the NodeID value. @@ -390,10 +400,6 @@ private: /// The operation that this node performs. int16_t NodeType; - /// This is true if OperandList was new[]'d. If true, - /// then they will be delete[]'d when the node is destroyed. - uint16_t OperandsNeedDelete : 1; - /// This tracks whether this node has one or more dbg_value /// nodes corresponding to it. uint16_t HasDebugValue : 1; @@ -402,7 +408,7 @@ protected: /// This member is defined by this class, but is not used for /// anything. Subclasses can use it to hold whatever state they find useful. /// This field is initialized to zero by the ctor. - uint16_t SubclassData : 14; + uint16_t SubclassData : 15; private: /// Unique id per SDNode in the DAG. @@ -436,6 +442,8 @@ private: friend class SelectionDAG; friend struct ilist_traits<SDNode>; + // TODO: unfriend HandleSDNode once we fix its operand handling. + friend class HandleSDNode; public: /// Unique and persistent id per SDNode in the DAG. @@ -621,18 +629,32 @@ public: /// NOTE: This is an expensive method. Use it carefully. bool hasPredecessor(const SDNode *N) const; - /// Return true if N is a predecessor of this node. - /// N is either an operand of this node, or can be reached by recursively - /// traversing up the operands. - /// In this helper the Visited and worklist sets are held externally to - /// cache predecessors over multiple invocations. If you want to test for - /// multiple predecessors this method is preferable to multiple calls to - /// hasPredecessor. Be sure to clear Visited and Worklist if the DAG - /// changes. - /// NOTE: This is still very expensive. Use carefully. - bool hasPredecessorHelper(const SDNode *N, - SmallPtrSetImpl<const SDNode *> &Visited, - SmallVectorImpl<const SDNode *> &Worklist) const; + /// Returns true if N is a predecessor of any node in Worklist. This + /// helper keeps Visited and Worklist sets externally to allow unions + /// searches to be performed in parallel, caching of results across + /// queries and incremental addition to Worklist. Stops early if N is + /// found but will resume. Remember to clear Visited and Worklists + /// if DAG changes. + static bool hasPredecessorHelper(const SDNode *N, + SmallPtrSetImpl<const SDNode *> &Visited, + SmallVectorImpl<const SDNode *> &Worklist) { + if (Visited.count(N)) + return true; + while (!Worklist.empty()) { + const SDNode *M = Worklist.pop_back_val(); + bool Found = false; + for (const SDValue &OpV : M->op_values()) { + SDNode *Op = OpV.getNode(); + if (Visited.insert(Op).second) + Worklist.push_back(Op); + if (Op == N) + Found = true; + } + if (Found) + return true; + } + return false; + } /// Return the number of values used by this operation. unsigned getNumOperands() const { return NumOperands; } @@ -788,101 +810,20 @@ protected: return Ret; } - SDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - ArrayRef<SDValue> Ops) - : NodeType(Opc), OperandsNeedDelete(true), HasDebugValue(false), - SubclassData(0), NodeId(-1), - OperandList(Ops.size() ? new SDUse[Ops.size()] : nullptr), - ValueList(VTs.VTs), UseList(nullptr), NumOperands(Ops.size()), - NumValues(VTs.NumVTs), IROrder(Order), debugLoc(std::move(dl)) { - assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); - assert(NumOperands == Ops.size() && - "NumOperands wasn't wide enough for its operands!"); - assert(NumValues == VTs.NumVTs && - "NumValues wasn't wide enough for its operands!"); - for (unsigned i = 0; i != Ops.size(); ++i) { - assert(OperandList && "no operands available"); - OperandList[i].setUser(this); - OperandList[i].setInitial(Ops[i]); - } - checkForCycles(this); - } - - /// This constructor adds no operands itself; operands can be - /// set later with InitOperands. + /// Create an SDNode. + /// + /// SDNodes are created without any operands, and never own the operand + /// storage. To add operands, see SelectionDAG::createOperands. SDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs) - : NodeType(Opc), OperandsNeedDelete(false), HasDebugValue(false), - SubclassData(0), NodeId(-1), OperandList(nullptr), ValueList(VTs.VTs), - UseList(nullptr), NumOperands(0), NumValues(VTs.NumVTs), - IROrder(Order), debugLoc(std::move(dl)) { + : NodeType(Opc), HasDebugValue(false), SubclassData(0), NodeId(-1), + OperandList(nullptr), ValueList(VTs.VTs), UseList(nullptr), + NumOperands(0), NumValues(VTs.NumVTs), IROrder(Order), + debugLoc(std::move(dl)) { assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); assert(NumValues == VTs.NumVTs && "NumValues wasn't wide enough for its operands!"); } - /// Initialize the operands list of this with 1 operand. - void InitOperands(SDUse *Ops, const SDValue &Op0) { - Ops[0].setUser(this); - Ops[0].setInitial(Op0); - NumOperands = 1; - OperandList = Ops; - checkForCycles(this); - } - - /// Initialize the operands list of this with 2 operands. - void InitOperands(SDUse *Ops, const SDValue &Op0, const SDValue &Op1) { - Ops[0].setUser(this); - Ops[0].setInitial(Op0); - Ops[1].setUser(this); - Ops[1].setInitial(Op1); - NumOperands = 2; - OperandList = Ops; - checkForCycles(this); - } - - /// Initialize the operands list of this with 3 operands. - void InitOperands(SDUse *Ops, const SDValue &Op0, const SDValue &Op1, - const SDValue &Op2) { - Ops[0].setUser(this); - Ops[0].setInitial(Op0); - Ops[1].setUser(this); - Ops[1].setInitial(Op1); - Ops[2].setUser(this); - Ops[2].setInitial(Op2); - NumOperands = 3; - OperandList = Ops; - checkForCycles(this); - } - - /// Initialize the operands list of this with 4 operands. - void InitOperands(SDUse *Ops, const SDValue &Op0, const SDValue &Op1, - const SDValue &Op2, const SDValue &Op3) { - Ops[0].setUser(this); - Ops[0].setInitial(Op0); - Ops[1].setUser(this); - Ops[1].setInitial(Op1); - Ops[2].setUser(this); - Ops[2].setInitial(Op2); - Ops[3].setUser(this); - Ops[3].setInitial(Op3); - NumOperands = 4; - OperandList = Ops; - checkForCycles(this); - } - - /// Initialize the operands list of this with N operands. - void InitOperands(SDUse *Ops, const SDValue *Vals, unsigned N) { - for (unsigned i = 0; i != N; ++i) { - Ops[i].setUser(this); - Ops[i].setInitial(Vals[i]); - } - NumOperands = N; - assert(NumOperands == N && - "NumOperands wasn't wide enough for its operands!"); - OperandList = Ops; - checkForCycles(this); - } - /// Release the operands and set this node to have zero operands. void DropOperands(); }; @@ -898,40 +839,20 @@ protected: /// be used by the DAGBuilder, the other to be used by others. class SDLoc { private: - // Ptr could be used for either Instruction* or SDNode*. It is used for - // Instruction* if IROrder is not -1. - const void *Ptr; - int IROrder; + DebugLoc DL; + int IROrder = 0; public: - SDLoc() : Ptr(nullptr), IROrder(0) {} - SDLoc(const SDNode *N) : Ptr(N), IROrder(-1) { - assert(N && "null SDNode"); - } - SDLoc(const SDValue V) : Ptr(V.getNode()), IROrder(-1) { - assert(Ptr && "null SDNode"); - } - SDLoc(const Instruction *I, int Order) : Ptr(I), IROrder(Order) { + SDLoc() = default; + SDLoc(const SDNode *N) : DL(N->getDebugLoc()), IROrder(N->getIROrder()) {} + SDLoc(const SDValue V) : SDLoc(V.getNode()) {} + SDLoc(const Instruction *I, int Order) : IROrder(Order) { assert(Order >= 0 && "bad IROrder"); + if (I) + DL = I->getDebugLoc(); } - unsigned getIROrder() { - if (IROrder >= 0 || Ptr == nullptr) { - return (unsigned)IROrder; - } - const SDNode *N = (const SDNode*)(Ptr); - return N->getIROrder(); - } - DebugLoc getDebugLoc() { - if (!Ptr) { - return DebugLoc(); - } - if (IROrder >= 0) { - const Instruction *I = (const Instruction*)(Ptr); - return I->getDebugLoc(); - } - const SDNode *N = (const SDNode*)(Ptr); - return N->getDebugLoc(); - } + unsigned getIROrder() const { return IROrder; } + const DebugLoc &getDebugLoc() const { return DL; } }; @@ -1008,30 +929,6 @@ inline void SDUse::setNode(SDNode *N) { if (N) N->addUse(*this); } -/// This class is used for single-operand SDNodes. This is solely -/// to allow co-allocation of node operands with the node itself. -class UnarySDNode : public SDNode { - SDUse Op; -public: - UnarySDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - SDValue X) - : SDNode(Opc, Order, dl, VTs) { - InitOperands(&Op, X); - } -}; - -/// This class is used for two-operand SDNodes. This is solely -/// to allow co-allocation of node operands with the node itself. -class BinarySDNode : public SDNode { - SDUse Ops[2]; -public: - BinarySDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - SDValue X, SDValue Y) - : SDNode(Opc, Order, dl, VTs) { - InitOperands(Ops, X, Y); - } -}; - /// Returns true if the opcode is a binary operation with flags. static bool isBinOpWithFlags(unsigned Opcode) { switch (Opcode) { @@ -1056,30 +953,17 @@ static bool isBinOpWithFlags(unsigned Opcode) { /// This class is an extension of BinarySDNode /// used from those opcodes that have associated extra flags. -class BinaryWithFlagsSDNode : public BinarySDNode { +class BinaryWithFlagsSDNode : public SDNode { public: SDNodeFlags Flags; - BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - SDValue X, SDValue Y, const SDNodeFlags &NodeFlags) - : BinarySDNode(Opc, Order, dl, VTs, X, Y), Flags(NodeFlags) {} + BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, + SDVTList VTs, const SDNodeFlags &NodeFlags) + : SDNode(Opc, Order, dl, VTs), Flags(NodeFlags) {} static bool classof(const SDNode *N) { return isBinOpWithFlags(N->getOpcode()); } }; -/// This class is used for three-operand SDNodes. This is solely -/// to allow co-allocation of node operands with the node itself. -class TernarySDNode : public SDNode { - SDUse Ops[3]; -public: - TernarySDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - SDValue X, SDValue Y, SDValue Z) - : SDNode(Opc, Order, dl, VTs) { - InitOperands(Ops, X, Y, Z); - } -}; - - /// This class is used to form a handle around another node that /// is persistent and is updated across invocations of replaceAllUsesWith on its /// operand. This node should be directly created by end-users and not added to @@ -1092,19 +976,27 @@ public: // HandleSDNodes are never inserted into the DAG, so they won't be // auto-numbered. Use ID 65535 as a sentinel. PersistentId = 0xffff; - InitOperands(&Op, X); + + // Manually set up the operand list. This node type is special in that it's + // always stack allocated and SelectionDAG does not manage its operands. + // TODO: This should either (a) not be in the SDNode hierarchy, or (b) not + // be so special. + Op.setUser(this); + Op.setInitial(X); + NumOperands = 1; + OperandList = &Op; } ~HandleSDNode(); const SDValue &getValue() const { return Op; } }; -class AddrSpaceCastSDNode : public UnarySDNode { +class AddrSpaceCastSDNode : public SDNode { private: unsigned SrcAddrSpace; unsigned DestAddrSpace; public: - AddrSpaceCastSDNode(unsigned Order, DebugLoc dl, EVT VT, SDValue X, + AddrSpaceCastSDNode(unsigned Order, const DebugLoc &dl, EVT VT, unsigned SrcAS, unsigned DestAS); unsigned getSrcAddressSpace() const { return SrcAddrSpace; } @@ -1126,12 +1018,9 @@ protected: MachineMemOperand *MMO; public: - MemSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, + MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO); - MemSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - ArrayRef<SDValue> Ops, EVT MemoryVT, MachineMemOperand *MMO); - bool readMem() const { return MMO->isLoad(); } bool writeMem() const { return MMO->isStore(); } @@ -1234,8 +1123,6 @@ public: /// This is an SDNode representing atomic operations. class AtomicSDNode : public MemSDNode { - SDUse Ops[4]; - /// For cmpxchg instructions, the ordering requirements when a store does not /// occur. AtomicOrdering FailureOrdering; @@ -1244,13 +1131,15 @@ class AtomicSDNode : public MemSDNode { AtomicOrdering FailureOrdering, SynchronizationScope SynchScope) { // This must match encodeMemSDNodeFlags() in SelectionDAG.cpp. - assert((SuccessOrdering & 15) == SuccessOrdering && + assert((AtomicOrdering)((unsigned)SuccessOrdering & 15) == + SuccessOrdering && "Ordering may not require more than 4 bits!"); - assert((FailureOrdering & 15) == FailureOrdering && + assert((AtomicOrdering)((unsigned)FailureOrdering & 15) == + FailureOrdering && "Ordering may not require more than 4 bits!"); assert((SynchScope & 1) == SynchScope && "SynchScope may not require more than 1 bit!"); - SubclassData |= SuccessOrdering << 8; + SubclassData |= (unsigned)SuccessOrdering << 8; SubclassData |= SynchScope << 12; this->FailureOrdering = FailureOrdering; assert(getSuccessOrdering() == SuccessOrdering && @@ -1261,50 +1150,12 @@ class AtomicSDNode : public MemSDNode { } public: - // Opc: opcode for atomic - // VTL: value type list - // Chain: memory chain for operaand - // Ptr: address to update as a SDValue - // Cmp: compare value - // Swp: swap value - // SrcVal: address to update as a Value (used for MemOperand) - // Align: alignment of memory - AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, - EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, - MachineMemOperand *MMO, AtomicOrdering Ordering, - SynchronizationScope SynchScope) - : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { - InitAtomic(Ordering, Ordering, SynchScope); - InitOperands(Ops, Chain, Ptr, Cmp, Swp); - } - AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, - EVT MemVT, - SDValue Chain, SDValue Ptr, - SDValue Val, MachineMemOperand *MMO, - AtomicOrdering Ordering, SynchronizationScope SynchScope) - : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { - InitAtomic(Ordering, Ordering, SynchScope); - InitOperands(Ops, Chain, Ptr, Val); - } - AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, - EVT MemVT, - SDValue Chain, SDValue Ptr, - MachineMemOperand *MMO, - AtomicOrdering Ordering, SynchronizationScope SynchScope) - : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { - InitAtomic(Ordering, Ordering, SynchScope); - InitOperands(Ops, Chain, Ptr); - } - AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, EVT MemVT, - const SDValue* AllOps, SDUse *DynOps, unsigned NumOps, - MachineMemOperand *MMO, + AtomicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTL, + EVT MemVT, MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope) - : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { + : MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) { InitAtomic(SuccessOrdering, FailureOrdering, SynchScope); - assert((DynOps || NumOps <= array_lengthof(Ops)) && - "Too many ops for internal storage!"); - InitOperands(DynOps ? DynOps : Ops, AllOps, NumOps); } const SDValue &getBasePtr() const { return getOperand(1); } @@ -1351,10 +1202,9 @@ public: /// with a value not less than FIRST_TARGET_MEMORY_OPCODE. class MemIntrinsicSDNode : public MemSDNode { public: - MemIntrinsicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - ArrayRef<SDValue> Ops, EVT MemoryVT, - MachineMemOperand *MMO) - : MemSDNode(Opc, Order, dl, VTs, Ops, MemoryVT, MMO) { + MemIntrinsicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, + SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO) + : MemSDNode(Opc, Order, dl, VTs, MemoryVT, MMO) { SubclassData |= 1u << 13; } @@ -1377,20 +1227,15 @@ public: /// An index of -1 is treated as undef, such that the code generator may put /// any value in the corresponding element of the result. class ShuffleVectorSDNode : public SDNode { - SDUse Ops[2]; - // The memory for Mask is owned by the SelectionDAG's OperandAllocator, and // is freed when the SelectionDAG object is destroyed. const int *Mask; protected: friend class SelectionDAG; - ShuffleVectorSDNode(EVT VT, unsigned Order, DebugLoc dl, SDValue N1, - SDValue N2, const int *M) - : SDNode(ISD::VECTOR_SHUFFLE, Order, dl, getSDVTList(VT)), Mask(M) { - InitOperands(Ops, N1, N2); - } -public: + ShuffleVectorSDNode(EVT VT, unsigned Order, const DebugLoc &dl, const int *M) + : SDNode(ISD::VECTOR_SHUFFLE, Order, dl, getSDVTList(VT)), Mask(M) {} +public: ArrayRef<int> getMask() const { EVT VT = getValueType(0); return makeArrayRef(Mask, VT.getVectorNumElements()); @@ -1414,7 +1259,7 @@ public: /// Change values in a shuffle permute mask assuming /// the two vector operands have swapped position. - static void commuteMask(SmallVectorImpl<int> &Mask) { + static void commuteMask(MutableArrayRef<int> Mask) { unsigned NumElems = Mask.size(); for (unsigned i = 0; i != NumElems; ++i) { int idx = Mask[i]; @@ -1436,9 +1281,10 @@ class ConstantSDNode : public SDNode { const ConstantInt *Value; friend class SelectionDAG; ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val, - DebugLoc DL, EVT VT) - : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, - 0, DL, getSDVTList(VT)), Value(val) { + const DebugLoc &DL, EVT VT) + : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DL, + getSDVTList(VT)), + Value(val) { SubclassData |= (uint16_t)isOpaque; } public: @@ -1463,10 +1309,12 @@ public: class ConstantFPSDNode : public SDNode { const ConstantFP *Value; friend class SelectionDAG; - ConstantFPSDNode(bool isTarget, const ConstantFP *val, DebugLoc DL, EVT VT) - : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, - 0, DL, getSDVTList(VT)), Value(val) { - } + ConstantFPSDNode(bool isTarget, const ConstantFP *val, const DebugLoc &DL, + EVT VT) + : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, 0, DL, + getSDVTList(VT)), + Value(val) {} + public: const APFloat& getValueAPF() const { return Value->getValueAPF(); } @@ -1517,15 +1365,19 @@ bool isNullFPConstant(SDValue V); bool isAllOnesConstant(SDValue V); /// Returns true if \p V is a constant integer one. bool isOneConstant(SDValue V); +/// Returns true if \p V is a bitwise not operation. Assumes that an all ones +/// constant is canonicalized to be operand 1. +bool isBitwiseNot(SDValue V); class GlobalAddressSDNode : public SDNode { const GlobalValue *TheGlobal; int64_t Offset; unsigned char TargetFlags; friend class SelectionDAG; - GlobalAddressSDNode(unsigned Opc, unsigned Order, DebugLoc DL, + GlobalAddressSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, const GlobalValue *GA, EVT VT, int64_t o, unsigned char TargetFlags); + public: const GlobalValue *getGlobal() const { return TheGlobal; } @@ -1821,13 +1673,11 @@ public: }; class EHLabelSDNode : public SDNode { - SDUse Chain; MCSymbol *Label; friend class SelectionDAG; - EHLabelSDNode(unsigned Order, DebugLoc dl, SDValue ch, MCSymbol *L) - : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) { - InitOperands(&Chain, ch); - } + EHLabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) + : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) {} + public: MCSymbol *getLabel() const { return Label; } @@ -1892,12 +1742,11 @@ public: class CvtRndSatSDNode : public SDNode { ISD::CvtCode CvtCode; friend class SelectionDAG; - explicit CvtRndSatSDNode(EVT VT, unsigned Order, DebugLoc dl, - ArrayRef<SDValue> Ops, ISD::CvtCode Code) - : SDNode(ISD::CONVERT_RNDSAT, Order, dl, getSDVTList(VT), Ops), - CvtCode(Code) { - assert(Ops.size() == 5 && "wrong number of operations"); + explicit CvtRndSatSDNode(EVT VT, unsigned Order, const DebugLoc &dl, + ISD::CvtCode Code) + : SDNode(ISD::CONVERT_RNDSAT, Order, dl, getSDVTList(VT)), CvtCode(Code) { } + public: ISD::CvtCode getCvtCode() const { return CvtCode; } @@ -1926,24 +1775,13 @@ public: /// Base class for LoadSDNode and StoreSDNode class LSBaseSDNode : public MemSDNode { - //! Operand array for load and store - /*! - \note Moving this array to the base class captures more - common functionality shared between LoadSDNode and - StoreSDNode - */ - SDUse Ops[4]; public: - LSBaseSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, - SDValue *Operands, unsigned numOperands, + LSBaseSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::MemIndexedMode AM, EVT MemVT, MachineMemOperand *MMO) - : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { + : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { SubclassData |= AM << 2; assert(getAddressingMode() == AM && "MemIndexedMode encoding error!"); - InitOperands(Ops, Operands, numOperands); - assert((getOffset().getOpcode() == ISD::UNDEF || isIndexed()) && - "Only indexed loads and stores have a non-undef offset operand"); } const SDValue &getOffset() const { @@ -1971,10 +1809,10 @@ public: /// This class is used to represent ISD::LOAD nodes. class LoadSDNode : public LSBaseSDNode { friend class SelectionDAG; - LoadSDNode(SDValue *ChainPtrOff, unsigned Order, DebugLoc dl, SDVTList VTs, + LoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::MemIndexedMode AM, ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) - : LSBaseSDNode(ISD::LOAD, Order, dl, ChainPtrOff, 3, VTs, AM, MemVT, MMO) { + : LSBaseSDNode(ISD::LOAD, Order, dl, VTs, AM, MemVT, MMO) { SubclassData |= (unsigned short)ETy; assert(getExtensionType() == ETy && "LoadExtType encoding error!"); assert(readMem() && "Load MachineMemOperand is not a load!"); @@ -1999,11 +1837,10 @@ public: /// This class is used to represent ISD::STORE nodes. class StoreSDNode : public LSBaseSDNode { friend class SelectionDAG; - StoreSDNode(SDValue *ChainValuePtrOff, unsigned Order, DebugLoc dl, - SDVTList VTs, ISD::MemIndexedMode AM, bool isTrunc, EVT MemVT, + StoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + ISD::MemIndexedMode AM, bool isTrunc, EVT MemVT, MachineMemOperand *MMO) - : LSBaseSDNode(ISD::STORE, Order, dl, ChainValuePtrOff, 4, - VTs, AM, MemVT, MMO) { + : LSBaseSDNode(ISD::STORE, Order, dl, VTs, AM, MemVT, MMO) { SubclassData |= (unsigned short)isTrunc; assert(isTruncatingStore() == isTrunc && "isTrunc encoding error!"); assert(!readMem() && "Store MachineMemOperand is a load!"); @@ -2027,16 +1864,12 @@ public: /// This base class is used to represent MLOAD and MSTORE nodes class MaskedLoadStoreSDNode : public MemSDNode { - // Operands - SDUse Ops[4]; public: friend class SelectionDAG; - MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, - SDValue *Operands, unsigned numOperands, SDVTList VTs, - EVT MemVT, MachineMemOperand *MMO) - : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { - InitOperands(Ops, Operands, numOperands); - } + MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, + const DebugLoc &dl, SDVTList VTs, EVT MemVT, + MachineMemOperand *MMO) + : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {} // In the both nodes address is Op1, mask is Op2: // MaskedLoadSDNode (Chain, ptr, mask, src0), src0 is a passthru value @@ -2055,11 +1888,9 @@ public: class MaskedLoadSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; - MaskedLoadSDNode(unsigned Order, DebugLoc dl, SDValue *Operands, - unsigned numOperands, SDVTList VTs, ISD::LoadExtType ETy, - EVT MemVT, MachineMemOperand *MMO) - : MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, Operands, numOperands, - VTs, MemVT, MMO) { + MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) + : MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, MemVT, MMO) { SubclassData |= (unsigned short)ETy; } @@ -2077,12 +1908,10 @@ class MaskedStoreSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; - MaskedStoreSDNode(unsigned Order, DebugLoc dl, SDValue *Operands, - unsigned numOperands, SDVTList VTs, bool isTrunc, EVT MemVT, - MachineMemOperand *MMO) - : MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, Operands, numOperands, - VTs, MemVT, MMO) { - SubclassData |= (unsigned short)isTrunc; + MaskedStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + bool isTrunc, EVT MemVT, MachineMemOperand *MMO) + : MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, MemVT, MMO) { + SubclassData |= (unsigned short)isTrunc; } /// Return true if the op does a truncation before store. /// For integers this is the same as doing a TRUNCATE and storing the result. @@ -2100,17 +1929,12 @@ public: /// MGATHER and MSCATTER nodes /// class MaskedGatherScatterSDNode : public MemSDNode { - // Operands - SDUse Ops[5]; public: friend class SelectionDAG; - MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, - ArrayRef<SDValue> Operands, SDVTList VTs, EVT MemVT, + MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, + const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) - : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { - assert(Operands.size() == 5 && "Incompatible number of operands"); - InitOperands(Ops, Operands.data(), Operands.size()); - } + : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {} // In the both nodes address is Op1, mask is Op2: // MaskedGatherSDNode (Chain, src0, mask, base, index), src0 is a passthru value @@ -2132,19 +1956,9 @@ public: class MaskedGatherSDNode : public MaskedGatherScatterSDNode { public: friend class SelectionDAG; - MaskedGatherSDNode(unsigned Order, DebugLoc dl, ArrayRef<SDValue> Operands, - SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) - : MaskedGatherScatterSDNode(ISD::MGATHER, Order, dl, Operands, VTs, MemVT, - MMO) { - assert(getValue().getValueType() == getValueType(0) && - "Incompatible type of the PassThru value in MaskedGatherSDNode"); - assert(getMask().getValueType().getVectorNumElements() == - getValueType(0).getVectorNumElements() && - "Vector width mismatch between mask and data"); - assert(getIndex().getValueType().getVectorNumElements() == - getValueType(0).getVectorNumElements() && - "Vector width mismatch between index and data"); - } + MaskedGatherSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + EVT MemVT, MachineMemOperand *MMO) + : MaskedGatherScatterSDNode(ISD::MGATHER, Order, dl, VTs, MemVT, MMO) {} static bool classof(const SDNode *N) { return N->getOpcode() == ISD::MGATHER; @@ -2157,17 +1971,9 @@ class MaskedScatterSDNode : public MaskedGatherScatterSDNode { public: friend class SelectionDAG; - MaskedScatterSDNode(unsigned Order, DebugLoc dl,ArrayRef<SDValue> Operands, - SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) - : MaskedGatherScatterSDNode(ISD::MSCATTER, Order, dl, Operands, VTs, MemVT, - MMO) { - assert(getMask().getValueType().getVectorNumElements() == - getValue().getValueType().getVectorNumElements() && - "Vector width mismatch between mask and data"); - assert(getIndex().getValueType().getVectorNumElements() == - getValue().getValueType().getVectorNumElements() && - "Vector width mismatch between index and data"); - } + MaskedScatterSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + EVT MemVT, MachineMemOperand *MMO) + : MaskedGatherScatterSDNode(ISD::MSCATTER, Order, dl, VTs, MemVT, MMO) {} static bool classof(const SDNode *N) { return N->getOpcode() == ISD::MSCATTER; @@ -2183,12 +1989,8 @@ public: private: friend class SelectionDAG; - MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc DL, SDVTList VTs) - : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} - - /// Operands for this instruction, if they fit here. If - /// they don't, this field is unused. - SDUse LocalOperands[4]; + MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, SDVTList VTs) + : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} /// Memory reference descriptions for this instruction. mmo_iterator MemRefs; @@ -2264,8 +2066,13 @@ template <> struct GraphTraits<SDNode*> { } }; -/// The largest SDNode class. -typedef MaskedGatherScatterSDNode LargestSDNode; +/// A representation of the largest SDNode, for use in sizeof(). +/// +/// This needs to be a union because the largest node differs on 32 bit systems +/// with 4 and 8 byte pointer alignment, respectively. +typedef AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode, + BlockAddressSDNode, GlobalAddressSDNode> + LargestSDNode; /// The SDNode class with the greatest alignment requirement. typedef GlobalAddressSDNode MostAlignedSDNode; diff --git a/include/llvm/Target/TargetSelectionDAGInfo.h b/include/llvm/CodeGen/SelectionDAGTargetInfo.h index a7143ac3fa66..ac5092af8def 100644 --- a/include/llvm/Target/TargetSelectionDAGInfo.h +++ b/include/llvm/CodeGen/SelectionDAGTargetInfo.h @@ -1,4 +1,4 @@ -//==-- llvm/Target/TargetSelectionDAGInfo.h - SelectionDAG Info --*- C++ -*-==// +//==-- llvm/CodeGen/SelectionDAGTargetInfo.h - SelectionDAG Info -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -7,16 +7,17 @@ // //===----------------------------------------------------------------------===// // -// This file declares the TargetSelectionDAGInfo class, which targets can +// This file declares the SelectionDAGTargetInfo class, which targets can // subclass to parameterize the SelectionDAG lowering and instruction // selection process. // //===----------------------------------------------------------------------===// -#ifndef LLVM_TARGET_TARGETSELECTIONDAGINFO_H -#define LLVM_TARGET_TARGETSELECTIONDAGINFO_H +#ifndef LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H +#define LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/Support/CodeGen.h" namespace llvm { @@ -24,13 +25,13 @@ namespace llvm { /// Targets can subclass this to parameterize the /// SelectionDAG lowering and instruction selection process. /// -class TargetSelectionDAGInfo { - TargetSelectionDAGInfo(const TargetSelectionDAGInfo &) = delete; - void operator=(const TargetSelectionDAGInfo &) = delete; +class SelectionDAGTargetInfo { + SelectionDAGTargetInfo(const SelectionDAGTargetInfo &) = delete; + void operator=(const SelectionDAGTargetInfo &) = delete; public: - explicit TargetSelectionDAGInfo() = default; - virtual ~TargetSelectionDAGInfo(); + explicit SelectionDAGTargetInfo() = default; + virtual ~SelectionDAGTargetInfo(); /// Emit target-specific code that performs a memcpy. /// This can be used by targets to provide code sequences for cases @@ -45,14 +46,13 @@ public: /// expanded in a place where calls are not feasible (e.g. within the prologue /// for another call). If the target chooses to decline an AlwaysInline /// request here, legalize will resort to using simple loads and stores. - virtual SDValue - EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, - SDValue Chain, - SDValue Op1, SDValue Op2, - SDValue Op3, unsigned Align, bool isVolatile, - bool AlwaysInline, - MachinePointerInfo DstPtrInfo, - MachinePointerInfo SrcPtrInfo) const { + virtual SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, const SDLoc &dl, + SDValue Chain, SDValue Op1, + SDValue Op2, SDValue Op3, + unsigned Align, bool isVolatile, + bool AlwaysInline, + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -62,13 +62,10 @@ public: /// more efficient than using a library call. This function can return a null /// SDValue if the target declines to use custom code and a different /// lowering strategy should be used. - virtual SDValue - EmitTargetCodeForMemmove(SelectionDAG &DAG, SDLoc dl, - SDValue Chain, - SDValue Op1, SDValue Op2, - SDValue Op3, unsigned Align, bool isVolatile, - MachinePointerInfo DstPtrInfo, - MachinePointerInfo SrcPtrInfo) const { + virtual SDValue EmitTargetCodeForMemmove( + SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, + SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, + MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -78,12 +75,11 @@ public: /// efficient than using a library call. This function can return a null /// SDValue if the target declines to use custom code and a different /// lowering strategy should be used. - virtual SDValue - EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl, - SDValue Chain, - SDValue Op1, SDValue Op2, - SDValue Op3, unsigned Align, bool isVolatile, - MachinePointerInfo DstPtrInfo) const { + virtual SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, const SDLoc &dl, + SDValue Chain, SDValue Op1, + SDValue Op2, SDValue Op3, + unsigned Align, bool isVolatile, + MachinePointerInfo DstPtrInfo) const { return SDValue(); } @@ -92,10 +88,9 @@ public: /// memcmp and the second is the chain. Both SDValues can be null if a normal /// libcall should be used. virtual std::pair<SDValue, SDValue> - EmitTargetCodeForMemcmp(SelectionDAG &DAG, SDLoc dl, - SDValue Chain, - SDValue Op1, SDValue Op2, - SDValue Op3, MachinePointerInfo Op1PtrInfo, + EmitTargetCodeForMemcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, + SDValue Op1, SDValue Op2, SDValue Op3, + MachinePointerInfo Op1PtrInfo, MachinePointerInfo Op2PtrInfo) const { return std::make_pair(SDValue(), SDValue()); } @@ -105,7 +100,7 @@ public: /// memchr and the second is the chain. Both SDValues can be null if a normal /// libcall should be used. virtual std::pair<SDValue, SDValue> - EmitTargetCodeForMemchr(SelectionDAG &DAG, SDLoc dl, SDValue Chain, + EmitTargetCodeForMemchr(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Src, SDValue Char, SDValue Length, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); @@ -118,11 +113,10 @@ public: /// for stpcpy) and the second is the chain. Both SDValues can be null /// if a normal libcall should be used. virtual std::pair<SDValue, SDValue> - EmitTargetCodeForStrcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrcpy(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest, SDValue Src, MachinePointerInfo DestPtrInfo, - MachinePointerInfo SrcPtrInfo, - bool isStpcpy) const { + MachinePointerInfo SrcPtrInfo, bool isStpcpy) const { return std::make_pair(SDValue(), SDValue()); } @@ -131,8 +125,7 @@ public: /// The first returned SDValue is the result of the strcmp and the second is /// the chain. Both SDValues can be null if a normal libcall should be used. virtual std::pair<SDValue, SDValue> - EmitTargetCodeForStrcmp(SelectionDAG &DAG, SDLoc dl, - SDValue Chain, + EmitTargetCodeForStrcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, SDValue Op2, MachinePointerInfo Op1PtrInfo, MachinePointerInfo Op2PtrInfo) const { @@ -140,17 +133,22 @@ public: } virtual std::pair<SDValue, SDValue> - EmitTargetCodeForStrlen(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Src, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); } virtual std::pair<SDValue, SDValue> - EmitTargetCodeForStrnlen(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrnlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Src, SDValue MaxLength, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); } + // Return true when the decision to generate FMA's (or FMS, FMLA etc) rather + // than FMUL and ADD is delegated to the machine combiner. + virtual bool generateFMAsInMachineCombiner(CodeGenOpt::Level OptLevel) const { + return false; + } }; } // end llvm namespace diff --git a/include/llvm/CodeGen/SlotIndexes.h b/include/llvm/CodeGen/SlotIndexes.h index 7b621bee259f..afb0288b024f 100644 --- a/include/llvm/CodeGen/SlotIndexes.h +++ b/include/llvm/CodeGen/SlotIndexes.h @@ -66,7 +66,6 @@ namespace llvm { bool isPoisoned() const { return (reinterpret_cast<intptr_t>(mi) & 0x1) == 0x1; } #endif // EXPENSIVE_CHECKS - }; template <> @@ -99,7 +98,7 @@ namespace llvm { Slot_Block, /// Early-clobber register use/def slot. A live range defined at - /// Slot_EarlyCLobber interferes with normal live ranges killed at + /// Slot_EarlyClobber interferes with normal live ranges killed at /// Slot_Register. Also used as the kill slot for live ranges tied to an /// early-clobber def. Slot_EarlyClobber, @@ -213,6 +212,12 @@ namespace llvm { return A.listEntry()->getIndex() < B.listEntry()->getIndex(); } + /// Return true if A refers to the same instruction as B or an earlier one. + /// This is equivalent to !isEarlierInstr(B, A). + static bool isEarlierEqualInstr(SlotIndex A, SlotIndex B) { + return !isEarlierInstr(B, A); + } + /// Return the distance from this index to the given one. int distance(SlotIndex other) const { return other.getIndex() - getIndex(); @@ -302,7 +307,6 @@ namespace llvm { SlotIndex getPrevIndex() const { return SlotIndex(&*--listEntry()->getIterator(), getSlot()); } - }; template <> struct isPodLike<SlotIndex> { static const bool value = true; }; @@ -376,7 +380,7 @@ namespace llvm { initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); } - ~SlotIndexes() { + ~SlotIndexes() override { // The indexList's nodes are all allocated in the BumpPtrAllocator. indexList.clearAndLeakNodesUnsafely(); } @@ -410,14 +414,14 @@ namespace llvm { /// Returns true if the given machine instr is mapped to an index, /// otherwise returns false. - bool hasIndex(const MachineInstr *instr) const { - return mi2iMap.count(instr); + bool hasIndex(const MachineInstr &instr) const { + return mi2iMap.count(&instr); } /// Returns the base index for the given instruction. - SlotIndex getInstructionIndex(const MachineInstr *MI) const { + SlotIndex getInstructionIndex(const MachineInstr &MI) const { // Instructions inside a bundle have the same number as the bundle itself. - Mi2IndexMap::const_iterator itr = mi2iMap.find(getBundleStart(MI)); + Mi2IndexMap::const_iterator itr = mi2iMap.find(&getBundleStart(MI)); assert(itr != mi2iMap.end() && "Instruction not found in maps."); return itr->second; } @@ -443,15 +447,15 @@ namespace llvm { /// getIndexBefore - Returns the index of the last indexed instruction /// before MI, or the start index of its basic block. /// MI is not required to have an index. - SlotIndex getIndexBefore(const MachineInstr *MI) const { - const MachineBasicBlock *MBB = MI->getParent(); + SlotIndex getIndexBefore(const MachineInstr &MI) const { + const MachineBasicBlock *MBB = MI.getParent(); assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, B = MBB->begin(); for (;;) { if (I == B) return getMBBStartIdx(MBB); --I; - Mi2IndexMap::const_iterator MapItr = mi2iMap.find(I); + Mi2IndexMap::const_iterator MapItr = mi2iMap.find(&*I); if (MapItr != mi2iMap.end()) return MapItr->second; } @@ -460,15 +464,15 @@ namespace llvm { /// getIndexAfter - Returns the index of the first indexed instruction /// after MI, or the end index of its basic block. /// MI is not required to have an index. - SlotIndex getIndexAfter(const MachineInstr *MI) const { - const MachineBasicBlock *MBB = MI->getParent(); + SlotIndex getIndexAfter(const MachineInstr &MI) const { + const MachineBasicBlock *MBB = MI.getParent(); assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, E = MBB->end(); for (;;) { ++I; if (I == E) return getMBBEndIdx(MBB); - Mi2IndexMap::const_iterator MapItr = mi2iMap.find(I); + Mi2IndexMap::const_iterator MapItr = mi2iMap.find(&*I); if (MapItr != mi2iMap.end()) return MapItr->second; } @@ -573,25 +577,25 @@ namespace llvm { /// If Late is set and there are null indexes between mi's neighboring /// instructions, create the new index after the null indexes instead of /// before them. - SlotIndex insertMachineInstrInMaps(MachineInstr *mi, bool Late = false) { - assert(!mi->isInsideBundle() && + SlotIndex insertMachineInstrInMaps(MachineInstr &MI, bool Late = false) { + assert(!MI.isInsideBundle() && "Instructions inside bundles should use bundle start's slot."); - assert(mi2iMap.find(mi) == mi2iMap.end() && "Instr already indexed."); + assert(mi2iMap.find(&MI) == mi2iMap.end() && "Instr already indexed."); // Numbering DBG_VALUE instructions could cause code generation to be // affected by debug information. - assert(!mi->isDebugValue() && "Cannot number DBG_VALUE instructions."); + assert(!MI.isDebugValue() && "Cannot number DBG_VALUE instructions."); - assert(mi->getParent() != nullptr && "Instr must be added to function."); + assert(MI.getParent() != nullptr && "Instr must be added to function."); - // Get the entries where mi should be inserted. + // Get the entries where MI should be inserted. IndexList::iterator prevItr, nextItr; if (Late) { - // Insert mi's index immediately before the following instruction. - nextItr = getIndexAfter(mi).listEntry()->getIterator(); + // Insert MI's index immediately before the following instruction. + nextItr = getIndexAfter(MI).listEntry()->getIterator(); prevItr = std::prev(nextItr); } else { - // Insert mi's index immediately after the preceding instruction. - prevItr = getIndexBefore(mi).listEntry()->getIterator(); + // Insert MI's index immediately after the preceding instruction. + prevItr = getIndexBefore(MI).listEntry()->getIterator(); nextItr = std::next(prevItr); } @@ -600,27 +604,27 @@ namespace llvm { unsigned dist = ((nextItr->getIndex() - prevItr->getIndex())/2) & ~3u; unsigned newNumber = prevItr->getIndex() + dist; - // Insert a new list entry for mi. + // Insert a new list entry for MI. IndexList::iterator newItr = - indexList.insert(nextItr, createEntry(mi, newNumber)); + indexList.insert(nextItr, createEntry(&MI, newNumber)); // Renumber locally if we need to. if (dist == 0) renumberIndexes(newItr); SlotIndex newIndex(&*newItr, SlotIndex::Slot_Block); - mi2iMap.insert(std::make_pair(mi, newIndex)); + mi2iMap.insert(std::make_pair(&MI, newIndex)); return newIndex; } /// Remove the given machine instruction from the mapping. - void removeMachineInstrFromMaps(MachineInstr *mi) { + void removeMachineInstrFromMaps(MachineInstr &MI) { // remove index -> MachineInstr and // MachineInstr -> index mappings - Mi2IndexMap::iterator mi2iItr = mi2iMap.find(mi); + Mi2IndexMap::iterator mi2iItr = mi2iMap.find(&MI); if (mi2iItr != mi2iMap.end()) { IndexListEntry *miEntry(mi2iItr->second.listEntry()); - assert(miEntry->getInstr() == mi && "Instruction indexes broken."); + assert(miEntry->getInstr() == &MI && "Instruction indexes broken."); // FIXME: Eventually we want to actually delete these indexes. miEntry->setInstr(nullptr); mi2iMap.erase(mi2iItr); @@ -629,17 +633,17 @@ namespace llvm { /// ReplaceMachineInstrInMaps - Replacing a machine instr with a new one in /// maps used by register allocator. - void replaceMachineInstrInMaps(MachineInstr *mi, MachineInstr *newMI) { - Mi2IndexMap::iterator mi2iItr = mi2iMap.find(mi); + void replaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI) { + Mi2IndexMap::iterator mi2iItr = mi2iMap.find(&MI); if (mi2iItr == mi2iMap.end()) return; SlotIndex replaceBaseIndex = mi2iItr->second; IndexListEntry *miEntry(replaceBaseIndex.listEntry()); - assert(miEntry->getInstr() == mi && + assert(miEntry->getInstr() == &MI && "Mismatched instruction in index tables."); - miEntry->setInstr(newMI); + miEntry->setInstr(&NewMI); mi2iMap.erase(mi2iItr); - mi2iMap.insert(std::make_pair(newMI, replaceBaseIndex)); + mi2iMap.insert(std::make_pair(&NewMI, replaceBaseIndex)); } /// Add the given MachineBasicBlock into the maps. @@ -703,15 +707,13 @@ namespace llvm { indexList.erase(entry); #endif } - }; - // Specialize IntervalMapInfo for half-open slot index intervals. template <> struct IntervalMapInfo<SlotIndex> : IntervalMapHalfOpenInfo<SlotIndex> { }; -} +} // end namespace llvm #endif // LLVM_CODEGEN_SLOTINDEXES_H diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h index 972a616ad779..918848f6b2a1 100644 --- a/include/llvm/CodeGen/StackMaps.h +++ b/include/llvm/CodeGen/StackMaps.h @@ -14,8 +14,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/Support/Debug.h" -#include <map> #include <vector> namespace llvm { diff --git a/include/llvm/CodeGen/StackProtector.h b/include/llvm/CodeGen/StackProtector.h index 8cef85cb4485..1b3c0eb4a4d0 100644 --- a/include/llvm/CodeGen/StackProtector.h +++ b/include/llvm/CodeGen/StackProtector.h @@ -75,6 +75,12 @@ private: /// times. SmallPtrSet<const PHINode *, 16> VisitedPHIs; + // A prologue is generated. + bool HasPrologue = false; + + // IR checking code is generated. + bool HasIRCheck = false; + /// InsertStackProtectors - Insert code into the prologue and epilogue of /// the function. /// @@ -120,6 +126,10 @@ public: } SSPLayoutKind getSSPLayout(const AllocaInst *AI) const; + + // Return true if StackProtector is supposed to be handled by SelectionDAG. + bool shouldEmitSDCheck(const BasicBlock &BB) const; + void adjustForColoring(const AllocaInst *From, const AllocaInst *To); bool runOnFunction(Function &Fn) override; diff --git a/include/llvm/CodeGen/TailDuplicator.h b/include/llvm/CodeGen/TailDuplicator.h new file mode 100644 index 000000000000..8e65199418a6 --- /dev/null +++ b/include/llvm/CodeGen/TailDuplicator.h @@ -0,0 +1,92 @@ +//===-- llvm/CodeGen/TailDuplicator.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TailDuplicator class. Used by the +// TailDuplication pass, and MachineBlockPlacement. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TAILDUPLICATOR_H +#define LLVM_CODEGEN_TAILDUPLICATOR_H + +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineSSAUpdater.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +namespace llvm { + +/// Utility class to perform tail duplication. +class TailDuplicator { + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + const MachineBranchProbabilityInfo *MBPI; + const MachineModuleInfo *MMI; + MachineRegisterInfo *MRI; + bool PreRegAlloc; + + // A list of virtual registers for which to update SSA form. + SmallVector<unsigned, 16> SSAUpdateVRs; + + // For each virtual register in SSAUpdateVals keep a list of source virtual + // registers. + typedef std::vector<std::pair<MachineBasicBlock *, unsigned>> AvailableValsTy; + + DenseMap<unsigned, AvailableValsTy> SSAUpdateVals; + +public: + void initMF(MachineFunction &MF, const MachineModuleInfo *MMI, + const MachineBranchProbabilityInfo *MBPI); + bool tailDuplicateBlocks(MachineFunction &MF); + static bool isSimpleBB(MachineBasicBlock *TailBB); + bool shouldTailDuplicate(const MachineFunction &MF, bool IsSimple, + MachineBasicBlock &TailBB); + bool tailDuplicateAndUpdate(MachineFunction &MF, bool IsSimple, + MachineBasicBlock *MBB); + +private: + typedef TargetInstrInfo::RegSubRegPair RegSubRegPair; + + void addSSAUpdateEntry(unsigned OrigReg, unsigned NewReg, + MachineBasicBlock *BB); + void processPHI(MachineInstr *MI, MachineBasicBlock *TailBB, + MachineBasicBlock *PredBB, + DenseMap<unsigned, RegSubRegPair> &LocalVRMap, + SmallVectorImpl<std::pair<unsigned, RegSubRegPair>> &Copies, + const DenseSet<unsigned> &UsedByPhi, bool Remove); + void duplicateInstruction(MachineInstr *MI, MachineBasicBlock *TailBB, + MachineBasicBlock *PredBB, MachineFunction &MF, + DenseMap<unsigned, RegSubRegPair> &LocalVRMap, + const DenseSet<unsigned> &UsedByPhi); + void updateSuccessorsPHIs(MachineBasicBlock *FromBB, bool isDead, + SmallVectorImpl<MachineBasicBlock *> &TDBBs, + SmallSetVector<MachineBasicBlock *, 8> &Succs); + bool canCompletelyDuplicateBB(MachineBasicBlock &BB); + bool duplicateSimpleBB(MachineBasicBlock *TailBB, + SmallVectorImpl<MachineBasicBlock *> &TDBBs, + const DenseSet<unsigned> &RegsUsedByPhi, + SmallVectorImpl<MachineInstr *> &Copies); + bool tailDuplicate(MachineFunction &MF, bool IsSimple, + MachineBasicBlock *TailBB, + SmallVectorImpl<MachineBasicBlock *> &TDBBs, + SmallVectorImpl<MachineInstr *> &Copies); + void appendCopies(MachineBasicBlock *MBB, + SmallVectorImpl<std::pair<unsigned,RegSubRegPair>> &CopyInfos, + SmallVectorImpl<MachineInstr *> &Copies); + + void removeDeadBlock(MachineBasicBlock *MBB); +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 2f1379131cbd..c856435f5ddc 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -15,7 +15,7 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H -#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/SectionKind.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -23,7 +23,6 @@ namespace llvm { class MachineModuleInfo; class Mangler; class MCAsmInfo; - class MCExpr; class MCSection; class MCSectionMachO; class MCSymbol; @@ -36,6 +35,10 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { bool UseInitArray; mutable unsigned NextUniqueID = 0; +protected: + MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = + MCSymbolRefExpr::VK_None; + public: TargetLoweringObjectFileELF() : UseInitArray(false) {} @@ -47,7 +50,8 @@ public: /// Given a constant with the SectionKind, return a section that it should be /// placed in. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C) const override; + const Constant *C, + unsigned &Align) const override; MCSection *getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang, @@ -81,6 +85,10 @@ public: const MCSymbol *KeySym) const override; MCSection *getStaticDtorSection(unsigned Priority, const MCSymbol *KeySym) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, Mangler &Mang, + const TargetMachine &TM) const override; }; @@ -104,7 +112,8 @@ public: const TargetMachine &TM) const override; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C) const override; + const Constant *C, + unsigned &Align) const override; /// The mach-o version of this method defaults to returning a stub reference. const MCExpr * @@ -131,6 +140,8 @@ public: class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { + mutable unsigned NextUniqueID = 0; + public: ~TargetLoweringObjectFileCOFF() override {} diff --git a/include/llvm/CodeGen/TargetPassConfig.h b/include/llvm/CodeGen/TargetPassConfig.h new file mode 100644 index 000000000000..9309655a972e --- /dev/null +++ b/include/llvm/CodeGen/TargetPassConfig.h @@ -0,0 +1,376 @@ +//===-- TargetPassConfig.h - Code Generation pass options -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Target-Independent Code Generator Pass Configuration Options pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TARGETPASSCONFIG_H +#define LLVM_CODEGEN_TARGETPASSCONFIG_H + +#include "llvm/Pass.h" +#include "llvm/Support/CodeGen.h" +#include <string> + +namespace llvm { + +class PassConfigImpl; +class ScheduleDAGInstrs; +class TargetMachine; +struct MachineSchedContext; + +// The old pass manager infrastructure is hidden in a legacy namespace now. +namespace legacy { +class PassManagerBase; +} +using legacy::PassManagerBase; + +/// Discriminated union of Pass ID types. +/// +/// The PassConfig API prefers dealing with IDs because they are safer and more +/// efficient. IDs decouple configuration from instantiation. This way, when a +/// pass is overriden, it isn't unnecessarily instantiated. It is also unsafe to +/// refer to a Pass pointer after adding it to a pass manager, which deletes +/// redundant pass instances. +/// +/// However, it is convient to directly instantiate target passes with +/// non-default ctors. These often don't have a registered PassInfo. Rather than +/// force all target passes to implement the pass registry boilerplate, allow +/// the PassConfig API to handle either type. +/// +/// AnalysisID is sadly char*, so PointerIntPair won't work. +class IdentifyingPassPtr { + union { + AnalysisID ID; + Pass *P; + }; + bool IsInstance; +public: + IdentifyingPassPtr() : P(nullptr), IsInstance(false) {} + IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr), IsInstance(false) {} + IdentifyingPassPtr(Pass *InstancePtr) : P(InstancePtr), IsInstance(true) {} + + bool isValid() const { return P; } + bool isInstance() const { return IsInstance; } + + AnalysisID getID() const { + assert(!IsInstance && "Not a Pass ID"); + return ID; + } + Pass *getInstance() const { + assert(IsInstance && "Not a Pass Instance"); + return P; + } +}; + +template <> struct isPodLike<IdentifyingPassPtr> { + static const bool value = true; +}; + +/// Target-Independent Code Generator Pass Configuration Options. +/// +/// This is an ImmutablePass solely for the purpose of exposing CodeGen options +/// to the internals of other CodeGen passes. +class TargetPassConfig : public ImmutablePass { +public: + /// Pseudo Pass IDs. These are defined within TargetPassConfig because they + /// are unregistered pass IDs. They are only useful for use with + /// TargetPassConfig APIs to identify multiple occurrences of the same pass. + /// + + /// EarlyTailDuplicate - A clone of the TailDuplicate pass that runs early + /// during codegen, on SSA form. + static char EarlyTailDuplicateID; + + /// PostRAMachineLICM - A clone of the LICM pass that runs during late machine + /// optimization after regalloc. + static char PostRAMachineLICMID; + +private: + PassManagerBase *PM; + AnalysisID StartBefore, StartAfter; + AnalysisID StopAfter; + bool Started; + bool Stopped; + bool AddingMachinePasses; + +protected: + TargetMachine *TM; + PassConfigImpl *Impl; // Internal data structures + bool Initialized; // Flagged after all passes are configured. + + // Target Pass Options + // Targets provide a default setting, user flags override. + // + bool DisableVerify; + + /// Default setting for -enable-tail-merge on this target. + bool EnableTailMerge; + +public: + TargetPassConfig(TargetMachine *tm, PassManagerBase &pm); + // Dummy constructor. + TargetPassConfig(); + + ~TargetPassConfig() override; + + static char ID; + + /// Get the right type of TargetMachine for this target. + template<typename TMC> TMC &getTM() const { + return *static_cast<TMC*>(TM); + } + + // + void setInitialized() { Initialized = true; } + + CodeGenOpt::Level getOptLevel() const; + + /// Set the StartAfter, StartBefore and StopAfter passes to allow running only + /// a portion of the normal code-gen pass sequence. + /// + /// If the StartAfter and StartBefore pass ID is zero, then compilation will + /// begin at the normal point; otherwise, clear the Started flag to indicate + /// that passes should not be added until the starting pass is seen. If the + /// Stop pass ID is zero, then compilation will continue to the end. + /// + /// This function expects that at least one of the StartAfter or the + /// StartBefore pass IDs is null. + void setStartStopPasses(AnalysisID StartBefore, AnalysisID StartAfter, + AnalysisID StopAfter) { + if (StartAfter) + assert(!StartBefore && "Start after and start before passes are given"); + this->StartBefore = StartBefore; + this->StartAfter = StartAfter; + this->StopAfter = StopAfter; + Started = (StartAfter == nullptr) && (StartBefore == nullptr); + } + + void setDisableVerify(bool Disable) { setOpt(DisableVerify, Disable); } + + bool getEnableTailMerge() const { return EnableTailMerge; } + void setEnableTailMerge(bool Enable) { setOpt(EnableTailMerge, Enable); } + + /// Allow the target to override a specific pass without overriding the pass + /// pipeline. When passes are added to the standard pipeline at the + /// point where StandardID is expected, add TargetID in its place. + void substitutePass(AnalysisID StandardID, IdentifyingPassPtr TargetID); + + /// Insert InsertedPassID pass after TargetPassID pass. + void insertPass(AnalysisID TargetPassID, IdentifyingPassPtr InsertedPassID, + bool VerifyAfter = true, bool PrintAfter = true); + + /// Allow the target to enable a specific standard pass by default. + void enablePass(AnalysisID PassID) { substitutePass(PassID, PassID); } + + /// Allow the target to disable a specific standard pass by default. + void disablePass(AnalysisID PassID) { + substitutePass(PassID, IdentifyingPassPtr()); + } + + /// Return the pass substituted for StandardID by the target. + /// If no substitution exists, return StandardID. + IdentifyingPassPtr getPassSubstitution(AnalysisID StandardID) const; + + /// Return true if the pass has been substituted by the target or + /// overridden on the command line. + bool isPassSubstitutedOrOverridden(AnalysisID ID) const; + + /// Return true if the optimized regalloc pipeline is enabled. + bool getOptimizeRegAlloc() const; + + /// Return true if shrink wrapping is enabled. + bool getEnableShrinkWrap() const; + + /// Return true if the default global register allocator is in use and + /// has not be overriden on the command line with '-regalloc=...' + bool usingDefaultRegAlloc() const; + + /// Add common target configurable passes that perform LLVM IR to IR + /// transforms following machine independent optimization. + virtual void addIRPasses(); + + /// Add passes to lower exception handling for the code generator. + void addPassesToHandleExceptions(); + + /// Add pass to prepare the LLVM IR for code generation. This should be done + /// before exception handling preparation passes. + virtual void addCodeGenPrepare(); + + /// Add common passes that perform LLVM IR to IR transforms in preparation for + /// instruction selection. + virtual void addISelPrepare(); + + /// addInstSelector - This method should install an instruction selector pass, + /// which converts from LLVM code to machine instructions. + virtual bool addInstSelector() { + return true; + } + + /// This method should install an IR translator pass, which converts from + /// LLVM code to machine instructions with possibly generic opcodes. + virtual bool addIRTranslator() { return true; } + + /// This method may be implemented by targets that want to run passes + /// immediately before the register bank selection. + virtual void addPreRegBankSelect() {} + + /// This method should install a register bank selector pass, which + /// assigns register banks to virtual registers without a register + /// class or register banks. + virtual bool addRegBankSelect() { return true; } + + /// Add the complete, standard set of LLVM CodeGen passes. + /// Fully developed targets will not generally override this. + virtual void addMachinePasses(); + + /// Create an instance of ScheduleDAGInstrs to be run within the standard + /// MachineScheduler pass for this function and target at the current + /// optimization level. + /// + /// This can also be used to plug a new MachineSchedStrategy into an instance + /// of the standard ScheduleDAGMI: + /// return new ScheduleDAGMI(C, make_unique<MyStrategy>(C), /*RemoveKillFlags=*/false) + /// + /// Return NULL to select the default (generic) machine scheduler. + virtual ScheduleDAGInstrs * + createMachineScheduler(MachineSchedContext *C) const { + return nullptr; + } + + /// Similar to createMachineScheduler but used when postRA machine scheduling + /// is enabled. + virtual ScheduleDAGInstrs * + createPostMachineScheduler(MachineSchedContext *C) const { + return nullptr; + } + + /// printAndVerify - Add a pass to dump then verify the machine function, if + /// those steps are enabled. + /// + void printAndVerify(const std::string &Banner); + + /// Add a pass to print the machine function if printing is enabled. + void addPrintPass(const std::string &Banner); + + /// Add a pass to perform basic verification of the machine function if + /// verification is enabled. + void addVerifyPass(const std::string &Banner); + +protected: + // Helper to verify the analysis is really immutable. + void setOpt(bool &Opt, bool Val); + + /// Methods with trivial inline returns are convenient points in the common + /// codegen pass pipeline where targets may insert passes. Methods with + /// out-of-line standard implementations are major CodeGen stages called by + /// addMachinePasses. Some targets may override major stages when inserting + /// passes is insufficient, but maintaining overriden stages is more work. + /// + + /// addPreISelPasses - This method should add any "last minute" LLVM->LLVM + /// passes (which are run just before instruction selector). + virtual bool addPreISel() { + return true; + } + + /// addMachineSSAOptimization - Add standard passes that optimize machine + /// instructions in SSA form. + virtual void addMachineSSAOptimization(); + + /// Add passes that optimize instruction level parallelism for out-of-order + /// targets. These passes are run while the machine code is still in SSA + /// form, so they can use MachineTraceMetrics to control their heuristics. + /// + /// All passes added here should preserve the MachineDominatorTree, + /// MachineLoopInfo, and MachineTraceMetrics analyses. + virtual bool addILPOpts() { + return false; + } + + /// This method may be implemented by targets that want to run passes + /// immediately before register allocation. + virtual void addPreRegAlloc() { } + + /// createTargetRegisterAllocator - Create the register allocator pass for + /// this target at the current optimization level. + virtual FunctionPass *createTargetRegisterAllocator(bool Optimized); + + /// addFastRegAlloc - Add the minimum set of target-independent passes that + /// are required for fast register allocation. + virtual void addFastRegAlloc(FunctionPass *RegAllocPass); + + /// addOptimizedRegAlloc - Add passes related to register allocation. + /// LLVMTargetMachine provides standard regalloc passes for most targets. + virtual void addOptimizedRegAlloc(FunctionPass *RegAllocPass); + + /// addPreRewrite - Add passes to the optimized register allocation pipeline + /// after register allocation is complete, but before virtual registers are + /// rewritten to physical registers. + /// + /// These passes must preserve VirtRegMap and LiveIntervals, and when running + /// after RABasic or RAGreedy, they should take advantage of LiveRegMatrix. + /// When these passes run, VirtRegMap contains legal physreg assignments for + /// all virtual registers. + virtual bool addPreRewrite() { + return false; + } + + /// This method may be implemented by targets that want to run passes after + /// register allocation pass pipeline but before prolog-epilog insertion. + virtual void addPostRegAlloc() { } + + /// Add passes that optimize machine instructions after register allocation. + virtual void addMachineLateOptimization(); + + /// This method may be implemented by targets that want to run passes after + /// prolog-epilog insertion and before the second instruction scheduling pass. + virtual void addPreSched2() { } + + /// addGCPasses - Add late codegen passes that analyze code for garbage + /// collection. This should return true if GC info should be printed after + /// these passes. + virtual bool addGCPasses(); + + /// Add standard basic block placement passes. + virtual void addBlockPlacement(); + + /// This pass may be implemented by targets that want to run passes + /// immediately before machine code is emitted. + virtual void addPreEmitPass() { } + + /// Utilities for targets to add passes to the pass manager. + /// + + /// Add a CodeGen pass at this point in the pipeline after checking overrides. + /// Return the pass that was added, or zero if no pass was added. + /// @p printAfter if true and adding a machine function pass add an extra + /// machine printer pass afterwards + /// @p verifyAfter if true and adding a machine function pass add an extra + /// machine verification pass afterwards. + AnalysisID addPass(AnalysisID PassID, bool verifyAfter = true, + bool printAfter = true); + + /// Add a pass to the PassManager if that pass is supposed to be run, as + /// determined by the StartAfter and StopAfter options. Takes ownership of the + /// pass. + /// @p printAfter if true and adding a machine function pass add an extra + /// machine printer pass afterwards + /// @p verifyAfter if true and adding a machine function pass add an extra + /// machine verification pass afterwards. + void addPass(Pass *P, bool verifyAfter = true, bool printAfter = true); + + /// addMachinePasses helper to create the target-selected or overriden + /// regalloc pass. + FunctionPass *createRegAllocPass(bool Optimized); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/CodeGen/UnreachableBlockElim.h b/include/llvm/CodeGen/UnreachableBlockElim.h new file mode 100644 index 000000000000..3e7afd4cd433 --- /dev/null +++ b/include/llvm/CodeGen/UnreachableBlockElim.h @@ -0,0 +1,37 @@ +//===-- UnreachableBlockElim.h - Remove unreachable blocks for codegen --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass is an extremely simple version of the SimplifyCFG pass. Its sole +// job is to delete LLVM basic blocks that are not reachable from the entry +// node. To do this, it performs a simple depth first traversal of the CFG, +// then deletes any unvisited nodes. +// +// Note that this pass is really a hack. In particular, the instruction +// selectors for various targets should just not generate code for unreachable +// blocks. Until LLVM has a more systematic way of defining instruction +// selectors, however, we cannot really expect them to handle additional +// complexity. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H +#define LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class UnreachableBlockElimPass + : public PassInfoMixin<UnreachableBlockElimPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H diff --git a/include/llvm/CodeGen/ValueTypes.h b/include/llvm/CodeGen/ValueTypes.h index 929eb88a0393..524a90803df8 100644 --- a/include/llvm/CodeGen/ValueTypes.h +++ b/include/llvm/CodeGen/ValueTypes.h @@ -124,6 +124,11 @@ namespace llvm { return isSimple() ? V.isInteger() : isExtendedInteger(); } + /// isScalarInteger - Return true if this is an integer, but not a vector. + bool isScalarInteger() const { + return isSimple() ? V.isScalarInteger() : isExtendedScalarInteger(); + } + /// isVector - Return true if this is a vector value type. bool isVector() const { return isSimple() ? V.isVector() : isExtendedVector(); @@ -367,6 +372,7 @@ namespace llvm { unsigned NumElements); bool isExtendedFloatingPoint() const LLVM_READONLY; bool isExtendedInteger() const LLVM_READONLY; + bool isExtendedScalarInteger() const LLVM_READONLY; bool isExtendedVector() const LLVM_READONLY; bool isExtended16BitVector() const LLVM_READONLY; bool isExtended32BitVector() const LLVM_READONLY; @@ -378,7 +384,7 @@ namespace llvm { bool isExtended2048BitVector() const LLVM_READONLY; EVT getExtendedVectorElementType() const; unsigned getExtendedVectorNumElements() const LLVM_READONLY; - unsigned getExtendedSizeInBits() const; + unsigned getExtendedSizeInBits() const LLVM_READONLY; }; } // End llvm namespace diff --git a/include/llvm/CodeGen/ValueTypes.td b/include/llvm/CodeGen/ValueTypes.td index f29ec42714e8..f7b1661d7451 100644 --- a/include/llvm/CodeGen/ValueTypes.td +++ b/include/llvm/CodeGen/ValueTypes.td @@ -39,8 +39,8 @@ def v8i1 : ValueType<8 , 15>; // 8 x i1 vector value def v16i1 : ValueType<16, 16>; // 16 x i1 vector value def v32i1 : ValueType<32 , 17>; // 32 x i1 vector value def v64i1 : ValueType<64 , 18>; // 64 x i1 vector value -def v512i1 : ValueType<512, 19>; // 512 x i8 vector value -def v1024i1: ValueType<1024,20>; //1024 x i8 vector value +def v512i1 : ValueType<512, 19>; // 512 x i1 vector value +def v1024i1: ValueType<1024,20>; //1024 x i1 vector value def v1i8 : ValueType<16, 21>; // 1 x i8 vector value def v2i8 : ValueType<16 , 22>; // 2 x i8 vector value @@ -96,24 +96,24 @@ def x86mmx : ValueType<64 , 64>; // X86 MMX value def FlagVT : ValueType<0 , 65>; // Pre-RA sched glue def isVoid : ValueType<0 , 66>; // Produces no value def untyped: ValueType<8 , 67>; // Produces an untyped value -def token : ValueType<0 , 249>; // TokenTy -def MetadataVT: ValueType<0, 250>; // Metadata +def token : ValueType<0 , 120>; // TokenTy +def MetadataVT: ValueType<0, 121>; // Metadata // Pseudo valuetype mapped to the current pointer size to any address space. // Should only be used in TableGen. -def iPTRAny : ValueType<0, 251>; +def iPTRAny : ValueType<0, 122>; // Pseudo valuetype to represent "vector of any size" -def vAny : ValueType<0 , 252>; +def vAny : ValueType<0 , 123>; // Pseudo valuetype to represent "float of any format" -def fAny : ValueType<0 , 253>; +def fAny : ValueType<0 , 124>; // Pseudo valuetype to represent "integer of any bit width" -def iAny : ValueType<0 , 254>; +def iAny : ValueType<0 , 125>; // Pseudo valuetype mapped to the current pointer size. -def iPTR : ValueType<0 , 255>; +def iPTR : ValueType<0 , 126>; // Pseudo valuetype to represent "any type of any size". -def Any : ValueType<0 , 256>; +def Any : ValueType<0 , 127>; diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index 46c1029f62cf..dd730495a5f6 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -18,6 +18,7 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/IR/Instructions.h" namespace llvm { class AllocaInst; @@ -108,6 +109,7 @@ struct WinEHFuncInfo { int EHRegNodeFrameIndex = INT_MAX; int EHRegNodeEndOffset = INT_MAX; + int EHGuardFrameIndex = INT_MAX; int SEHSetFrameOffset = INT_MAX; WinEHFuncInfo(); diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index 6a5ac889e6f0..45b30d9171d9 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -1,5 +1,3 @@ -/* include/llvm/Config/config.h.cmake corresponding to config.h.in. */ - #ifndef CONFIG_H #define CONFIG_H @@ -15,15 +13,9 @@ /* Define to enable crash overrides */ #cmakedefine ENABLE_CRASH_OVERRIDES -/* Define to disable C++ atexit */ -#cmakedefine DISABLE_LLVM_DYLIB_ATEXIT - /* Define if position independent code is enabled */ #cmakedefine ENABLE_PIC -/* Define if timestamp information (e.g., __DATE__) is allowed */ -#cmakedefine ENABLE_TIMESTAMPS ${ENABLE_TIMESTAMPS} - /* Define to 1 if you have the `arc4random' function. */ #cmakedefine HAVE_DECL_ARC4RANDOM ${HAVE_DECL_ARC4RANDOM} @@ -256,6 +248,9 @@ /* Define if you have the shl_load function. */ #undef HAVE_SHL_LOAD +/* Define to 1 if you have the `sigaltstack' function. */ +#cmakedefine HAVE_SIGALTSTACK ${HAVE_SIGALTSTACK} + /* Define to 1 if you have the `siglongjmp' function. */ #cmakedefine HAVE_SIGLONGJMP ${HAVE_SIGLONGJMP} @@ -327,6 +322,9 @@ /* Define if the setupterm() function is supported this platform. */ #cmakedefine HAVE_TERMINFO ${HAVE_TERMINFO} +/* Define if the xar_open() function is supported this platform. */ +#cmakedefine HAVE_LIBXAR ${HAVE_LIBXAR} + /* Define to 1 if you have the <termios.h> header file. */ #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H} @@ -336,6 +334,9 @@ /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} +/* Define to 1 if you have the `_Unwind_Backtrace' function. */ +#cmakedefine HAVE_UNWIND_BACKTRACE ${HAVE_UNWIND_BACKTRACE} + /* Define to 1 if you have the <utime.h> header file. */ #cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H} @@ -504,6 +505,9 @@ /* LLVM version string */ #define LLVM_VERSION_STRING "${PACKAGE_VERSION}" +/* LLVM version information */ +#cmakedefine LLVM_VERSION_INFO "${LLVM_VERSION_INFO}" + /* Define if we link Polly to the tools */ #cmakedefine LINK_POLLY_INTO_TOOLS @@ -542,6 +546,9 @@ /* Define to the version of this package. */ #cmakedefine PACKAGE_VERSION "${PACKAGE_VERSION}" +/* Define to the vendor of this package. */ +#cmakedefine PACKAGE_VENDOR "${PACKAGE_VENDOR}" + /* Define as the return type of signal handlers (`int' or `void'). */ #cmakedefine RETSIGTYPE ${RETSIGTYPE} @@ -557,9 +564,6 @@ /* Define to 1 if your <sys/time.h> declares `struct tm'. */ #undef TM_IN_SYS_TIME -/* Type of 1st arg on ELM Callback */ -#cmakedefine WIN32_ELMCB_PCSTR ${WIN32_ELMCB_PCSTR} - /* Define to `int' if <sys/types.h> does not define. */ #undef pid_t diff --git a/include/llvm/Config/config.h.in b/include/llvm/Config/config.h.in deleted file mode 100644 index 498aa9ee6b5d..000000000000 --- a/include/llvm/Config/config.h.in +++ /dev/null @@ -1,538 +0,0 @@ -/* include/llvm/Config/config.h.in. Generated from autoconf/configure.ac by autoheader. */ - -#ifndef CONFIG_H -#define CONFIG_H - -/* Exported configuration */ -#include "llvm/Config/llvm-config.h" - -/* Bug report URL. */ -#undef BUG_REPORT_URL - -/* Default OpenMP runtime used by -fopenmp. */ -#undef CLANG_DEFAULT_OPENMP_RUNTIME - -/* Define if we have libxml2 */ -#undef CLANG_HAVE_LIBXML - -/* Multilib suffix for libdir. */ -#undef CLANG_LIBDIR_SUFFIX - -/* Relative directory for resource files */ -#undef CLANG_RESOURCE_DIR - -/* Directories clang will search for headers */ -#undef C_INCLUDE_DIRS - -/* Default <path> to all compiler invocations for --sysroot=<path>. */ -#undef DEFAULT_SYSROOT - -/* Define if you want backtraces on crash */ -#undef ENABLE_BACKTRACES - -/* Define to enable crash handling overrides */ -#undef ENABLE_CRASH_OVERRIDES - -/* Define if position independent code is enabled */ -#undef ENABLE_PIC - -/* Define if timestamp information (e.g., __DATE__) is allowed */ -#undef ENABLE_TIMESTAMPS - -/* Directory where gcc is installed. */ -#undef GCC_INSTALL_PREFIX - -/* Define to 1 if you have the `backtrace' function. */ -#undef HAVE_BACKTRACE - -/* Define to 1 if you have the <CrashReporterClient.h> header file. */ -#undef HAVE_CRASHREPORTERCLIENT_H - -/* can use __crashreporter_info__ */ -#undef HAVE_CRASHREPORTER_INFO - -/* Define to 1 if you have the <cxxabi.h> header file. */ -#undef HAVE_CXXABI_H - -/* Define to 1 if you have the declaration of `arc4random', and to 0 if you - don't. */ -#undef HAVE_DECL_ARC4RANDOM - -/* Define to 1 if you have the declaration of `FE_ALL_EXCEPT', and to 0 if you - don't. */ -#undef HAVE_DECL_FE_ALL_EXCEPT - -/* Define to 1 if you have the declaration of `FE_INEXACT', and to 0 if you - don't. */ -#undef HAVE_DECL_FE_INEXACT - -/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you - don't. */ -#undef HAVE_DECL_STRERROR_S - -/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. - */ -#undef HAVE_DIRENT_H - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#undef HAVE_DLFCN_H - -/* Define if dlopen() is available on this platform. */ -#undef HAVE_DLOPEN - -/* Define if the dot program is available */ -#undef HAVE_DOT - -/* Define to 1 if you have the <errno.h> header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if you have the <execinfo.h> header file. */ -#undef HAVE_EXECINFO_H - -/* Define to 1 if you have the <fcntl.h> header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the <fenv.h> header file. */ -#undef HAVE_FENV_H - -/* Define if libffi is available on this platform. */ -#undef HAVE_FFI_CALL - -/* Define to 1 if you have the <ffi/ffi.h> header file. */ -#undef HAVE_FFI_FFI_H - -/* Define to 1 if you have the <ffi.h> header file. */ -#undef HAVE_FFI_H - -/* Define to 1 if you have the `futimens' function. */ -#undef HAVE_FUTIMENS - -/* Define to 1 if you have the `futimes' function. */ -#undef HAVE_FUTIMES - -/* Define to 1 if you have the `getcwd' function. */ -#undef HAVE_GETCWD - -/* Define to 1 if you have the `getpagesize' function. */ -#undef HAVE_GETPAGESIZE - -/* Define to 1 if you have the `getrlimit' function. */ -#undef HAVE_GETRLIMIT - -/* Define to 1 if you have the `getrusage' function. */ -#undef HAVE_GETRUSAGE - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if the system has the type `int64_t'. */ -#undef HAVE_INT64_T - -/* Define to 1 if you have the <inttypes.h> header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `isatty' function. */ -#undef HAVE_ISATTY - -/* Define if libedit is available on this platform. */ -#undef HAVE_LIBEDIT - -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - -/* Define to 1 if you have the `ole32' library (-lole32). */ -#undef HAVE_LIBOLE32 - -/* Define to 1 if you have the `psapi' library (-lpsapi). */ -#undef HAVE_LIBPSAPI - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -#undef HAVE_LIBPTHREAD - -/* Define to 1 if you have the `shell32' library (-lshell32). */ -#undef HAVE_LIBSHELL32 - -/* Define to 1 if you have the `uuid' library (-luuid). */ -#undef HAVE_LIBUUID - -/* Define to 1 if you have the `z' library (-lz). */ -#undef HAVE_LIBZ - -/* Define if you can use -rdynamic. */ -#undef HAVE_LINK_EXPORT_DYNAMIC - -/* Define to 1 if you have the <link.h> header file. */ -#undef HAVE_LINK_H - -/* Define if you can use -Wl,-R. to pass -R. to the linker, in order to add - the current directory to the dynamic linker search path. */ -#undef HAVE_LINK_R - -/* Define to 1 if you have the `longjmp' function. */ -#undef HAVE_LONGJMP - -/* Define to 1 if you have the <mach/mach.h> header file. */ -#undef HAVE_MACH_MACH_H - -/* Define if mallinfo() is available on this platform. */ -#undef HAVE_MALLINFO - -/* Define to 1 if you have the <malloc.h> header file. */ -#undef HAVE_MALLOC_H - -/* Define to 1 if you have the <malloc/malloc.h> header file. */ -#undef HAVE_MALLOC_MALLOC_H - -/* Define to 1 if you have the `malloc_zone_statistics' function. */ -#undef HAVE_MALLOC_ZONE_STATISTICS - -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `mkdtemp' function. */ -#undef HAVE_MKDTEMP - -/* Define to 1 if you have the `mkstemp' function. */ -#undef HAVE_MKSTEMP - -/* Define to 1 if you have the `mktemp' function. */ -#undef HAVE_MKTEMP - -/* Define to 1 if you have a working `mmap' system call. */ -#undef HAVE_MMAP - -/* Define if mmap() uses MAP_ANONYMOUS to map anonymous pages, or undefine if - it uses MAP_ANON */ -#undef HAVE_MMAP_ANONYMOUS - -/* Define if mmap() can map files into memory */ -#undef HAVE_MMAP_FILE - -/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ -#undef HAVE_NDIR_H - -/* Define to 1 if you have the `posix_spawn' function. */ -#undef HAVE_POSIX_SPAWN - -/* Define to 1 if you have the `pread' function. */ -#undef HAVE_PREAD - -/* Define to have the %a format string */ -#undef HAVE_PRINTF_A - -/* Have pthread_getspecific */ -#undef HAVE_PTHREAD_GETSPECIFIC - -/* Define to 1 if you have the <pthread.h> header file. */ -#undef HAVE_PTHREAD_H - -/* Have pthread_mutex_lock */ -#undef HAVE_PTHREAD_MUTEX_LOCK - -/* Have pthread_rwlock_init */ -#undef HAVE_PTHREAD_RWLOCK_INIT - -/* Define to 1 if you have the `realpath' function. */ -#undef HAVE_REALPATH - -/* Define to 1 if you have the `sbrk' function. */ -#undef HAVE_SBRK - -/* Define to 1 if you have the `setenv' function. */ -#undef HAVE_SETENV - -/* Define to 1 if you have the `setjmp' function. */ -#undef HAVE_SETJMP - -/* Define to 1 if you have the <setjmp.h> header file. */ -#undef HAVE_SETJMP_H - -/* Define to 1 if you have the `setrlimit' function. */ -#undef HAVE_SETRLIMIT - -/* Define to 1 if you have the <signal.h> header file. */ -#undef HAVE_SIGNAL_H - -/* Define to 1 if you have the <stdint.h> header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the <stdlib.h> header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the `strerror_r' function. */ -#undef HAVE_STRERROR_R - -/* Define to 1 if you have the <strings.h> header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the <string.h> header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strtoll' function. */ -#undef HAVE_STRTOLL - -/* Define to 1 if you have the `strtoq' function. */ -#undef HAVE_STRTOQ - -/* Define to 1 if you have the `sysconf' function. */ -#undef HAVE_SYSCONF - -/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. - */ -#undef HAVE_SYS_DIR_H - -/* Define to 1 if you have the <sys/ioctl.h> header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the <sys/mman.h> header file. */ -#undef HAVE_SYS_MMAN_H - -/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. - */ -#undef HAVE_SYS_NDIR_H - -/* Define to 1 if you have the <sys/param.h> header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the <sys/resource.h> header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the <sys/time.h> header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the <sys/types.h> header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the <sys/uio.h> header file. */ -#undef HAVE_SYS_UIO_H - -/* Define if the setupterm() function is supported this platform. */ -#undef HAVE_TERMINFO - -/* Define to 1 if you have the <termios.h> header file. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if the system has the type `uint64_t'. */ -#undef HAVE_UINT64_T - -/* Define to 1 if you have the <unistd.h> header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if the system has the type `u_int64_t'. */ -#undef HAVE_U_INT64_T - -/* Define to 1 if you have the <valgrind/valgrind.h> header file. */ -#undef HAVE_VALGRIND_VALGRIND_H - -/* Define to 1 if you have the `writev' function. */ -#undef HAVE_WRITEV - -/* Define to 1 if you have the <zlib.h> header file. */ -#undef HAVE_ZLIB_H - -/* Have host's _alloca */ -#undef HAVE__ALLOCA - -/* Have host's __alloca */ -#undef HAVE___ALLOCA - -/* Have host's __ashldi3 */ -#undef HAVE___ASHLDI3 - -/* Have host's __ashrdi3 */ -#undef HAVE___ASHRDI3 - -/* Have host's __chkstk */ -#undef HAVE___CHKSTK - -/* Have host's __chkstk_ms */ -#undef HAVE___CHKSTK_MS - -/* Have host's __cmpdi2 */ -#undef HAVE___CMPDI2 - -/* Have host's __divdi3 */ -#undef HAVE___DIVDI3 - -/* Define to 1 if you have the `__dso_handle' function. */ -#undef HAVE___DSO_HANDLE - -/* Have host's __fixdfdi */ -#undef HAVE___FIXDFDI - -/* Have host's __fixsfdi */ -#undef HAVE___FIXSFDI - -/* Have host's __floatdidf */ -#undef HAVE___FLOATDIDF - -/* Have host's __lshrdi3 */ -#undef HAVE___LSHRDI3 - -/* Have host's __main */ -#undef HAVE___MAIN - -/* Have host's __moddi3 */ -#undef HAVE___MODDI3 - -/* Have host's __udivdi3 */ -#undef HAVE___UDIVDI3 - -/* Have host's __umoddi3 */ -#undef HAVE___UMODDI3 - -/* Have host's ___chkstk */ -#undef HAVE____CHKSTK - -/* Have host's ___chkstk_ms */ -#undef HAVE____CHKSTK_MS - -/* Linker version detected at compile time. */ -#undef HOST_LINK_VERSION - -/* Installation directory for binary executables */ -#undef LLVM_BINDIR - -/* Time at which LLVM was configured */ -#undef LLVM_CONFIGTIME - -/* Installation directory for data files */ -#undef LLVM_DATADIR - -/* Target triple LLVM will generate code for by default */ -#undef LLVM_DEFAULT_TARGET_TRIPLE - -/* Installation directory for documentation */ -#undef LLVM_DOCSDIR - -/* Define to enable checks that alter the LLVM C++ ABI */ -#undef LLVM_ENABLE_ABI_BREAKING_CHECKS - -/* Define if threads enabled */ -#undef LLVM_ENABLE_THREADS - -/* Define if zlib is enabled */ -#undef LLVM_ENABLE_ZLIB - -/* Installation directory for config files */ -#undef LLVM_ETCDIR - -/* Has gcc/MSVC atomic intrinsics */ -#undef LLVM_HAS_ATOMICS - -/* Host triple LLVM will be executed on */ -#undef LLVM_HOST_TRIPLE - -/* Installation directory for include files */ -#undef LLVM_INCLUDEDIR - -/* Installation directory for .info files */ -#undef LLVM_INFODIR - -/* Installation directory for man pages */ -#undef LLVM_MANDIR - -/* LLVM architecture name for the native architecture, if available */ -#undef LLVM_NATIVE_ARCH - -/* LLVM name for the native AsmParser init function, if available */ -#undef LLVM_NATIVE_ASMPARSER - -/* LLVM name for the native AsmPrinter init function, if available */ -#undef LLVM_NATIVE_ASMPRINTER - -/* LLVM name for the native Disassembler init function, if available */ -#undef LLVM_NATIVE_DISASSEMBLER - -/* LLVM name for the native Target init function, if available */ -#undef LLVM_NATIVE_TARGET - -/* LLVM name for the native TargetInfo init function, if available */ -#undef LLVM_NATIVE_TARGETINFO - -/* LLVM name for the native target MC init function, if available */ -#undef LLVM_NATIVE_TARGETMC - -/* Define if this is Unixish platform */ -#undef LLVM_ON_UNIX - -/* Define if this is Win32ish platform */ -#undef LLVM_ON_WIN32 - -/* Define to path to dot program if found or 'echo dot' otherwise */ -#undef LLVM_PATH_DOT - -/* Installation prefix directory */ -#undef LLVM_PREFIX - -/* Define if we have the Intel JIT API runtime support library */ -#undef LLVM_USE_INTEL_JITEVENTS - -/* Define if we have the oprofile JIT-support library */ -#undef LLVM_USE_OPROFILE - -/* Major version of the LLVM API */ -#undef LLVM_VERSION_MAJOR - -/* Minor version of the LLVM API */ -#undef LLVM_VERSION_MINOR - -/* Patch version of the LLVM API */ -#undef LLVM_VERSION_PATCH - -/* LLVM version string */ -#undef LLVM_VERSION_STRING - -/* The shared library extension */ -#undef LTDL_SHLIB_EXT - -/* Define if /dev/zero should be used when mapping RWX memory, or undefine if - its not necessary */ -#undef NEED_DEV_ZERO_FOR_MMAP - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE - -/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */ -#undef STAT_MACROS_BROKEN - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ -#undef TIME_WITH_SYS_TIME - -/* Define to 1 if your <sys/time.h> declares `struct tm'. */ -#undef TM_IN_SYS_TIME - -/* Type of 1st arg on ELM Callback */ -#undef WIN32_ELMCB_PCSTR - -/* Define to `int' if <sys/types.h> does not define. */ -#undef pid_t - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -#undef size_t - -#endif diff --git a/include/llvm/Config/llvm-config.h.in b/include/llvm/Config/llvm-config.h.in deleted file mode 100644 index 2dd5d0af7b58..000000000000 --- a/include/llvm/Config/llvm-config.h.in +++ /dev/null @@ -1,104 +0,0 @@ -/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/ -/* */ -/* The LLVM Compiler Infrastructure */ -/* */ -/* This file is distributed under the University of Illinois Open Source */ -/* License. See LICENSE.TXT for details. */ -/* */ -/*===----------------------------------------------------------------------===*/ - -/* This file enumerates variables from the LLVM configuration so that they - can be in exported headers and won't override package specific directives. - This is a C header that can be included in the llvm-c headers. */ - -#ifndef LLVM_CONFIG_H -#define LLVM_CONFIG_H - -/* Installation directory for binary executables */ -#undef LLVM_BINDIR - -/* Time at which LLVM was configured */ -#undef LLVM_CONFIGTIME - -/* Installation directory for data files */ -#undef LLVM_DATADIR - -/* Target triple LLVM will generate code for by default */ -#undef LLVM_DEFAULT_TARGET_TRIPLE - -/* Installation directory for documentation */ -#undef LLVM_DOCSDIR - -/* Define to enable checks that alter the LLVM C++ ABI */ -#undef LLVM_ENABLE_ABI_BREAKING_CHECKS - -/* Define if threads enabled */ -#undef LLVM_ENABLE_THREADS - -/* Installation directory for config files */ -#undef LLVM_ETCDIR - -/* Has gcc/MSVC atomic intrinsics */ -#undef LLVM_HAS_ATOMICS - -/* Host triple LLVM will be executed on */ -#undef LLVM_HOST_TRIPLE - -/* Installation directory for include files */ -#undef LLVM_INCLUDEDIR - -/* Installation directory for .info files */ -#undef LLVM_INFODIR - -/* Installation directory for man pages */ -#undef LLVM_MANDIR - -/* LLVM architecture name for the native architecture, if available */ -#undef LLVM_NATIVE_ARCH - -/* LLVM name for the native AsmParser init function, if available */ -#undef LLVM_NATIVE_ASMPARSER - -/* LLVM name for the native AsmPrinter init function, if available */ -#undef LLVM_NATIVE_ASMPRINTER - -/* LLVM name for the native Disassembler init function, if available */ -#undef LLVM_NATIVE_DISASSEMBLER - -/* LLVM name for the native Target init function, if available */ -#undef LLVM_NATIVE_TARGET - -/* LLVM name for the native TargetInfo init function, if available */ -#undef LLVM_NATIVE_TARGETINFO - -/* LLVM name for the native target MC init function, if available */ -#undef LLVM_NATIVE_TARGETMC - -/* Define if this is Unixish platform */ -#undef LLVM_ON_UNIX - -/* Define if this is Win32ish platform */ -#undef LLVM_ON_WIN32 - -/* Installation prefix directory */ -#undef LLVM_PREFIX - -/* Define if we have the Intel JIT API runtime support library */ -#undef LLVM_USE_INTEL_JITEVENTS - -/* Define if we have the oprofile JIT-support library */ -#undef LLVM_USE_OPROFILE - -/* Major version of the LLVM API */ -#undef LLVM_VERSION_MAJOR - -/* Minor version of the LLVM API */ -#undef LLVM_VERSION_MINOR - -/* Patch version of the LLVM API */ -#undef LLVM_VERSION_PATCH - -/* LLVM version string */ -#undef LLVM_VERSION_STRING - -#endif diff --git a/include/llvm/DebugInfo/CodeView/ByteStream.h b/include/llvm/DebugInfo/CodeView/ByteStream.h new file mode 100644 index 000000000000..f398c93723e7 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ByteStream.h @@ -0,0 +1,58 @@ +//===- ByteStream.h - Reads stream data from a byte sequence ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H +#define LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <memory> +#include <type_traits> + +namespace llvm { +namespace codeview { +class StreamReader; + +template <bool Writable = false> class ByteStream : public StreamInterface { + typedef typename std::conditional<Writable, MutableArrayRef<uint8_t>, + ArrayRef<uint8_t>>::type ArrayType; + +public: + ByteStream() {} + explicit ByteStream(ArrayType Data) : Data(Data) {} + ~ByteStream() override {} + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) const override; + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override; + + uint32_t getLength() const override; + + Error commit() const override; + + ArrayRef<uint8_t> data() const { return Data; } + StringRef str() const; + +private: + ArrayType Data; +}; + +extern template class ByteStream<true>; +extern template class ByteStream<false>; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h new file mode 100644 index 000000000000..dba359fcbe82 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -0,0 +1,56 @@ +//===- RecordIterator.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace codeview { + +template <typename Kind> struct CVRecord { + uint32_t Length; + Kind Type; + ArrayRef<uint8_t> Data; + ArrayRef<uint8_t> RawData; +}; + +template <typename Kind> struct VarStreamArrayExtractor<CVRecord<Kind>> { + Error operator()(StreamRef Stream, uint32_t &Len, + CVRecord<Kind> &Item) const { + const RecordPrefix *Prefix = nullptr; + StreamReader Reader(Stream); + uint32_t Offset = Reader.getOffset(); + + if (auto EC = Reader.readObject(Prefix)) + return EC; + Item.Length = Prefix->RecordLen; + if (Item.Length < 2) + return make_error<CodeViewError>(cv_error_code::corrupt_record); + Item.Type = static_cast<Kind>(uint16_t(Prefix->RecordKind)); + + Reader.setOffset(Offset); + if (auto EC = + Reader.readBytes(Item.RawData, Item.Length + sizeof(uint16_t))) + return EC; + Item.Data = Item.RawData.slice(sizeof(RecordPrefix)); + Len = Prefix->RecordLen + 2; + return Error::success(); + } +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def new file mode 100644 index 000000000000..32813d861d90 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def @@ -0,0 +1,258 @@ +//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +#ifndef CV_SYMBOL +#define CV_SYMBOL(ename, value) +#endif + +#ifndef SYMBOL_RECORD +#define SYMBOL_RECORD(lf_ename, value, name) CV_SYMBOL(lf_ename, value) +#endif + +#ifndef SYMBOL_RECORD_ALIAS +#define SYMBOL_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + SYMBOL_RECORD(lf_ename, value, name) +#endif + +// 16 bit symbol types. Not very useful, provided only for reference. +CV_SYMBOL(S_COMPILE , 0x0001) +CV_SYMBOL(S_REGISTER_16t , 0x0002) +CV_SYMBOL(S_CONSTANT_16t , 0x0003) +CV_SYMBOL(S_UDT_16t , 0x0004) +CV_SYMBOL(S_SSEARCH , 0x0005) +CV_SYMBOL(S_SKIP , 0x0007) +CV_SYMBOL(S_CVRESERVE , 0x0008) +CV_SYMBOL(S_OBJNAME_ST , 0x0009) +CV_SYMBOL(S_ENDARG , 0x000a) +CV_SYMBOL(S_COBOLUDT_16t , 0x000b) +CV_SYMBOL(S_MANYREG_16t , 0x000c) +CV_SYMBOL(S_RETURN , 0x000d) +CV_SYMBOL(S_ENTRYTHIS , 0x000e) +CV_SYMBOL(S_BPREL16 , 0x0100) +CV_SYMBOL(S_LDATA16 , 0x0101) +CV_SYMBOL(S_GDATA16 , 0x0102) +CV_SYMBOL(S_PUB16 , 0x0103) +CV_SYMBOL(S_LPROC16 , 0x0104) +CV_SYMBOL(S_GPROC16 , 0x0105) +CV_SYMBOL(S_THUNK16 , 0x0106) +CV_SYMBOL(S_BLOCK16 , 0x0107) +CV_SYMBOL(S_WITH16 , 0x0108) +CV_SYMBOL(S_LABEL16 , 0x0109) +CV_SYMBOL(S_CEXMODEL16 , 0x010a) +CV_SYMBOL(S_VFTABLE16 , 0x010b) +CV_SYMBOL(S_REGREL16 , 0x010c) +CV_SYMBOL(S_BPREL32_16t , 0x0200) +CV_SYMBOL(S_LDATA32_16t , 0x0201) +CV_SYMBOL(S_GDATA32_16t , 0x0202) +CV_SYMBOL(S_PUB32_16t , 0x0203) +CV_SYMBOL(S_LPROC32_16t , 0x0204) +CV_SYMBOL(S_GPROC32_16t , 0x0205) +CV_SYMBOL(S_THUNK32_ST , 0x0206) +CV_SYMBOL(S_BLOCK32_ST , 0x0207) +CV_SYMBOL(S_WITH32_ST , 0x0208) +CV_SYMBOL(S_LABEL32_ST , 0x0209) +CV_SYMBOL(S_CEXMODEL32 , 0x020a) +CV_SYMBOL(S_VFTABLE32_16t , 0x020b) +CV_SYMBOL(S_REGREL32_16t , 0x020c) +CV_SYMBOL(S_LTHREAD32_16t , 0x020d) +CV_SYMBOL(S_GTHREAD32_16t , 0x020e) +CV_SYMBOL(S_SLINK32 , 0x020f) +CV_SYMBOL(S_LPROCMIPS_16t , 0x0300) +CV_SYMBOL(S_GPROCMIPS_16t , 0x0301) +CV_SYMBOL(S_PROCREF_ST , 0x0400) +CV_SYMBOL(S_DATAREF_ST , 0x0401) +CV_SYMBOL(S_ALIGN , 0x0402) +CV_SYMBOL(S_LPROCREF_ST , 0x0403) +CV_SYMBOL(S_OEM , 0x0404) + +// All post 16 bit symbol types have the 0x1000 bit set. +CV_SYMBOL(S_TI16_MAX , 0x1000) + +// Mostly unused "start" symbol types. +CV_SYMBOL(S_REGISTER_ST , 0x1001) +CV_SYMBOL(S_CONSTANT_ST , 0x1002) +CV_SYMBOL(S_UDT_ST , 0x1003) +CV_SYMBOL(S_COBOLUDT_ST , 0x1004) +CV_SYMBOL(S_MANYREG_ST , 0x1005) +CV_SYMBOL(S_BPREL32_ST , 0x1006) +CV_SYMBOL(S_LDATA32_ST , 0x1007) +CV_SYMBOL(S_GDATA32_ST , 0x1008) +CV_SYMBOL(S_PUB32_ST , 0x1009) +CV_SYMBOL(S_LPROC32_ST , 0x100a) +CV_SYMBOL(S_GPROC32_ST , 0x100b) +CV_SYMBOL(S_VFTABLE32 , 0x100c) +CV_SYMBOL(S_REGREL32_ST , 0x100d) +CV_SYMBOL(S_LTHREAD32_ST , 0x100e) +CV_SYMBOL(S_GTHREAD32_ST , 0x100f) +CV_SYMBOL(S_LPROCMIPS_ST , 0x1010) +CV_SYMBOL(S_GPROCMIPS_ST , 0x1011) + +CV_SYMBOL(S_COMPILE2_ST , 0x1013) +CV_SYMBOL(S_MANYREG2_ST , 0x1014) +CV_SYMBOL(S_LPROCIA64_ST , 0x1015) +CV_SYMBOL(S_GPROCIA64_ST , 0x1016) +CV_SYMBOL(S_LOCALSLOT_ST , 0x1017) +CV_SYMBOL(S_PARAMSLOT_ST , 0x1018) +CV_SYMBOL(S_ANNOTATION , 0x1019) +CV_SYMBOL(S_GMANPROC_ST , 0x101a) +CV_SYMBOL(S_LMANPROC_ST , 0x101b) +CV_SYMBOL(S_RESERVED1 , 0x101c) +CV_SYMBOL(S_RESERVED2 , 0x101d) +CV_SYMBOL(S_RESERVED3 , 0x101e) +CV_SYMBOL(S_RESERVED4 , 0x101f) +CV_SYMBOL(S_LMANDATA_ST , 0x1020) +CV_SYMBOL(S_GMANDATA_ST , 0x1021) +CV_SYMBOL(S_MANFRAMEREL_ST, 0x1022) +CV_SYMBOL(S_MANREGISTER_ST, 0x1023) +CV_SYMBOL(S_MANSLOT_ST , 0x1024) +CV_SYMBOL(S_MANMANYREG_ST , 0x1025) +CV_SYMBOL(S_MANREGREL_ST , 0x1026) +CV_SYMBOL(S_MANMANYREG2_ST, 0x1027) +CV_SYMBOL(S_MANTYPREF , 0x1028) +CV_SYMBOL(S_UNAMESPACE_ST , 0x1029) + +// End of S_*_ST symbols, which do not appear to be generated by modern +// compilers. +CV_SYMBOL(S_ST_MAX , 0x1100) + + +CV_SYMBOL(S_WITH32 , 0x1104) +CV_SYMBOL(S_MANYREG , 0x110a) +CV_SYMBOL(S_LPROCMIPS , 0x1114) +CV_SYMBOL(S_GPROCMIPS , 0x1115) +CV_SYMBOL(S_MANYREG2 , 0x1117) +CV_SYMBOL(S_LPROCIA64 , 0x1118) +CV_SYMBOL(S_GPROCIA64 , 0x1119) +CV_SYMBOL(S_LOCALSLOT , 0x111a) +CV_SYMBOL(S_PARAMSLOT , 0x111b) + +// Managed code symbols. +CV_SYMBOL(S_MANFRAMEREL , 0x111e) +CV_SYMBOL(S_MANREGISTER , 0x111f) +CV_SYMBOL(S_MANSLOT , 0x1120) +CV_SYMBOL(S_MANMANYREG , 0x1121) +CV_SYMBOL(S_MANREGREL , 0x1122) +CV_SYMBOL(S_MANMANYREG2 , 0x1123) +CV_SYMBOL(S_UNAMESPACE , 0x1124) +CV_SYMBOL(S_DATAREF , 0x1126) +CV_SYMBOL(S_ANNOTATIONREF , 0x1128) +CV_SYMBOL(S_TOKENREF , 0x1129) +CV_SYMBOL(S_GMANPROC , 0x112a) +CV_SYMBOL(S_LMANPROC , 0x112b) +CV_SYMBOL(S_ATTR_FRAMEREL , 0x112e) +CV_SYMBOL(S_ATTR_REGISTER , 0x112f) +CV_SYMBOL(S_ATTR_REGREL , 0x1130) +CV_SYMBOL(S_ATTR_MANYREG , 0x1131) + + +CV_SYMBOL(S_SEPCODE , 0x1132) +CV_SYMBOL(S_LOCAL_2005 , 0x1133) +CV_SYMBOL(S_DEFRANGE_2005 , 0x1134) +CV_SYMBOL(S_DEFRANGE2_2005, 0x1135) +CV_SYMBOL(S_DISCARDED , 0x113b) + +// Current symbol types for most procedures as of this writing. +CV_SYMBOL(S_LPROCMIPS_ID , 0x1148) +CV_SYMBOL(S_GPROCMIPS_ID , 0x1149) +CV_SYMBOL(S_LPROCIA64_ID , 0x114a) +CV_SYMBOL(S_GPROCIA64_ID , 0x114b) + +CV_SYMBOL(S_DEFRANGE_HLSL , 0x1150) +CV_SYMBOL(S_GDATA_HLSL , 0x1151) +CV_SYMBOL(S_LDATA_HLSL , 0x1152) +CV_SYMBOL(S_LOCAL_DPC_GROUPSHARED, 0x1154) +CV_SYMBOL(S_DEFRANGE_DPC_PTR_TAG, 0x1157) +CV_SYMBOL(S_DPC_SYM_TAG_MAP, 0x1158) +CV_SYMBOL(S_ARMSWITCHTABLE , 0x1159) +CV_SYMBOL(S_POGODATA , 0x115c) +CV_SYMBOL(S_INLINESITE2 , 0x115d) +CV_SYMBOL(S_MOD_TYPEREF , 0x115f) +CV_SYMBOL(S_REF_MINIPDB , 0x1160) +CV_SYMBOL(S_PDBMAP , 0x1161) +CV_SYMBOL(S_GDATA_HLSL32 , 0x1162) +CV_SYMBOL(S_LDATA_HLSL32 , 0x1163) +CV_SYMBOL(S_GDATA_HLSL32_EX, 0x1164) +CV_SYMBOL(S_LDATA_HLSL32_EX, 0x1165) + +// Known symbol types +SYMBOL_RECORD(S_END , 0x0006, ScopeEndSym) +SYMBOL_RECORD_ALIAS(S_INLINESITE_END , 0x114e, InlineSiteEnd, ScopeEndSym) +SYMBOL_RECORD_ALIAS(S_PROC_ID_END , 0x114f, ProcEnd, ScopeEndSym) + +SYMBOL_RECORD(S_THUNK32 , 0x1102, Thunk32Sym) +SYMBOL_RECORD(S_TRAMPOLINE , 0x112c, TrampolineSym) +SYMBOL_RECORD(S_SECTION , 0x1136, SectionSym) +SYMBOL_RECORD(S_COFFGROUP , 0x1137, CoffGroupSym) +SYMBOL_RECORD(S_EXPORT , 0x1138, ExportSym) + +SYMBOL_RECORD(S_LPROC32 , 0x110f, ProcSym) +SYMBOL_RECORD_ALIAS(S_GPROC32 , 0x1110, GlobalProcSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_ID , 0x1146, ProcIdSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_GPROC32_ID , 0x1147, GlobalProcIdSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_DPC , 0x1155, DPCProcSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_DPC_ID , 0x1156, DPCProcIdSym, ProcSym) + +SYMBOL_RECORD(S_REGISTER , 0x1106, RegisterSym) +SYMBOL_RECORD(S_PUB32 , 0x110e, PublicSym32) + +SYMBOL_RECORD(S_PROCREF , 0x1125, ProcRefSym) +SYMBOL_RECORD_ALIAS(S_LPROCREF, 0x1127, LocalProcRef, ProcRefSym) + + +SYMBOL_RECORD(S_ENVBLOCK , 0x113d, EnvBlockSym) + +SYMBOL_RECORD(S_INLINESITE , 0x114d, InlineSiteSym) +SYMBOL_RECORD(S_LOCAL , 0x113e, LocalSym) +SYMBOL_RECORD(S_DEFRANGE , 0x113f, DefRangeSym) +SYMBOL_RECORD(S_DEFRANGE_SUBFIELD, 0x1140, DefRangeSubfieldSym) +SYMBOL_RECORD(S_DEFRANGE_REGISTER, 0x1141, DefRangeRegisterSym) +SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142, DefRangeFramePointerRelSym) +SYMBOL_RECORD(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143, DefRangeSubfieldRegisterSym) +SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144, DefRangeFramePointerRelFullScopeSym) +SYMBOL_RECORD(S_DEFRANGE_REGISTER_REL, 0x1145, DefRangeRegisterRelSym) +SYMBOL_RECORD(S_BLOCK32 , 0x1103, BlockSym) +SYMBOL_RECORD(S_LABEL32 , 0x1105, LabelSym) +SYMBOL_RECORD(S_OBJNAME , 0x1101, ObjNameSym) +SYMBOL_RECORD(S_COMPILE2 , 0x1116, Compile2Sym) +SYMBOL_RECORD(S_COMPILE3 , 0x113c, Compile3Sym) +SYMBOL_RECORD(S_FRAMEPROC , 0x1012, FrameProcSym) +SYMBOL_RECORD(S_CALLSITEINFO , 0x1139, CallSiteInfoSym) +SYMBOL_RECORD(S_FILESTATIC , 0x1153, FileStaticSym) +SYMBOL_RECORD(S_HEAPALLOCSITE , 0x115e, HeapAllocationSiteSym) +SYMBOL_RECORD(S_FRAMECOOKIE , 0x113a, FrameCookieSym) + +SYMBOL_RECORD(S_CALLEES , 0x115a, CallerSym) +SYMBOL_RECORD_ALIAS(S_CALLERS , 0x115b, CalleeSym, CallerSym) + +SYMBOL_RECORD(S_UDT , 0x1108, UDTSym) +SYMBOL_RECORD_ALIAS(S_COBOLUDT , 0x1109, CobolUDT, UDTSym) + +SYMBOL_RECORD(S_BUILDINFO , 0x114c, BuildInfoSym) +SYMBOL_RECORD(S_BPREL32 , 0x110b, BPRelativeSym) +SYMBOL_RECORD(S_REGREL32 , 0x1111, RegRelativeSym) + +SYMBOL_RECORD(S_CONSTANT , 0x1107, ConstantSym) +SYMBOL_RECORD_ALIAS(S_MANCONSTANT , 0x112d, ManagedConstant, ConstantSym) + +SYMBOL_RECORD(S_LDATA32 , 0x110c, DataSym) +SYMBOL_RECORD_ALIAS(S_GDATA32 , 0x110d, GlobalData, DataSym) +SYMBOL_RECORD_ALIAS(S_LMANDATA , 0x111c, ManagedLocalData, DataSym) +SYMBOL_RECORD_ALIAS(S_GMANDATA , 0x111d, ManagedGlobalData, DataSym) + +SYMBOL_RECORD(S_LTHREAD32 , 0x1112, ThreadLocalDataSym) +SYMBOL_RECORD_ALIAS(S_GTHREAD32 , 0x1113, GlobalTLS, ThreadLocalDataSym) + + +#undef CV_SYMBOL +#undef SYMBOL_RECORD +#undef SYMBOL_RECORD_ALIAS diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h new file mode 100644 index 000000000000..7c88956c984e --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h @@ -0,0 +1,103 @@ +//===- CVSymbolVisitor.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H + +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace codeview { + +template <typename Derived> class CVSymbolVisitor { +public: + CVSymbolVisitor(SymbolVisitorDelegate *Delegate) : Delegate(Delegate) {} + + bool hadError() const { return HadError; } + + template <typename T> + bool consumeObject(ArrayRef<uint8_t> &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) { + HadError = true; + return false; + } + Res = reinterpret_cast<const T *>(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return true; + } + +/// Actions to take on known symbols. By default, they do nothing. Visit methods +/// for member records take the FieldData by non-const reference and are +/// expected to consume the trailing bytes used by the field. +/// FIXME: Make the visitor interpret the trailing bytes so that clients don't +/// need to. +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + void visit##Name(SymbolRecordKind Kind, Name &Record) {} +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "CVSymbolTypes.def" + + void visitSymbolRecord(const CVRecord<SymbolKind> &Record) { + ArrayRef<uint8_t> Data = Record.Data; + auto *DerivedThis = static_cast<Derived *>(this); + DerivedThis->visitSymbolBegin(Record.Type, Data); + uint32_t RecordOffset = Delegate ? Delegate->getRecordOffset(Data) : 0; + switch (Record.Type) { + default: + DerivedThis->visitUnknownSymbol(Record.Type, Data); + break; +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + SymbolRecordKind RK = static_cast<SymbolRecordKind>(EnumName); \ + auto Result = Name::deserialize(RK, RecordOffset, Data); \ + if (Result.getError()) \ + return parseError(); \ + DerivedThis->visit##Name(Record.Type, *Result); \ + break; \ + } +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + SYMBOL_RECORD(EnumVal, EnumVal, AliasName) +#include "CVSymbolTypes.def" + } + DerivedThis->visitSymbolEnd(Record.Type, Record.Data); + } + + /// Visits the symbol records in Data. Sets the error flag on parse failures. + void visitSymbolStream(const CVSymbolArray &Symbols) { + for (const auto &I : Symbols) { + visitSymbolRecord(I); + if (hadError()) + break; + } + } + + /// Action to take on unknown symbols. By default, they are ignored. + void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data) {} + + /// Paired begin/end actions for all symbols. Receives all record data, + /// including the fixed-length record prefix. + void visitSymbolBegin(SymbolKind Leaf, ArrayRef<uint8_t> RecordData) {} + void visitSymbolEnd(SymbolKind Leaf, ArrayRef<uint8_t> OriginalSymData) {} + + /// Helper for returning from a void function when the stream is corrupted. + void parseError() { HadError = true; } + +private: + SymbolVisitorDelegate *Delegate; + /// Whether a symbol stream parsing error was encountered. + bool HadError = false; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h new file mode 100644 index 000000000000..930ac6930c24 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -0,0 +1,44 @@ +//===- CVTypeVisitor.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H + +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +class CVTypeVisitor { +public: + explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); + + Error visitTypeRecord(const CVRecord<TypeLeafKind> &Record); + + /// Visits the type records in Data. Sets the error flag on parse failures. + Error visitTypeStream(const CVTypeArray &Types); + + Error skipPadding(ArrayRef<uint8_t> &Data); + + /// Visits individual member records of a field list record. Member records do + /// not describe their own length, and need special handling. + Error visitFieldList(const CVRecord<TypeLeafKind> &Record); + +private: + /// The interface to the class that gets notified of each visitation. + TypeVisitorCallbacks &Callbacks; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index 7728120d68de..1ee203b4f8fa 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -11,10 +11,156 @@ #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEW_H #include <cinttypes> +#include <type_traits> namespace llvm { namespace codeview { +/// Distinguishes individual records in .debug$T section or PDB type stream. The +/// documentation and headers talk about this as the "leaf" type. +enum class TypeRecordKind : uint16_t { +#define TYPE_RECORD(lf_ename, value, name) name = value, +#include "TypeRecords.def" + // FIXME: Add serialization support + FieldList = 0x1203, +}; + +/// Duplicate copy of the above enum, but using the official CV names. Useful +/// for reference purposes and when dealing with unknown record types. +enum TypeLeafKind : uint16_t { +#define CV_TYPE(name, val) name = val, +#include "TypeRecords.def" +}; + +/// Distinguishes individual records in the Symbols subsection of a .debug$S +/// section. Equivalent to SYM_ENUM_e in cvinfo.h. +enum class SymbolRecordKind : uint16_t { +#define SYMBOL_RECORD(lf_ename, value, name) name = value, +#include "CVSymbolTypes.def" +}; + +/// Duplicate copy of the above enum, but using the official CV names. Useful +/// for reference purposes and when dealing with unknown record types. +enum SymbolKind : uint16_t { +#define CV_SYMBOL(name, val) name = val, +#include "CVSymbolTypes.def" +}; + +#define CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class) \ + inline Class operator|(Class a, Class b) { \ + return static_cast<Class>( \ + static_cast<std::underlying_type<Class>::type>(a) | \ + static_cast<std::underlying_type<Class>::type>(b)); \ + } \ + inline Class operator&(Class a, Class b) { \ + return static_cast<Class>( \ + static_cast<std::underlying_type<Class>::type>(a) & \ + static_cast<std::underlying_type<Class>::type>(b)); \ + } \ + inline Class operator~(Class a) { \ + return static_cast<Class>( \ + ~static_cast<std::underlying_type<Class>::type>(a)); \ + } \ + inline Class &operator|=(Class &a, Class b) { \ + a = a | b; \ + return a; \ + } \ + inline Class &operator&=(Class &a, Class b) { \ + a = a & b; \ + return a; \ + } + +/// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented +/// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx +enum class CPUType : uint16_t { + Intel8080 = 0x0, + Intel8086 = 0x1, + Intel80286 = 0x2, + Intel80386 = 0x3, + Intel80486 = 0x4, + Pentium = 0x5, + PentiumPro = 0x6, + Pentium3 = 0x7, + MIPS = 0x10, + MIPS16 = 0x11, + MIPS32 = 0x12, + MIPS64 = 0x13, + MIPSI = 0x14, + MIPSII = 0x15, + MIPSIII = 0x16, + MIPSIV = 0x17, + MIPSV = 0x18, + M68000 = 0x20, + M68010 = 0x21, + M68020 = 0x22, + M68030 = 0x23, + M68040 = 0x24, + Alpha = 0x30, + Alpha21164 = 0x31, + Alpha21164A = 0x32, + Alpha21264 = 0x33, + Alpha21364 = 0x34, + PPC601 = 0x40, + PPC603 = 0x41, + PPC604 = 0x42, + PPC620 = 0x43, + PPCFP = 0x44, + PPCBE = 0x45, + SH3 = 0x50, + SH3E = 0x51, + SH3DSP = 0x52, + SH4 = 0x53, + SHMedia = 0x54, + ARM3 = 0x60, + ARM4 = 0x61, + ARM4T = 0x62, + ARM5 = 0x63, + ARM5T = 0x64, + ARM6 = 0x65, + ARM_XMAC = 0x66, + ARM_WMMX = 0x67, + ARM7 = 0x68, + Omni = 0x70, + Ia64 = 0x80, + Ia64_2 = 0x81, + CEE = 0x90, + AM33 = 0xa0, + M32R = 0xb0, + TriCore = 0xc0, + X64 = 0xd0, + EBC = 0xe0, + Thumb = 0xf0, + ARMNT = 0xf4, + D3D11_Shader = 0x100, +}; + +/// These values correspond to the CV_CFL_LANG enumeration, and are documented +/// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx +enum SourceLanguage : uint8_t { + C = 0x00, + Cpp = 0x01, + Fortran = 0x02, + Masm = 0x03, + Pascal = 0x04, + Basic = 0x05, + Cobol = 0x06, + Link = 0x07, + Cvtres = 0x08, + Cvtpgd = 0x09, + CSharp = 0x0a, + VB = 0x0b, + ILAsm = 0x0c, + Java = 0x0d, + JScript = 0x0e, + MSIL = 0x0f, + HLSL = 0x10 +}; + +/// These values correspond to the CV_call_e enumeration, and are documented +/// at the following locations: +/// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx +/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680207(v=vs.85).aspx +/// enum class CallingConvention : uint8_t { NearC = 0x00, // near right to left push, caller pops stack FarC = 0x01, // far right to left push, caller pops stack @@ -58,20 +204,7 @@ enum class ClassOptions : uint16_t { Sealed = 0x0400, Intrinsic = 0x2000 }; - -inline ClassOptions operator|(ClassOptions a, ClassOptions b) { - return static_cast<ClassOptions>(static_cast<uint16_t>(a) | - static_cast<uint16_t>(b)); -} - -inline ClassOptions operator&(ClassOptions a, ClassOptions b) { - return static_cast<ClassOptions>(static_cast<uint16_t>(a) & - static_cast<uint16_t>(b)); -} - -inline ClassOptions operator~(ClassOptions a) { - return static_cast<ClassOptions>(~static_cast<uint16_t>(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ClassOptions) enum class FrameProcedureOptions : uint32_t { None = 0x00000000, @@ -95,22 +228,7 @@ enum class FrameProcedureOptions : uint32_t { GuardCfg = 0x00200000, GuardCfw = 0x00400000 }; - -inline FrameProcedureOptions operator|(FrameProcedureOptions a, - FrameProcedureOptions b) { - return static_cast<FrameProcedureOptions>(static_cast<uint32_t>(a) | - static_cast<uint32_t>(b)); -} - -inline FrameProcedureOptions operator&(FrameProcedureOptions a, - FrameProcedureOptions b) { - return static_cast<FrameProcedureOptions>(static_cast<uint32_t>(a) & - static_cast<uint32_t>(b)); -} - -inline FrameProcedureOptions operator~(FrameProcedureOptions a) { - return static_cast<FrameProcedureOptions>(~static_cast<uint32_t>(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FrameProcedureOptions) enum class FunctionOptions : uint8_t { None = 0x00, @@ -118,20 +236,7 @@ enum class FunctionOptions : uint8_t { Constructor = 0x02, ConstructorWithVirtualBases = 0x04 }; - -inline FunctionOptions operator|(FunctionOptions a, FunctionOptions b) { - return static_cast<FunctionOptions>(static_cast<uint8_t>(a) | - static_cast<uint8_t>(b)); -} - -inline FunctionOptions operator&(FunctionOptions a, FunctionOptions b) { - return static_cast<FunctionOptions>(static_cast<uint8_t>(a) & - static_cast<uint8_t>(b)); -} - -inline FunctionOptions operator~(FunctionOptions a) { - return static_cast<FunctionOptions>(~static_cast<uint8_t>(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FunctionOptions) enum class HfaKind : uint8_t { None = 0x00, @@ -140,6 +245,7 @@ enum class HfaKind : uint8_t { Other = 0x03 }; +/// Source-level access specifier. (CV_access_e) enum class MemberAccess : uint8_t { None = 0, Private = 1, @@ -147,6 +253,7 @@ enum class MemberAccess : uint8_t { Public = 3 }; +/// Part of member attribute flags. (CV_methodprop_e) enum class MethodKind : uint8_t { Vanilla = 0x00, Virtual = 0x01, @@ -157,49 +264,30 @@ enum class MethodKind : uint8_t { PureIntroducingVirtual = 0x06 }; +/// Equivalent to CV_fldattr_t bitfield. enum class MethodOptions : uint16_t { None = 0x0000, + AccessMask = 0x0003, + MethodKindMask = 0x001c, Pseudo = 0x0020, + NoInherit = 0x0040, + NoConstruct = 0x0080, CompilerGenerated = 0x0100, Sealed = 0x0200 }; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(MethodOptions) -inline MethodOptions operator|(MethodOptions a, MethodOptions b) { - return static_cast<MethodOptions>(static_cast<uint16_t>(a) | - static_cast<uint16_t>(b)); -} - -inline MethodOptions operator&(MethodOptions a, MethodOptions b) { - return static_cast<MethodOptions>(static_cast<uint16_t>(a) & - static_cast<uint16_t>(b)); -} - -inline MethodOptions operator~(MethodOptions a) { - return static_cast<MethodOptions>(~static_cast<uint16_t>(a)); -} - +/// Equivalent to CV_modifier_t. enum class ModifierOptions : uint16_t { None = 0x0000, Const = 0x0001, Volatile = 0x0002, Unaligned = 0x0004 }; - -inline ModifierOptions operator|(ModifierOptions a, ModifierOptions b) { - return static_cast<ModifierOptions>(static_cast<uint16_t>(a) | - static_cast<uint16_t>(b)); -} - -inline ModifierOptions operator&(ModifierOptions a, ModifierOptions b) { - return static_cast<ModifierOptions>(static_cast<uint16_t>(a) & - static_cast<uint16_t>(b)); -} - -inline ModifierOptions operator~(ModifierOptions a) { - return static_cast<ModifierOptions>(~static_cast<uint16_t>(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ModifierOptions) enum class ModuleSubstreamKind : uint32_t { + None = 0, Symbols = 0xf1, Lines = 0xf2, StringTable = 0xf3, @@ -207,9 +295,18 @@ enum class ModuleSubstreamKind : uint32_t { FrameData = 0xf5, InlineeLines = 0xf6, CrossScopeImports = 0xf7, - CrossScopeExports = 0xf8 + CrossScopeExports = 0xf8, + + // These appear to relate to .Net assembly info. + ILLines = 0xf9, + FuncMDTokenMap = 0xfa, + TypeMDTokenMap = 0xfb, + MergedAssemblyInput = 0xfc, + + CoffSymbolRVA = 0xfd, }; +/// Equivalent to CV_ptrtype_e. enum class PointerKind : uint8_t { Near16 = 0x00, // 16 bit pointer Far16 = 0x01, // 16:16 far pointer @@ -226,6 +323,7 @@ enum class PointerKind : uint8_t { Near64 = 0x0c // 64 bit pointer }; +/// Equivalent to CV_ptrmode_e. enum class PointerMode : uint8_t { Pointer = 0x00, // "normal" pointer LValueReference = 0x01, // "old" reference @@ -234,6 +332,7 @@ enum class PointerMode : uint8_t { RValueReference = 0x04 // r-value reference }; +/// Equivalent to misc lfPointerAttr bitfields. enum class PointerOptions : uint32_t { None = 0x00000000, Flat32 = 0x00000100, @@ -243,21 +342,9 @@ enum class PointerOptions : uint32_t { Restrict = 0x00001000, WinRTSmartPointer = 0x00080000 }; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(PointerOptions) -inline PointerOptions operator|(PointerOptions a, PointerOptions b) { - return static_cast<PointerOptions>(static_cast<uint16_t>(a) | - static_cast<uint16_t>(b)); -} - -inline PointerOptions operator&(PointerOptions a, PointerOptions b) { - return static_cast<PointerOptions>(static_cast<uint16_t>(a) & - static_cast<uint16_t>(b)); -} - -inline PointerOptions operator~(PointerOptions a) { - return static_cast<PointerOptions>(~static_cast<uint16_t>(a)); -} - +/// Equivalent to CV_pmtype_e. enum class PointerToMemberRepresentation : uint16_t { Unknown = 0x00, // not specified (pre VC8) SingleInheritanceData = 0x01, // member data, single inheritance @@ -270,82 +357,7 @@ enum class PointerToMemberRepresentation : uint16_t { GeneralFunction = 0x08 // member function, most general }; -enum class TypeRecordKind : uint16_t { - None = 0, - - VirtualTableShape = 0x000a, - Label = 0x000e, - EndPrecompiledHeader = 0x0014, - - Modifier = 0x1001, - Pointer = 0x1002, - Procedure = 0x1008, - MemberFunction = 0x1009, - - Oem = 0x100f, - Oem2 = 0x1011, - - ArgumentList = 0x1201, - FieldList = 0x1203, - BitField = 0x1205, - MethodList = 0x1206, - - BaseClass = 0x1400, - VirtualBaseClass = 0x1401, - IndirectVirtualBaseClass = 0x1402, - Index = 0x1404, - VirtualFunctionTablePointer = 0x1409, - - Enumerate = 0x1502, - Array = 0x1503, - Class = 0x1504, - Structure = 0x1505, - Union = 0x1506, - Enum = 0x1507, - Alias = 0x150a, - Member = 0x150d, - StaticMember = 0x150e, - Method = 0x150f, - NestedType = 0x1510, - OneMethod = 0x1511, - VirtualFunctionTable = 0x151d, - - FunctionId = 0x1601, - MemberFunctionId = 0x1602, - BuildInfo = 0x1603, - SubstringList = 0x1604, - StringId = 0x1605, - UdtSourceLine = 0x1606, - - SByte = 0x8000, - Int16 = 0x8001, - UInt16 = 0x8002, - Int32 = 0x8003, - UInt32 = 0x8004, - Single = 0x8005, - Double = 0x8006, - Float80 = 0x8007, - Float128 = 0x8008, - Int64 = 0x8009, - UInt64 = 0x800a, - Float48 = 0x800b, - Complex32 = 0x800c, - Complex64 = 0x800d, - Complex80 = 0x800e, - Complex128 = 0x800f, - VarString = 0x8010, - - Int128 = 0x8017, - UInt128 = 0x8018, - - Decimal = 0x8019, - Date = 0x801a, - Utf8String = 0x801b, - - Float16 = 0x801c -}; - -enum class VirtualTableSlotKind : uint8_t { +enum class VFTableSlotKind : uint8_t { Near16 = 0x00, Far16 = 0x01, This = 0x02, @@ -361,6 +373,177 @@ enum class WindowsRTClassKind : uint8_t { ValueClass = 0x02, Interface = 0x03 }; + +/// Corresponds to CV_LVARFLAGS bitfield. +enum class LocalSymFlags : uint16_t { + None = 0, + IsParameter = 1 << 0, + IsAddressTaken = 1 << 1, + IsCompilerGenerated = 1 << 2, + IsAggregate = 1 << 3, + IsAggregated = 1 << 4, + IsAliased = 1 << 5, + IsAlias = 1 << 6, + IsReturnValue = 1 << 7, + IsOptimizedOut = 1 << 8, + IsEnregisteredGlobal = 1 << 9, + IsEnregisteredStatic = 1 << 10, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(LocalSymFlags) + +/// Corresponds to the CV_PROCFLAGS bitfield. +enum class ProcSymFlags : uint8_t { + None = 0, + HasFP = 1 << 0, + HasIRET = 1 << 1, + HasFRET = 1 << 2, + IsNoReturn = 1 << 3, + IsUnreachable = 1 << 4, + HasCustomCallingConv = 1 << 5, + IsNoInline = 1 << 6, + HasOptimizedDebugInfo = 1 << 7, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ProcSymFlags) + +/// Corresponds to COMPILESYM2::Flags bitfield. +enum class CompileSym2Flags : uint32_t { + EC = 1 << 8, + NoDbgInfo = 1 << 9, + LTCG = 1 << 10, + NoDataAlign = 1 << 11, + ManagedPresent = 1 << 12, + SecurityChecks = 1 << 13, + HotPatch = 1 << 14, + CVTCIL = 1 << 15, + MSILModule = 1 << 16, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym2Flags) + +/// Corresponds to COMPILESYM3::Flags bitfield. +enum class CompileSym3Flags : uint32_t { + EC = 1 << 8, + NoDbgInfo = 1 << 9, + LTCG = 1 << 10, + NoDataAlign = 1 << 11, + ManagedPresent = 1 << 12, + SecurityChecks = 1 << 13, + HotPatch = 1 << 14, + CVTCIL = 1 << 15, + MSILModule = 1 << 16, + Sdl = 1 << 17, + PGO = 1 << 18, + Exp = 1 << 19, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym3Flags) + +enum class ExportFlags : uint16_t { + IsConstant = 1 << 0, + IsData = 1 << 1, + IsPrivate = 1 << 2, + HasNoName = 1 << 3, + HasExplicitOrdinal = 1 << 4, + IsForwarder = 1 << 5 +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ExportFlags) + +// Corresponds to BinaryAnnotationOpcode enum. +enum class BinaryAnnotationsOpCode : uint32_t { + Invalid, + CodeOffset, + ChangeCodeOffsetBase, + ChangeCodeOffset, + ChangeCodeLength, + ChangeFile, + ChangeLineOffset, + ChangeLineEndDelta, + ChangeRangeKind, + ChangeColumnStart, + ChangeColumnEndDelta, + ChangeCodeOffsetAndLineOffset, + ChangeCodeLengthAndCodeOffset, + ChangeColumnEnd, +}; + +// Corresponds to CV_cookietype_e enum. +enum class FrameCookieKind : uint8_t { + Copy, + XorStackPointer, + XorFramePointer, + XorR13, +}; + +// Corresponds to CV_HREG_e enum. +enum class RegisterId : uint16_t { + Unknown = 0, + VFrame = 30006, + AL = 1, + CL = 2, + DL = 3, + BL = 4, + AH = 5, + CH = 6, + DH = 7, + BH = 8, + AX = 9, + CX = 10, + DX = 11, + BX = 12, + SP = 13, + BP = 14, + SI = 15, + DI = 16, + EAX = 17, + ECX = 18, + EDX = 19, + EBX = 20, + ESP = 21, + EBP = 22, + ESI = 23, + EDI = 24, + ES = 25, + CS = 26, + SS = 27, + DS = 28, + FS = 29, + GS = 30, + IP = 31, + RAX = 328, + RBX = 329, + RCX = 330, + RDX = 331, + RSI = 332, + RDI = 333, + RBP = 334, + RSP = 335, + R8 = 336, + R9 = 337, + R10 = 338, + R11 = 339, + R12 = 340, + R13 = 341, + R14 = 342, + R15 = 343, +}; + +/// These values correspond to the THUNK_ORDINAL enumeration. +enum class ThunkOrdinal { + Standard, + ThisAdjustor, + Vcall, + Pcode, + UnknownLoad, + TrampIncremental, + BranchIsland +}; + +enum class TrampolineType { TrampIncremental, BranchIsland }; + +// These values correspond to the CV_SourceChksum_t enumeration. +enum class FileChecksumKind : uint8_t { None, MD5, SHA1, SHA256 }; + +enum LineFlags : uint32_t { + HaveColumns = 1, // CV_LINES_HAVE_COLUMNS +}; } } diff --git a/include/llvm/DebugInfo/CodeView/CodeViewError.h b/include/llvm/DebugInfo/CodeView/CodeViewError.h new file mode 100644 index 000000000000..69ff29aab6f1 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CodeViewError.h @@ -0,0 +1,44 @@ +//===- CodeViewError.h - Error extensions for CodeView ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H +#define LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H + +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace codeview { +enum class cv_error_code { + unspecified = 1, + insufficient_buffer, + operation_unsupported, + corrupt_record, +}; + +/// Base class for errors originating when parsing raw PDB files +class CodeViewError : public ErrorInfo<CodeViewError> { +public: + static char ID; + CodeViewError(cv_error_code C); + CodeViewError(const std::string &Context); + CodeViewError(cv_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + cv_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/CodeView/EnumTables.h b/include/llvm/DebugInfo/CodeView/EnumTables.h new file mode 100644 index 000000000000..021288e57618 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/EnumTables.h @@ -0,0 +1,42 @@ +//===- EnumTables.h Enum to string conversion tables ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H +#define LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include <stdint.h> + +namespace llvm { +namespace codeview { +ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames(); +ArrayRef<EnumEntry<uint16_t>> getRegisterNames(); +ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames(); +ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames(); +ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames(); +ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames(); +ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames(); +ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames(); +ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames(); +ArrayRef<EnumEntry<unsigned>> getCPUTypeNames(); +ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames(); +ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames(); +ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames(); +ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames(); +ArrayRef<EnumEntry<uint16_t>> getTrampolineNames(); +ArrayRef<EnumEntry<COFF::SectionCharacteristics>> +getImageSectionCharacteristicNames(); +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H diff --git a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h index 1ed62487aecc..75a075157d22 100644 --- a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" namespace llvm { namespace codeview { @@ -46,31 +47,17 @@ private: public: FieldListRecordBuilder(); - void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset); - void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name); - void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset, - StringRef Name); - void writeOneMethod(MemberAccess Access, MethodKind Kind, - MethodOptions Options, TypeIndex Type, - int32_t VTableSlotOffset, StringRef Name); - void writeOneMethod(const MethodInfo &Method, StringRef Name); - void writeMethod(uint16_t OverloadCount, TypeIndex MethodList, - StringRef Name); - void writeNestedType(TypeIndex Type, StringRef Name); - void writeStaticMember(MemberAccess Access, TypeIndex Type, StringRef Name); - void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access, - TypeIndex Type, TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualFunctionTablePointer(TypeIndex Type); + void reset() { ListRecordBuilder::reset(); } + + void writeBaseClass(const BaseClassRecord &Record); + void writeEnumerator(const EnumeratorRecord &Record); + void writeDataMember(const DataMemberRecord &Record); + void writeOneMethod(const OneMethodRecord &Record); + void writeOverloadedMethod(const OverloadedMethodRecord &Record); + void writeNestedType(const NestedTypeRecord &Record); + void writeStaticDataMember(const StaticDataMemberRecord &Record); + void writeVirtualBaseClass(const VirtualBaseClassRecord &Record); + void writeVFPtr(const VFPtrRecord &Type); }; } } diff --git a/include/llvm/DebugInfo/CodeView/Line.h b/include/llvm/DebugInfo/CodeView/Line.h index a7cdbdaac32f..975b503fe30b 100644 --- a/include/llvm/DebugInfo/CodeView/Line.h +++ b/include/llvm/DebugInfo/CodeView/Line.h @@ -10,24 +10,32 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_LINE_H #define LLVM_DEBUGINFO_CODEVIEW_LINE_H +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Endian.h" #include <cinttypes> namespace llvm { namespace codeview { +using llvm::support::ulittle32_t; + class LineInfo { public: - static const uint32_t AlwaysStepIntoLineNumber = 0xfeefee; - static const uint32_t NeverStepIntoLineNumber = 0xf00f00; + enum : uint32_t { + AlwaysStepIntoLineNumber = 0xfeefee, + NeverStepIntoLineNumber = 0xf00f00 + }; -private: - static const uint32_t StartLineMask = 0x00ffffff; - static const uint32_t EndLineDeltaMask = 0x7f000000; - static const int EndLineDeltaShift = 24; - static const uint32_t StatementFlag = 0x80000000u; + enum : int { EndLineDeltaShift = 24 }; + + enum : uint32_t { + StartLineMask = 0x00ffffff, + EndLineDeltaMask = 0x7f000000, + StatementFlag = 0x80000000u + }; -public: LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement); + LineInfo(uint32_t LineData) : LineData(LineData) {} uint32_t getStartLine() const { return LineData & StartLineMask; } @@ -118,7 +126,29 @@ public: bool isNeverStepInto() const { return LineInf.isNeverStepInto(); } }; -} -} + +enum class InlineeLinesSignature : uint32_t { + Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE + ExtraFiles // CV_INLINEE_SOURCE_LINE_SIGNATURE_EX +}; + +struct InlineeSourceLine { + TypeIndex Inlinee; // ID of the function that was inlined. + ulittle32_t FileID; // Offset into FileChecksums subsection. + ulittle32_t SourceLineNum; // First line of inlined code. + // If extra files present: + // ulittle32_t ExtraFileCount; + // ulittle32_t Files[]; +}; + +struct FileChecksum { + ulittle32_t FileNameOffset; // Byte offset of filename in global string table. + uint8_t ChecksumSize; // Number of bytes of checksum. + uint8_t ChecksumKind; // FileChecksumKind + // Checksum bytes follow. +}; + +} // namespace codeview +} // namespace llvm #endif diff --git a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h index df0a2e08a418..00bf03d417a2 100644 --- a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h @@ -14,6 +14,7 @@ namespace llvm { namespace codeview { +class TypeTableBuilder; class ListRecordBuilder { private: @@ -28,14 +29,35 @@ protected: public: llvm::StringRef str() { return Builder.str(); } + void reset() { + Builder.reset(Kind); + ContinuationOffsets.clear(); + SubrecordStart = 0; + } + + void writeListContinuation(const ListContinuationRecord &R); + + /// Writes this list record as a possible sequence of records. + TypeIndex writeListRecord(TypeTableBuilder &Table); + protected: void finishSubRecord(); TypeRecordBuilder &getBuilder() { return Builder; } private: + size_t getLastContinuationStart() const { + return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back(); + } + size_t getLastContinuationEnd() const { return Builder.size(); } + size_t getLastContinuationSize() const { + return getLastContinuationEnd() - getLastContinuationStart(); + } + + TypeRecordKind Kind; TypeRecordBuilder Builder; SmallVector<size_t, 4> ContinuationOffsets; + size_t SubrecordStart = 0; }; } } diff --git a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h index 5bfe2a068672..002f885c7c5a 100644 --- a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h @@ -10,12 +10,9 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H -#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include <functional> -#include <memory> -#include <unordered_map> #include <vector> namespace llvm { @@ -23,46 +20,29 @@ namespace codeview { class MemoryTypeTableBuilder : public TypeTableBuilder { public: - class Record { - public: - explicit Record(llvm::StringRef RData); - - const char *data() const { return Data.get(); } - uint16_t size() const { return Size; } - - private: - uint16_t Size; - std::unique_ptr<char[]> Data; - }; - -private: - class RecordHash : std::unary_function<llvm::StringRef, size_t> { - public: - size_t operator()(llvm::StringRef Val) const { - return static_cast<size_t>(llvm::hash_value(Val)); - } - }; - -public: MemoryTypeTableBuilder() {} + bool empty() const { return Records.empty(); } + template <typename TFunc> void ForEachRecord(TFunc Func) { uint32_t Index = TypeIndex::FirstNonSimpleIndex; - for (const std::unique_ptr<Record> &R : Records) { - Func(TypeIndex(Index), R.get()); + for (StringRef R : Records) { + Func(TypeIndex(Index), R); ++Index; } } -private: - virtual TypeIndex writeRecord(llvm::StringRef Data) override; +protected: + TypeIndex writeRecord(llvm::StringRef Data) override; private: - std::vector<std::unique_ptr<Record>> Records; - std::unordered_map<llvm::StringRef, TypeIndex, RecordHash> HashedRecords; + std::vector<StringRef> Records; + BumpPtrAllocator RecordStorage; + DenseMap<StringRef, TypeIndex> HashedRecords; }; -} -} -#endif +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h new file mode 100644 index 000000000000..6affac801d4d --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -0,0 +1,87 @@ +//===- ModuleSubstream.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +// Corresponds to the `CV_DebugSSubsectionHeader_t` structure. +struct ModuleSubsectionHeader { + support::ulittle32_t Kind; // codeview::ModuleSubstreamKind enum + support::ulittle32_t Length; // number of bytes occupied by this record. +}; + +// Corresponds to the `CV_DebugSLinesHeader_t` structure. +struct LineSubstreamHeader { + support::ulittle32_t RelocOffset; // Code offset of line contribution. + support::ulittle16_t RelocSegment; // Code segment of line contribution. + support::ulittle16_t Flags; // See LineFlags enumeration. + support::ulittle32_t CodeSize; // Code size of this line contribution. +}; + +// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure. +struct LineFileBlockHeader { + support::ulittle32_t NameIndex; // Index in DBI name buffer of filename. + support::ulittle32_t NumLines; // Number of lines + support::ulittle32_t BlockSize; // Code size of block, in bytes. + // The following two variable length arrays appear immediately after the + // header. The structure definitions follow. + // LineNumberEntry Lines[NumLines]; + // ColumnNumberEntry Columns[NumLines]; +}; + +// Corresponds to `CV_Line_t` structure +struct LineNumberEntry { + support::ulittle32_t Offset; // Offset to start of code bytes for line number + support::ulittle32_t Flags; // Start:24, End:7, IsStatement:1 +}; + +// Corresponds to `CV_Column_t` structure +struct ColumnNumberEntry { + support::ulittle16_t StartColumn; + support::ulittle16_t EndColumn; +}; + +class ModuleSubstream { +public: + ModuleSubstream(); + ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data); + static Error initialize(StreamRef Stream, ModuleSubstream &Info); + uint32_t getRecordLength() const; + ModuleSubstreamKind getSubstreamKind() const; + StreamRef getRecordData() const; + +private: + ModuleSubstreamKind Kind; + StreamRef Data; +}; + +template <> struct VarStreamArrayExtractor<ModuleSubstream> { + Error operator()(StreamRef Stream, uint32_t &Length, + ModuleSubstream &Info) const { + if (auto EC = ModuleSubstream::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; + +typedef VarStreamArray<ModuleSubstream> ModuleSubstreamArray; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h new file mode 100644 index 000000000000..6df230903712 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -0,0 +1,121 @@ +//===- ModuleSubstreamVisitor.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" + +namespace llvm { +namespace codeview { + +struct LineColumnEntry { + support::ulittle32_t NameIndex; + FixedStreamArray<LineNumberEntry> LineNumbers; + FixedStreamArray<ColumnNumberEntry> Columns; +}; + +template <> class VarStreamArrayExtractor<LineColumnEntry> { +public: + VarStreamArrayExtractor(const LineSubstreamHeader *Header) : Header(Header) {} + + Error operator()(StreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) const { + const LineFileBlockHeader *BlockHeader; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(BlockHeader)) + return EC; + bool HasColumn = Header->Flags & LineFlags::HaveColumns; + uint32_t LineInfoSize = + BlockHeader->NumLines * + (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); + if (BlockHeader->BlockSize < sizeof(LineFileBlockHeader)) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader); + if (LineInfoSize > Size) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + // The value recorded in BlockHeader->BlockSize includes the size of + // LineFileBlockHeader. + Len = BlockHeader->BlockSize; + Item.NameIndex = BlockHeader->NameIndex; + if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) + return EC; + if (HasColumn) { + if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) + return EC; + } + return Error::success(); + } + +private: + const LineSubstreamHeader *Header; +}; + +struct FileChecksumEntry { + uint32_t FileNameOffset; // Byte offset of filename in global stringtable. + FileChecksumKind Kind; // The type of checksum. + ArrayRef<uint8_t> Checksum; // The bytes of the checksum. +}; + +template <> class VarStreamArrayExtractor<FileChecksumEntry> { +public: + Error operator()(StreamRef Stream, uint32_t &Len, + FileChecksumEntry &Item) const { + const FileChecksum *Header; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(Header)) + return EC; + Item.FileNameOffset = Header->FileNameOffset; + Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind); + if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize)) + return EC; + Len = sizeof(FileChecksum) + Header->ChecksumSize; + return Error::success(); + } +}; + +typedef VarStreamArray<LineColumnEntry> LineInfoArray; +typedef VarStreamArray<FileChecksumEntry> FileChecksumArray; + +class IModuleSubstreamVisitor { +public: + virtual ~IModuleSubstreamVisitor() {} + + virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0; + virtual Error visitSymbols(StreamRef Data); + virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + const LineInfoArray &Lines); + virtual Error visitStringTable(StreamRef Data); + virtual Error visitFileChecksums(StreamRef Data, + const FileChecksumArray &Checksums); + virtual Error visitFrameData(StreamRef Data); + virtual Error visitInlineeLines(StreamRef Data); + virtual Error visitCrossScopeImports(StreamRef Data); + virtual Error visitCrossScopeExports(StreamRef Data); + virtual Error visitILLines(StreamRef Data); + virtual Error visitFuncMDTokenMap(StreamRef Data); + virtual Error visitTypeMDTokenMap(StreamRef Data); + virtual Error visitMergedAssemblyInput(StreamRef Data); + virtual Error visitCoffSymbolRVA(StreamRef Data); +}; + +Error visitModuleSubstream(const ModuleSubstream &R, + IModuleSubstreamVisitor &V); + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/RecordSerialization.h b/include/llvm/DebugInfo/CodeView/RecordSerialization.h new file mode 100644 index 000000000000..84179f5f81f7 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/RecordSerialization.h @@ -0,0 +1,278 @@ +//===- RecordSerialization.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include <cinttypes> +#include <tuple> + +namespace llvm { +namespace codeview { +using llvm::support::little32_t; +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; + +struct RecordPrefix { + ulittle16_t RecordLen; // Record length, starting from &Leaf. + ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind) +}; + +/// Reinterpret a byte array as an array of characters. Does not interpret as +/// a C string, as StringRef has several helpers (split) that make that easy. +StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData); +StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData); + +/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if +/// there are not enough bytes remaining. Reinterprets the consumed bytes as a +/// T object and points 'Res' at them. +template <typename T, typename U> +inline std::error_code consumeObject(U &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return std::make_error_code(std::errc::illegal_byte_sequence); + Res = reinterpret_cast<const T *>(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return std::error_code(); +} + +inline std::error_code consume(ArrayRef<uint8_t> &Data) { + return std::error_code(); +} + +/// Decodes a numeric "leaf" value. These are integer literals encountered in +/// the type stream. If the value is positive and less than LF_NUMERIC (1 << +/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR +/// that indicates the bitwidth and sign of the numeric data. +std::error_code consume(ArrayRef<uint8_t> &Data, APSInt &Num); +std::error_code consume(StringRef &Data, APSInt &Num); + +/// Decodes a numeric leaf value that is known to be a particular type. +std::error_code consume_numeric(ArrayRef<uint8_t> &Data, uint64_t &Value); + +/// Decodes signed and unsigned fixed-length integers. +std::error_code consume(ArrayRef<uint8_t> &Data, uint32_t &Item); +std::error_code consume(StringRef &Data, uint32_t &Item); +std::error_code consume(ArrayRef<uint8_t> &Data, int32_t &Item); + +/// Decodes a null terminated string. +std::error_code consume(ArrayRef<uint8_t> &Data, StringRef &Item); + +/// Decodes an arbitrary object whose layout matches that of the underlying +/// byte sequence, and returns a pointer to the object. +template <typename T> +std::error_code consume(ArrayRef<uint8_t> &Data, T *&Item) { + return consumeObject(Data, Item); +} + +template <typename T, typename U> struct serialize_conditional_impl { + serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + if (!Func()) + return std::error_code(); + return consume(Data, Item); + } + + T &Item; + U Func; +}; + +template <typename T, typename U> +serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) { + return serialize_conditional_impl<T, U>(Item, Func); +} + +template <typename T, typename U> struct serialize_array_impl { + serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + uint32_t N = Func(); + if (N == 0) + return std::error_code(); + + uint32_t Size = sizeof(T) * N; + + if (Size / sizeof(T) != N) + return std::make_error_code(std::errc::illegal_byte_sequence); + + if (Data.size() < Size) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.data()), N); + Data = Data.drop_front(Size); + return std::error_code(); + } + + ArrayRef<T> &Item; + U Func; +}; + +template <typename T> struct serialize_vector_tail_impl { + serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + T Field; + // Stop when we run out of bytes or we hit record padding bytes. + while (!Data.empty() && Data.front() < LF_PAD0) { + if (auto EC = consume(Data, Field)) + return EC; + Item.push_back(Field); + } + return std::error_code(); + } + + std::vector<T> &Item; +}; + +struct serialize_null_term_string_array_impl { + serialize_null_term_string_array_impl(std::vector<StringRef> &Item) + : Item(Item) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + StringRef Field; + // Stop when we run out of bytes or we hit record padding bytes. + while (Data.front() != 0) { + if (auto EC = consume(Data, Field)) + return EC; + Item.push_back(Field); + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + } + Data = Data.drop_front(1); + return std::error_code(); + } + + std::vector<StringRef> &Item; +}; + +template <typename T> struct serialize_arrayref_tail_impl { + serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + uint32_t Count = Data.size() / sizeof(T); + Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.begin()), Count); + return std::error_code(); + } + + ArrayRef<T> &Item; +}; + +template <typename T> struct serialize_numeric_impl { + serialize_numeric_impl(T &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef<uint8_t> &Data) const { + return consume_numeric(Data, Item); + } + + T &Item; +}; + +template <typename T, typename U> +serialize_array_impl<T, U> serialize_array(ArrayRef<T> &Item, U Func) { + return serialize_array_impl<T, U>(Item, Func); +} + +inline serialize_null_term_string_array_impl +serialize_null_term_string_array(std::vector<StringRef> &Item) { + return serialize_null_term_string_array_impl(Item); +} + +template <typename T> +serialize_vector_tail_impl<T> serialize_array_tail(std::vector<T> &Item) { + return serialize_vector_tail_impl<T>(Item); +} + +template <typename T> +serialize_arrayref_tail_impl<T> serialize_array_tail(ArrayRef<T> &Item) { + return serialize_arrayref_tail_impl<T>(Item); +} + +template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) { + return serialize_numeric_impl<T>(Item); +} + +// This field is only present in the byte record if the condition is true. The +// condition is evaluated lazily, so it can depend on items that were +// deserialized +// earlier. +#define CV_CONDITIONAL_FIELD(I, C) \ + serialize_conditional(I, [&]() { return !!(C); }) + +// This is an array of N items, where N is evaluated lazily, so it can refer +// to a field deserialized earlier. +#define CV_ARRAY_FIELD_N(I, N) serialize_array(I, [&]() { return N; }) + +// This is an array that exhausts the remainder of the input buffer. +#define CV_ARRAY_FIELD_TAIL(I) serialize_array_tail(I) + +// This is an array that consumes null terminated strings until a double null +// is encountered. +#define CV_STRING_ARRAY_NULL_TERM(I) serialize_null_term_string_array(I) + +#define CV_NUMERIC_FIELD(I) serialize_numeric(I) + +template <typename T, typename U> +std::error_code consume(ArrayRef<uint8_t> &Data, + const serialize_conditional_impl<T, U> &Item) { + return Item.deserialize(Data); +} + +template <typename T, typename U> +std::error_code consume(ArrayRef<uint8_t> &Data, + const serialize_array_impl<T, U> &Item) { + return Item.deserialize(Data); +} + +inline std::error_code +consume(ArrayRef<uint8_t> &Data, + const serialize_null_term_string_array_impl &Item) { + return Item.deserialize(Data); +} + +template <typename T> +std::error_code consume(ArrayRef<uint8_t> &Data, + const serialize_vector_tail_impl<T> &Item) { + return Item.deserialize(Data); +} + +template <typename T> +std::error_code consume(ArrayRef<uint8_t> &Data, + const serialize_arrayref_tail_impl<T> &Item) { + return Item.deserialize(Data); +} + +template <typename T> +std::error_code consume(ArrayRef<uint8_t> &Data, + const serialize_numeric_impl<T> &Item) { + return Item.deserialize(Data); +} + +template <typename T, typename U, typename... Args> +std::error_code consume(ArrayRef<uint8_t> &Data, T &&X, U &&Y, + Args &&... Rest) { + if (auto EC = consume(Data, X)) + return EC; + return consume(Data, Y, std::forward<Args>(Rest)...); +} + +#define CV_DESERIALIZE(...) \ + if (auto EC = consume(__VA_ARGS__)) \ + return EC; +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/StreamArray.h b/include/llvm/DebugInfo/CodeView/StreamArray.h new file mode 100644 index 000000000000..0b9349aac753 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamArray.h @@ -0,0 +1,275 @@ +//===- StreamArray.h - Array backed by an arbitrary stream ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H + +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Error.h" + +#include <functional> +#include <type_traits> + +namespace llvm { +namespace codeview { + +/// VarStreamArrayExtractor is intended to be specialized to provide customized +/// extraction logic. On input it receives a StreamRef pointing to the +/// beginning of the next record, but where the length of the record is not yet +/// known. Upon completion, it should return an appropriate Error instance if +/// a record could not be extracted, or if one could be extracted it should +/// return success and set Len to the number of bytes this record occupied in +/// the underlying stream, and it should fill out the fields of the value type +/// Item appropriately to represent the current record. +/// +/// You can specialize this template for your own custom value types to avoid +/// having to specify a second template argument to VarStreamArray (documented +/// below). +template <typename T> struct VarStreamArrayExtractor { + // Method intentionally deleted. You must provide an explicit specialization + // with the following method implemented. + Error operator()(StreamRef Stream, uint32_t &Len, T &Item) const = delete; +}; + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. Elements are parsed +/// lazily on iteration, so there is no upfront cost associated with building +/// a VarStreamArray, no matter how large it may be. +/// +/// You create a VarStreamArray by specifying a ValueType and an Extractor type. +/// If you do not specify an Extractor type, it expects you to specialize +/// VarStreamArrayExtractor<T> for your ValueType. +/// +/// By default an Extractor is default constructed in the class, but in some +/// cases you might find it useful for an Extractor to maintain state across +/// extractions. In this case you can provide your own Extractor through a +/// secondary constructor. The following examples show various ways of +/// creating a VarStreamArray. +/// +/// // Will use VarStreamArrayExtractor<MyType> as the extractor. +/// VarStreamArray<MyType> MyTypeArray; +/// +/// // Will use a default-constructed MyExtractor as the extractor. +/// VarStreamArray<MyType, MyExtractor> MyTypeArray2; +/// +/// // Will use the specific instance of MyExtractor provided. +/// // MyExtractor need not be default-constructible in this case. +/// MyExtractor E(SomeContext); +/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E); +/// +template <typename ValueType, typename Extractor> class VarStreamArrayIterator; + +template <typename ValueType, + typename Extractor = VarStreamArrayExtractor<ValueType>> +class VarStreamArray { + friend class VarStreamArrayIterator<ValueType, Extractor>; + +public: + typedef VarStreamArrayIterator<ValueType, Extractor> Iterator; + + VarStreamArray() {} + explicit VarStreamArray(const Extractor &E) : E(E) {} + + explicit VarStreamArray(StreamRef Stream) : Stream(Stream) {} + VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {} + + VarStreamArray(const VarStreamArray<ValueType, Extractor> &Other) + : Stream(Other.Stream), E(Other.E) {} + + Iterator begin(bool *HadError = nullptr) const { + return Iterator(*this, E, HadError); + } + + Iterator end() const { return Iterator(E); } + + const Extractor &getExtractor() const { return E; } + + StreamRef getUnderlyingStream() const { return Stream; } + +private: + StreamRef Stream; + Extractor E; +}; + +template <typename ValueType, typename Extractor> class VarStreamArrayIterator { + typedef VarStreamArrayIterator<ValueType, Extractor> IterType; + typedef VarStreamArray<ValueType, Extractor> ArrayType; + +public: + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError = nullptr) + : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) { + if (IterRef.getLength() == 0) + moveToEnd(); + else { + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } + } + } + VarStreamArrayIterator() {} + explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} + ~VarStreamArrayIterator() {} + + bool operator==(const IterType &R) const { + if (Array && R.Array) { + // Both have a valid array, make sure they're same. + assert(Array == R.Array); + return IterRef == R.IterRef; + } + + // Both iterators are at the end. + if (!Array && !R.Array) + return true; + + // One is not at the end and one is. + return false; + } + + bool operator!=(const IterType &R) { return !(*this == R); } + + const ValueType &operator*() const { + assert(Array && !HasError); + return ThisValue; + } + + IterType &operator++() { + // We are done with the current record, discard it so that we are + // positioned at the next record. + IterRef = IterRef.drop_front(ThisLen); + if (IterRef.getLength() == 0) { + // There is nothing after the current record, we must make this an end + // iterator. + moveToEnd(); + } else { + // There is some data after the current record. + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } else if (ThisLen == 0) { + // An empty record? Make this an end iterator. + moveToEnd(); + } + } + return *this; + } + + IterType operator++(int) { + IterType Original = *this; + ++*this; + return Original; + } + +private: + void moveToEnd() { + Array = nullptr; + ThisLen = 0; + } + void markError() { + moveToEnd(); + HasError = true; + if (HadError != nullptr) + *HadError = true; + } + + ValueType ThisValue; + StreamRef IterRef; + const ArrayType *Array{nullptr}; + uint32_t ThisLen{0}; + bool HasError{false}; + bool *HadError{nullptr}; + Extractor Extract; +}; + +template <typename T> class FixedStreamArrayIterator; + +template <typename T> class FixedStreamArray { + friend class FixedStreamArrayIterator<T>; + +public: + FixedStreamArray() : Stream() {} + FixedStreamArray(StreamRef Stream) : Stream(Stream) { + assert(Stream.getLength() % sizeof(T) == 0); + } + + const T &operator[](uint32_t Index) const { + assert(Index < size()); + uint32_t Off = Index * sizeof(T); + ArrayRef<uint8_t> Data; + if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) { + assert(false && "Unexpected failure reading from stream"); + // This should never happen since we asserted that the stream length was + // an exact multiple of the element size. + consumeError(std::move(EC)); + } + return *reinterpret_cast<const T *>(Data.data()); + } + + uint32_t size() const { return Stream.getLength() / sizeof(T); } + + FixedStreamArrayIterator<T> begin() const { + return FixedStreamArrayIterator<T>(*this, 0); + } + FixedStreamArrayIterator<T> end() const { + return FixedStreamArrayIterator<T>(*this, size()); + } + + StreamRef getUnderlyingStream() const { return Stream; } + +private: + StreamRef Stream; +}; + +template <typename T> class FixedStreamArrayIterator { +public: + FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index) + : Array(Array), Index(Index) {} + + bool operator==(const FixedStreamArrayIterator<T> &R) { + assert(&Array == &R.Array); + return Index == R.Index; + } + + bool operator!=(const FixedStreamArrayIterator<T> &R) { + return !(*this == R); + } + + const T &operator*() const { return Array[Index]; } + + FixedStreamArrayIterator<T> &operator++() { + assert(Index < Array.size()); + ++Index; + return *this; + } + + FixedStreamArrayIterator<T> operator++(int) { + FixedStreamArrayIterator<T> Original = *this; + ++*this; + return Original; + } + +private: + const FixedStreamArray<T> &Array; + uint32_t Index; +}; + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H diff --git a/include/llvm/DebugInfo/CodeView/StreamInterface.h b/include/llvm/DebugInfo/CodeView/StreamInterface.h new file mode 100644 index 000000000000..241aec457870 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamInterface.h @@ -0,0 +1,55 @@ +//===- StreamInterface.h - Base interface for a stream of data --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { +namespace codeview { + +/// StreamInterface abstracts the notion of a data stream. This way, an +/// implementation could implement trivial reading from a contiguous memory +/// buffer or, as in the case of PDB files, reading from a set of possibly +/// discontiguous blocks. The implementation is required to return references +/// to stable memory, so if this is not possible (for example in the case of +/// a PDB file with discontiguous blocks, it must keep its own pool of temp +/// storage. +class StreamInterface { +public: + virtual ~StreamInterface() {} + + // Given an offset into the stream and a number of bytes, attempt to read + // the bytes and set the output ArrayRef to point to a reference into the + // stream, without copying any data. + virtual Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const = 0; + + // Given an offset into the stream, read as much as possible without copying + // any data. + virtual Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) const = 0; + + // Attempt to write the given bytes into the stream at the desired offset. + // This will always necessitate a copy. Cannot shrink or grow the stream, + // only writes into existing allocated space. + virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const = 0; + + virtual uint32_t getLength() const = 0; + + virtual Error commit() const = 0; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H diff --git a/include/llvm/DebugInfo/CodeView/StreamReader.h b/include/llvm/DebugInfo/CodeView/StreamReader.h new file mode 100644 index 000000000000..2f497c2c43f1 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamReader.h @@ -0,0 +1,111 @@ +//===- StreamReader.h - Reads bytes and objects from a stream ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace codeview { + +class StreamRef; + +class StreamReader { +public: + StreamReader(StreamRef Stream); + + Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer); + Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size); + Error readInteger(uint16_t &Dest); + Error readInteger(uint32_t &Dest); + Error readZeroString(StringRef &Dest); + Error readFixedString(StringRef &Dest, uint32_t Length); + Error readStreamRef(StreamRef &Ref); + Error readStreamRef(StreamRef &Ref, uint32_t Length); + + template <typename T> Error readEnum(T &Dest) { + typename std::underlying_type<T>::type N; + if (auto EC = readInteger(N)) + return EC; + Dest = static_cast<T>(N); + return Error::success(); + } + + template <typename T> Error readObject(const T *&Dest) { + ArrayRef<uint8_t> Buffer; + if (auto EC = readBytes(Buffer, sizeof(T))) + return EC; + Dest = reinterpret_cast<const T *>(Buffer.data()); + return Error::success(); + } + + template <typename T> + Error readArray(ArrayRef<T> &Array, uint32_t NumElements) { + ArrayRef<uint8_t> Bytes; + if (NumElements == 0) { + Array = ArrayRef<T>(); + return Error::success(); + } + + if (NumElements > UINT32_MAX/sizeof(T)) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); + return Error::success(); + } + + template <typename T, typename U> + Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { + StreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray<T, U>(S, Array.getExtractor()); + return Error::success(); + } + + template <typename T> + Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) { + if (NumItems == 0) { + Array = FixedStreamArray<T>(); + return Error::success(); + } + uint32_t Length = NumItems * sizeof(T); + if (Length / sizeof(T) != NumItems) + return make_error<CodeViewError>(cv_error_code::corrupt_record); + if (Offset + Length > Stream.getLength()) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + StreamRef View = Stream.slice(Offset, Length); + Array = FixedStreamArray<T>(View); + Offset += Length; + return Error::success(); + } + + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + +private: + StreamRef Stream; + uint32_t Offset; +}; +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H diff --git a/include/llvm/DebugInfo/CodeView/StreamRef.h b/include/llvm/DebugInfo/CodeView/StreamRef.h new file mode 100644 index 000000000000..a4f244a32289 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamRef.h @@ -0,0 +1,104 @@ +//===- StreamRef.h - A copyable reference to a stream -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" + +namespace llvm { +namespace codeview { + +class StreamRef { +public: + StreamRef() : Stream(nullptr), ViewOffset(0), Length(0) {} + StreamRef(const StreamInterface &Stream) + : Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {} + StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length) + : Stream(&Stream), ViewOffset(Offset), Length(Length) {} + + // Use StreamRef.slice() instead. + StreamRef(const StreamRef &S, uint32_t Offset, uint32_t Length) = delete; + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const { + if (ViewOffset + Offset < Offset) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + if (Size + Offset > Length) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + return Stream->readBytes(ViewOffset + Offset, Size, Buffer); + } + + // Given an offset into the stream, read as much as possible without copying + // any data. + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) const { + if (Offset >= Length) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + if (auto EC = Stream->readLongestContiguousChunk(Offset, Buffer)) + return EC; + // This StreamRef might refer to a smaller window over a larger stream. In + // that case we will have read out more bytes than we should return, because + // we should not read past the end of the current view. + uint32_t MaxLength = Length - Offset; + if (Buffer.size() > MaxLength) + Buffer = Buffer.slice(0, MaxLength); + return Error::success(); + } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { + if (Data.size() + Offset > Length) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + return Stream->writeBytes(ViewOffset + Offset, Data); + } + + uint32_t getLength() const { return Length; } + + Error commit() const { return Stream->commit(); } + + StreamRef drop_front(uint32_t N) const { + if (!Stream) + return StreamRef(); + + N = std::min(N, Length); + return StreamRef(*Stream, ViewOffset + N, Length - N); + } + + StreamRef keep_front(uint32_t N) const { + if (!Stream) + return StreamRef(); + N = std::min(N, Length); + return StreamRef(*Stream, ViewOffset, N); + } + + StreamRef slice(uint32_t Offset, uint32_t Len) const { + return drop_front(Offset).keep_front(Len); + } + + bool operator==(const StreamRef &Other) const { + if (Stream != Other.Stream) + return false; + if (ViewOffset != Other.ViewOffset) + return false; + if (Length != Other.Length) + return false; + return true; + } + +private: + const StreamInterface *Stream; + uint32_t ViewOffset; + uint32_t Length; +}; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H diff --git a/include/llvm/DebugInfo/CodeView/StreamWriter.h b/include/llvm/DebugInfo/CodeView/StreamWriter.h new file mode 100644 index 000000000000..4d393d2ef790 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamWriter.h @@ -0,0 +1,86 @@ +//===- StreamWriter.h - Writes bytes and objects to a stream ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace codeview { + +class StreamRef; + +class StreamWriter { +public: + StreamWriter(StreamRef Stream); + + Error writeBytes(ArrayRef<uint8_t> Buffer); + Error writeInteger(uint16_t Dest); + Error writeInteger(uint32_t Dest); + Error writeZeroString(StringRef Str); + Error writeFixedString(StringRef Str); + Error writeStreamRef(StreamRef Ref); + Error writeStreamRef(StreamRef Ref, uint32_t Size); + + template <typename T> Error writeEnum(T Num) { + return writeInteger( + static_cast<typename std::underlying_type<T>::type>(Num)); + } + + template <typename T> Error writeObject(const T &Obj) { + static_assert(!std::is_pointer<T>::value, + "writeObject should not be used with pointers, to write " + "the pointed-to value dereference the pointer before calling " + "writeObject"); + return writeBytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T))); + } + + template <typename T> Error writeArray(ArrayRef<T> Array) { + if (Array.size() == 0) + return Error::success(); + + if (Array.size() > UINT32_MAX / sizeof(T)) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + return writeBytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()), + Array.size() * sizeof(T))); + } + + template <typename T, typename U> + Error writeArray(VarStreamArray<T, U> Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + template <typename T> Error writeArray(FixedStreamArray<T> Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + +private: + StreamRef Stream; + uint32_t Offset; +}; +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h new file mode 100644 index 000000000000..30b0a40451cb --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h @@ -0,0 +1,37 @@ +//===-- SymbolDumpDelegate.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H + +#include "SymbolVisitorDelegate.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include <stdint.h> + +namespace llvm { + +namespace codeview { + +class SymbolDumpDelegate : public SymbolVisitorDelegate { +public: + virtual ~SymbolDumpDelegate() {} + + virtual void printRelocatedField(StringRef Label, uint32_t RelocOffset, + uint32_t Offset, + StringRef *RelocSym = nullptr) = 0; + virtual void printBinaryBlockWithRelocs(StringRef Label, + ArrayRef<uint8_t> Block) = 0; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumper.h b/include/llvm/DebugInfo/CodeView/SymbolDumper.h new file mode 100644 index 000000000000..648e40f55810 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -0,0 +1,54 @@ +//===-- SymbolDumper.h - CodeView symbol info dumper ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { +class CVTypeDumper; + +/// Dumper for CodeView symbol streams found in COFF object files and PDB files. +class CVSymbolDumper { +public: + CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD, + std::unique_ptr<SymbolDumpDelegate> ObjDelegate, + bool PrintRecordBytes) + : W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)), + PrintRecordBytes(PrintRecordBytes) {} + + /// Dumps one type record. Returns false if there was a type parsing error, + /// and true otherwise. This should be called in order, since the dumper + /// maintains state about previous records which are necessary for cross + /// type references. + bool dump(const CVRecord<SymbolKind> &Record); + + /// Dumps the type records in Data. Returns false if there was a type stream + /// parse error, and true otherwise. + bool dump(const CVSymbolArray &Symbols); + +private: + ScopedPrinter &W; + CVTypeDumper &CVTD; + std::unique_ptr<SymbolDumpDelegate> ObjDelegate; + + bool PrintRecordBytes; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h new file mode 100644 index 000000000000..77e894fba4a9 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -0,0 +1,1452 @@ +//===- SymbolRecord.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; +using llvm::support::little32_t; + +class SymbolRecord { +protected: + explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {} + +public: + SymbolRecordKind getKind() const { return Kind; } + +private: + SymbolRecordKind Kind; +}; + +// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or +// S_LPROC32_DPC_ID +class ProcSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + ulittle32_t PtrNext; + ulittle32_t CodeSize; + ulittle32_t DbgStart; + ulittle32_t DbgEnd; + TypeIndex FunctionType; + ulittle32_t CodeOffset; + ulittle16_t Segment; + uint8_t Flags; // ProcSymFlags enum + // Name: The null-terminated name follows. + }; + + ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { + } + + static ErrorOr<ProcSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ProcSym(Kind, RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_THUNK32 +class Thunk32Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Parent; + ulittle32_t End; + ulittle32_t Next; + ulittle32_t Off; + ulittle16_t Seg; + ulittle16_t Len; + uint8_t Ord; // ThunkOrdinal enumeration + // Name: The null-terminated name follows. + // Variant portion of thunk + }; + + Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name, ArrayRef<uint8_t> VariantData) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name), + VariantData(VariantData) {} + + static ErrorOr<Thunk32Sym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + ArrayRef<uint8_t> VariantData; + + CV_DESERIALIZE(Data, H, Name, CV_ARRAY_FIELD_TAIL(VariantData)); + + return Thunk32Sym(Kind, RecordOffset, H, Name, VariantData); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; + ArrayRef<uint8_t> VariantData; +}; + +// S_TRAMPOLINE +class TrampolineSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Type; // TrampolineType enum + ulittle16_t Size; + ulittle32_t ThunkOff; + ulittle32_t TargetOff; + ulittle16_t ThunkSection; + ulittle16_t TargetSection; + }; + + TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<TrampolineSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + + CV_DESERIALIZE(Data, H); + + return TrampolineSym(Kind, RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_SECTION +class SectionSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t SectionNumber; + uint8_t Alignment; + uint8_t Reserved; // Must be 0 + ulittle32_t Rva; + ulittle32_t Length; + ulittle32_t Characteristics; + // Name: The null-terminated name follows. + }; + + SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { + } + + static ErrorOr<SectionSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + + CV_DESERIALIZE(Data, H, Name); + + return SectionSym(Kind, RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_COFFGROUP +class CoffGroupSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Size; + ulittle32_t Characteristics; + ulittle32_t Offset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { + } + + static ErrorOr<CoffGroupSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + + CV_DESERIALIZE(Data, H, Name); + + return CoffGroupSym(Kind, RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +class ScopeEndSym : public SymbolRecord { +public: + ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset) + : SymbolRecord(Kind), RecordOffset(RecordOffset) {} + + static ErrorOr<ScopeEndSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + return ScopeEndSym(Kind, RecordOffset); + } + uint32_t RecordOffset; +}; + +class CallerSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Count; + }; + + CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *Header, + ArrayRef<TypeIndex> Indices) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*Header), + Indices(Indices) {} + + static ErrorOr<CallerSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *Header; + ArrayRef<TypeIndex> Indices; + + CV_DESERIALIZE(Data, Header, CV_ARRAY_FIELD_N(Indices, Header->Count)); + + return CallerSym(Kind, RecordOffset, Header, Indices); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<TypeIndex> Indices; +}; + +struct BinaryAnnotationIterator { + struct AnnotationData { + BinaryAnnotationsOpCode OpCode; + StringRef Name; + uint32_t U1; + uint32_t U2; + int32_t S1; + }; + + BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {} + BinaryAnnotationIterator() {} + BinaryAnnotationIterator(const BinaryAnnotationIterator &Other) + : Data(Other.Data) {} + + bool operator==(BinaryAnnotationIterator Other) const { + return Data == Other.Data; + } + + bool operator!=(BinaryAnnotationIterator Other) const { + return !(*this == Other); + } + + BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) { + Data = Other.Data; + return *this; + } + + BinaryAnnotationIterator &operator++() { + if (!ParseCurrentAnnotation()) { + *this = BinaryAnnotationIterator(); + return *this; + } + Data = Next; + Next = ArrayRef<uint8_t>(); + Current.reset(); + return *this; + } + + BinaryAnnotationIterator operator++(int) { + BinaryAnnotationIterator Orig(*this); + ++(*this); + return Orig; + } + + const AnnotationData &operator*() { + ParseCurrentAnnotation(); + return Current.getValue(); + } + +private: + static uint32_t GetCompressedAnnotation(ArrayRef<uint8_t> &Annotations) { + if (Annotations.empty()) + return -1; + + uint8_t FirstByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0x80) == 0x00) + return FirstByte; + + if (Annotations.empty()) + return -1; + + uint8_t SecondByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0xC0) == 0x80) + return ((FirstByte & 0x3F) << 8) | SecondByte; + + if (Annotations.empty()) + return -1; + + uint8_t ThirdByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if (Annotations.empty()) + return -1; + + uint8_t FourthByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0xE0) == 0xC0) + return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) | + (ThirdByte << 8) | FourthByte; + + return -1; + }; + + static int32_t DecodeSignedOperand(uint32_t Operand) { + if (Operand & 1) + return -(Operand >> 1); + return Operand >> 1; + }; + + static int32_t DecodeSignedOperand(ArrayRef<uint8_t> &Annotations) { + return DecodeSignedOperand(GetCompressedAnnotation(Annotations)); + }; + + bool ParseCurrentAnnotation() { + if (Current.hasValue()) + return true; + + Next = Data; + uint32_t Op = GetCompressedAnnotation(Next); + AnnotationData Result; + Result.OpCode = static_cast<BinaryAnnotationsOpCode>(Op); + switch (Result.OpCode) { + case BinaryAnnotationsOpCode::Invalid: + Result.Name = "Invalid"; + Next = ArrayRef<uint8_t>(); + break; + case BinaryAnnotationsOpCode::CodeOffset: + Result.Name = "CodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: + Result.Name = "ChangeCodeOffsetBase"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffset: + Result.Name = "ChangeCodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeLength: + Result.Name = "ChangeCodeLength"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeFile: + Result.Name = "ChangeFile"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeLineEndDelta: + Result.Name = "ChangeLineEndDelta"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeRangeKind: + Result.Name = "ChangeRangeKind"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnStart: + Result.Name = "ChangeColumnStart"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnEnd: + Result.Name = "ChangeColumnEnd"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeLineOffset: + Result.Name = "ChangeLineOffset"; + Result.S1 = DecodeSignedOperand(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnEndDelta: + Result.Name = "ChangeColumnEndDelta"; + Result.S1 = DecodeSignedOperand(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { + Result.Name = "ChangeCodeOffsetAndLineOffset"; + uint32_t Annotation = GetCompressedAnnotation(Next); + Result.S1 = DecodeSignedOperand(Annotation >> 4); + Result.U1 = Annotation & 0xf; + break; + } + case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { + Result.Name = "ChangeCodeLengthAndCodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + Result.U2 = GetCompressedAnnotation(Next); + break; + } + } + Current = Result; + return true; + } + + Optional<AnnotationData> Current; + ArrayRef<uint8_t> Data; + ArrayRef<uint8_t> Next; +}; + +// S_INLINESITE +class InlineSiteSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + TypeIndex Inlinee; + // BinaryAnnotations + }; + + InlineSiteSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<uint8_t> Annotations) + : SymbolRecord(SymbolRecordKind::InlineSiteSym), + RecordOffset(RecordOffset), Header(*H), Annotations(Annotations) {} + + static ErrorOr<InlineSiteSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<uint8_t> Annotations; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Annotations)); + + return InlineSiteSym(RecordOffset, H, Annotations); + } + + llvm::iterator_range<BinaryAnnotationIterator> annotations() const { + return llvm::make_range(BinaryAnnotationIterator(Annotations), + BinaryAnnotationIterator()); + } + + uint32_t RecordOffset; + Hdr Header; + +private: + ArrayRef<uint8_t> Annotations; +}; + +// S_PUB32 +class PublicSym32 : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type index, or Metadata token if a managed symbol + ulittle32_t Off; + ulittle16_t Seg; + // Name: The null-terminated name follows. + }; + + PublicSym32(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::PublicSym32), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<PublicSym32> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return PublicSym32(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_REGISTER +class RegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type index or Metadata token + ulittle16_t Register; // RegisterId enumeration + // Name: The null-terminated name follows. + }; + + RegisterSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::RegisterSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<RegisterSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return RegisterSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_PROCREF, S_LPROCREF +class ProcRefSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t SumName; // SUC of the name (?) + ulittle32_t SymOffset; // Offset of actual symbol in $$Symbols + ulittle16_t Mod; // Module containing the actual symbol + // Name: The null-terminated name follows. + }; + + ProcRefSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<ProcRefSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ProcRefSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_LOCAL +class LocalSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle16_t Flags; // LocalSymFlags enum + // Name: The null-terminated name follows. + }; + + LocalSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<LocalSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return LocalSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +struct LocalVariableAddrRange { + ulittle32_t OffsetStart; + ulittle16_t ISectStart; + ulittle16_t Range; +}; + +struct LocalVariableAddrGap { + ulittle16_t GapStartOffset; + ulittle16_t Range; +}; + +enum : uint16_t { MaxDefRange = 0xf000 }; + +// S_DEFRANGE +class DefRangeSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Program; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSym), RecordOffset(RecordOffset), + Header(*H), Gaps(Gaps) {} + + static ErrorOr<DefRangeSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_SUBFIELD +class DefRangeSubfieldSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Program; + ulittle16_t OffsetInParent; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + DefRangeSubfieldSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + static ErrorOr<DefRangeSubfieldSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSubfieldSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_REGISTER +class DefRangeRegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Register; + ulittle16_t MayHaveNoName; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeRegisterSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeRegisterSym(uint16_t Register, uint16_t MayHaveNoName, + uint32_t OffsetStart, uint16_t ISectStart, uint16_t Range, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), RecordOffset(0), + Gaps(Gaps) { + Header.Register = Register; + Header.MayHaveNoName = MayHaveNoName; + Header.Range.OffsetStart = OffsetStart; + Header.Range.ISectStart = ISectStart; + Header.Range.Range = Range; + } + + static ErrorOr<DefRangeRegisterSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeRegisterSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_SUBFIELD_REGISTER +class DefRangeSubfieldRegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Register; // Register to which the variable is relative + ulittle16_t MayHaveNoName; + ulittle32_t OffsetInParent; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeSubfieldRegisterSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeSubfieldRegisterSym(uint16_t Register, uint16_t MayHaveNoName, + uint32_t OffsetInParent, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym), + RecordOffset(0), Gaps(Gaps) { + Header.Register = Register; + Header.MayHaveNoName = MayHaveNoName; + Header.OffsetInParent = OffsetInParent; + } + + static ErrorOr<DefRangeSubfieldRegisterSym> + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSubfieldRegisterSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_FRAMEPOINTER_REL +class DefRangeFramePointerRelSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the frame pointer register + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeFramePointerRelSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + static ErrorOr<DefRangeFramePointerRelSym> + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeFramePointerRelSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_REGISTER_REL +class DefRangeRegisterRelSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t BaseRegister; + ulittle16_t Flags; + little32_t BasePointerOffset; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeRegisterRelSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeRegisterRelSym(uint16_t BaseRegister, uint16_t Flags, + int32_t BasePointerOffset, uint32_t OffsetStart, + uint16_t ISectStart, uint16_t Range, + ArrayRef<LocalVariableAddrGap> Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), RecordOffset(0), + Gaps(Gaps) { + Header.BaseRegister = BaseRegister; + Header.Flags = Flags; + Header.BasePointerOffset = BasePointerOffset; + Header.Range.OffsetStart = OffsetStart; + Header.Range.ISectStart = ISectStart; + Header.Range.Range = Range; + } + + static ErrorOr<DefRangeRegisterRelSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + ArrayRef<LocalVariableAddrGap> Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeRegisterRelSym(RecordOffset, H, Gaps); + } + + bool hasSpilledUDTMember() const { return Header.Flags & 1; } + uint16_t offsetInParent() const { return Header.Flags >> 4; } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef<LocalVariableAddrGap> Gaps; +}; + +// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE +class DefRangeFramePointerRelFullScopeSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the frame pointer register + }; + + DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<DefRangeFramePointerRelFullScopeSym> + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return DefRangeFramePointerRelFullScopeSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_BLOCK32 +class BlockSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + ulittle32_t CodeSize; + ulittle32_t CodeOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + BlockSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<BlockSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return BlockSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_LABEL32 +class LabelSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + uint8_t Flags; // CV_PROCFLAGS + // Name: The null-terminated name follows. + }; + + LabelSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<LabelSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return LabelSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_OBJNAME +class ObjNameSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Signature; + // Name: The null-terminated name follows. + }; + + ObjNameSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<ObjNameSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ObjNameSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_ENVBLOCK +class EnvBlockSym : public SymbolRecord { +public: + struct Hdr { + uint8_t Reserved; + // Sequence of zero terminated strings. + }; + + EnvBlockSym(uint32_t RecordOffset, const Hdr *H, + const std::vector<StringRef> &Fields) + : SymbolRecord(SymbolRecordKind::EnvBlockSym), RecordOffset(RecordOffset), + Header(*H), Fields(Fields) {} + + static ErrorOr<EnvBlockSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + std::vector<StringRef> Fields; + CV_DESERIALIZE(Data, H, CV_STRING_ARRAY_NULL_TERM(Fields)); + + return EnvBlockSym(RecordOffset, H, Fields); + } + + uint32_t RecordOffset; + Hdr Header; + std::vector<StringRef> Fields; +}; + +// S_EXPORT +class ExportSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Ordinal; + ulittle16_t Flags; // ExportFlags + // Name: The null-terminated name follows. + }; + + ExportSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<ExportSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ExportSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_FILESTATIC +class FileStaticSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type Index + ulittle32_t ModFilenameOffset; // Index of mod filename in string table + ulittle16_t Flags; // LocalSymFlags enum + // Name: The null-terminated name follows. + }; + + FileStaticSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::FileStaticSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr<FileStaticSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return FileStaticSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_COMPILE2 +class Compile2Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t flags; // CompileSym2Flags enum + uint8_t getLanguage() const { return flags & 0xFF; } + unsigned short Machine; // CPUType enum + unsigned short VersionFrontendMajor; + unsigned short VersionFrontendMinor; + unsigned short VersionFrontendBuild; + unsigned short VersionBackendMajor; + unsigned short VersionBackendMinor; + unsigned short VersionBackendBuild; + // Version: The null-terminated version string follows. + // Optional block of zero terminated strings terminated with a double zero. + }; + + Compile2Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version) + : SymbolRecord(SymbolRecordKind::Compile2Sym), RecordOffset(RecordOffset), + Header(*H), Version(Version) {} + + static ErrorOr<Compile2Sym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Version; + CV_DESERIALIZE(Data, H, Version); + + return Compile2Sym(RecordOffset, H, Version); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Version; +}; + +// S_COMPILE3 +class Compile3Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t flags; // CompileSym3Flags enum + uint8_t getLanguage() const { return flags & 0xff; } + ulittle16_t Machine; // CPUType enum + ulittle16_t VersionFrontendMajor; + ulittle16_t VersionFrontendMinor; + ulittle16_t VersionFrontendBuild; + ulittle16_t VersionFrontendQFE; + ulittle16_t VersionBackendMajor; + ulittle16_t VersionBackendMinor; + ulittle16_t VersionBackendBuild; + ulittle16_t VersionBackendQFE; + // VersionString: The null-terminated version string follows. + }; + + Compile3Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version) + : SymbolRecord(SymbolRecordKind::Compile3Sym), RecordOffset(RecordOffset), + Header(*H), Version(Version) {} + + static ErrorOr<Compile3Sym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Version; + CV_DESERIALIZE(Data, H, Version); + + return Compile3Sym(RecordOffset, H, Version); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Version; +}; + +// S_FRAMEPROC +class FrameProcSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t TotalFrameBytes; + ulittle32_t PaddingFrameBytes; + ulittle32_t OffsetToPadding; + ulittle32_t BytesOfCalleeSavedRegisters; + ulittle32_t OffsetOfExceptionHandler; + ulittle16_t SectionIdOfExceptionHandler; + ulittle32_t Flags; + }; + + FrameProcSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::FrameProcSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<FrameProcSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return FrameProcSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_CALLSITEINFO +class CallSiteInfoSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + ulittle16_t Reserved; + TypeIndex Type; + }; + + CallSiteInfoSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::CallSiteInfoSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<CallSiteInfoSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return CallSiteInfoSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_HEAPALLOCSITE +class HeapAllocationSiteSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + ulittle16_t CallInstructionSize; + TypeIndex Type; + }; + + HeapAllocationSiteSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<HeapAllocationSiteSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return HeapAllocationSiteSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_FRAMECOOKIE +class FrameCookieSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Register; + uint8_t CookieKind; + uint8_t Flags; + }; + + FrameCookieSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::FrameCookieSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<FrameCookieSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return FrameCookieSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_UDT, S_COBOLUDT +class UDTSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; // Type of the UDT + // Name: The null-terminated name follows. + }; + + UDTSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::UDTSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<UDTSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return UDTSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_BUILDINFO +class BuildInfoSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t BuildId; + }; + + BuildInfoSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::BuildInfoSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr<BuildInfoSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return BuildInfoSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_BPREL32 +class BPRelativeSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the base pointer register + TypeIndex Type; // Type of the variable + // Name: The null-terminated name follows. + }; + + BPRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::BPRelativeSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr<BPRelativeSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return BPRelativeSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_REGREL32 +class RegRelativeSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Offset; // Offset from the register + TypeIndex Type; // Type of the variable + ulittle16_t Register; // Register to which the variable is relative + // Name: The null-terminated name follows. + }; + + RegRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::RegRelativeSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr<RegRelativeSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return RegRelativeSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_CONSTANT, S_MANCONSTANT +class ConstantSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + // Value: The value of the constant. + // Name: The null-terminated name follows. + }; + + ConstantSym(uint32_t RecordOffset, const Hdr *H, const APSInt &Value, + StringRef Name) + : SymbolRecord(SymbolRecordKind::ConstantSym), RecordOffset(RecordOffset), + Header(*H), Value(Value), Name(Name) {} + + static ErrorOr<ConstantSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + APSInt Value; + StringRef Name; + CV_DESERIALIZE(Data, H, Value, Name); + + return ConstantSym(RecordOffset, H, Value, Name); + } + + uint32_t RecordOffset; + Hdr Header; + APSInt Value; + StringRef Name; +}; + +// S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA +class DataSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle32_t DataOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + DataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr<DataSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return DataSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, DataOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_LTHREAD32, S_GTHREAD32 +class ThreadLocalDataSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle32_t DataOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + ThreadLocalDataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr<ThreadLocalDataSym> deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef<uint8_t> &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ThreadLocalDataSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, DataOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +typedef CVRecord<SymbolKind> CVSymbol; +typedef VarStreamArray<CVSymbol> CVSymbolArray; + +} // namespace codeview +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h new file mode 100644 index 000000000000..a4965168c3db --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h @@ -0,0 +1,33 @@ +//===-- SymbolVisitorDelegate.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include <stdint.h> + +namespace llvm { + +namespace codeview { + +class SymbolVisitorDelegate { +public: + virtual ~SymbolVisitorDelegate() {} + + virtual uint32_t getRecordOffset(ArrayRef<uint8_t> Record) = 0; + virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0; + virtual StringRef getStringTable() = 0; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h new file mode 100644 index 000000000000..ca79ab076e5e --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -0,0 +1,105 @@ +//===-- TypeDumper.h - CodeView type info dumper ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +class CVTypeDumper : public TypeVisitorCallbacks { +public: + CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes) + : W(W), PrintRecordBytes(PrintRecordBytes) {} + + StringRef getTypeName(TypeIndex TI); + void printTypeIndex(StringRef FieldName, TypeIndex TI); + + /// Dumps one type record. Returns false if there was a type parsing error, + /// and true otherwise. This should be called in order, since the dumper + /// maintains state about previous records which are necessary for cross + /// type references. + Error dump(const CVRecord<TypeLeafKind> &Record); + + /// Dumps the type records in Types. Returns false if there was a type stream + /// parse error, and true otherwise. + Error dump(const CVTypeArray &Types); + + /// Dumps the type records in Data. Returns false if there was a type stream + /// parse error, and true otherwise. Use this method instead of the + /// CVTypeArray overload when type records are laid out contiguously in + /// memory. + Error dump(ArrayRef<uint8_t> Data); + + /// Gets the type index for the next type record. + unsigned getNextTypeIndex() const { + return 0x1000 + CVUDTNames.size(); + } + + /// Records the name of a type, and reserves its type index. + void recordType(StringRef Name) { CVUDTNames.push_back(Name); } + + /// Saves the name in a StringSet and creates a stable StringRef. + StringRef saveName(StringRef TypeName) { + return TypeNames.insert(TypeName).first->getKey(); + } + + void setPrinter(ScopedPrinter *P); + ScopedPrinter *getPrinter() { return W; } + + /// Action to take on unknown types. By default, they are ignored. + Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override; + Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) override; + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override; + Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visit##Name(Name##Record &Record) override; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" + +private: + void printMemberAttributes(MemberAttributes Attrs); + void printMemberAttributes(MemberAccess Access, MethodKind Kind, + MethodOptions Options); + + ScopedPrinter *W; + + bool PrintRecordBytes = false; + + /// Name of the current type. Only valid before visitTypeEnd. + StringRef Name; + + /// All user defined type records in .debug$T live in here. Type indices + /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to + /// index into this vector. + SmallVector<StringRef, 10> CVUDTNames; + + StringSet<> TypeNames; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeIndex.h b/include/llvm/DebugInfo/CodeView/TypeIndex.h index d3a541be4c62..c2ebf3848892 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndex.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H #define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H +#include "llvm/Support/Endian.h" #include <cassert> #include <cinttypes> @@ -26,6 +27,8 @@ enum class SimpleTypeKind : uint32_t { UnsignedCharacter = 0x0020, // 8 bit unsigned NarrowCharacter = 0x0070, // really a char WideCharacter = 0x0071, // wide char + Character16 = 0x007a, // char16_t + Character32 = 0x007b, // char32_t SByte = 0x0068, // 8 bit signed int Byte = 0x0069, // 8 bit unsigned int @@ -41,6 +44,8 @@ enum class SimpleTypeKind : uint32_t { UInt64Quad = 0x0023, // 64 bit unsigned Int64 = 0x0076, // 64 bit signed int UInt64 = 0x0077, // 64 bit unsigned int + Int128Oct = 0x0014, // 128 bit signed int + UInt128Oct = 0x0024, // 128 bit unsigned int Int128 = 0x0078, // 128 bit signed int UInt128 = 0x0079, // 128 bit unsigned int @@ -52,15 +57,19 @@ enum class SimpleTypeKind : uint32_t { Float80 = 0x0042, // 80 bit real Float128 = 0x0043, // 128 bit real - Complex32 = 0x0050, // 32 bit complex - Complex64 = 0x0051, // 64 bit complex - Complex80 = 0x0052, // 80 bit complex - Complex128 = 0x0053, // 128 bit complex - - Boolean8 = 0x0030, // 8 bit boolean - Boolean16 = 0x0031, // 16 bit boolean - Boolean32 = 0x0032, // 32 bit boolean - Boolean64 = 0x0033 // 64 bit boolean + Complex16 = 0x0056, // 16 bit complex + Complex32 = 0x0050, // 32 bit complex + Complex32PartialPrecision = 0x0055, // 32 bit PP complex + Complex48 = 0x0054, // 48 bit complex + Complex64 = 0x0051, // 64 bit complex + Complex80 = 0x0052, // 80 bit complex + Complex128 = 0x0053, // 128 bit complex + + Boolean8 = 0x0030, // 8 bit boolean + Boolean16 = 0x0031, // 16 bit boolean + Boolean32 = 0x0032, // 32 bit boolean + Boolean64 = 0x0033, // 64 bit boolean + Boolean128 = 0x0034, // 128 bit boolean }; enum class SimpleTypeMode : uint32_t { @@ -74,6 +83,9 @@ enum class SimpleTypeMode : uint32_t { NearPointer128 = 0x00000700 // 128 bit near pointer }; +/// A 32-bit type reference. Types are indexed by their order of appearance in +/// .debug$T plus 0x1000. Type indices less than 0x1000 are "simple" types, +/// composed of a SimpleTypeMode byte followed by a SimpleTypeKind byte. class TypeIndex { public: static const uint32_t FirstNonSimpleIndex = 0x1000; @@ -91,6 +103,8 @@ public: uint32_t getIndex() const { return Index; } bool isSimple() const { return Index < FirstNonSimpleIndex; } + bool isNoneType() const { return *this == None(); } + SimpleTypeKind getSimpleKind() const { assert(isSimple()); return static_cast<SimpleTypeKind>(Index & SimpleKindMask); @@ -101,6 +115,7 @@ public: return static_cast<SimpleTypeMode>(Index & SimpleModeMask); } + static TypeIndex None() { return TypeIndex(SimpleTypeKind::None); } static TypeIndex Void() { return TypeIndex(SimpleTypeKind::Void); } static TypeIndex VoidPointer32() { return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer32); @@ -143,33 +158,34 @@ public: static TypeIndex Float32() { return TypeIndex(SimpleTypeKind::Float32); } static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); } -private: - uint32_t Index; -}; + friend inline bool operator==(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() == B.getIndex(); + } -inline bool operator==(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() == B.getIndex(); -} + friend inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() != B.getIndex(); + } -inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() != B.getIndex(); -} + friend inline bool operator<(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() < B.getIndex(); + } -inline bool operator<(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() < B.getIndex(); -} + friend inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() <= B.getIndex(); + } -inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() <= B.getIndex(); -} + friend inline bool operator>(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() > B.getIndex(); + } -inline bool operator>(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() > B.getIndex(); -} + friend inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() >= B.getIndex(); + } + +private: + support::ulittle32_t Index; +}; -inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() >= B.getIndex(); -} } } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h index 21755f5d9b09..42751fbd4af1 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -10,15 +10,96 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/ErrorOr.h" #include <cinttypes> +#include <utility> namespace llvm { namespace codeview { +using llvm::support::little32_t; +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; + +/// Equvalent to CV_fldattr_t in cvinfo.h. +struct MemberAttributes { + ulittle16_t Attrs; + enum { + MethodKindShift = 2, + }; + + /// Get the access specifier. Valid for any kind of member. + MemberAccess getAccess() const { + return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); + } + + /// Indicates if a method is defined with friend, virtual, static, etc. + MethodKind getMethodKind() const { + return MethodKind( + (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> + MethodKindShift); + } + + /// Get the flags that are not included in access control or method + /// properties. + MethodOptions getFlags() const { + return MethodOptions( + unsigned(Attrs) & + ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); + } + + /// Is this method virtual. + bool isVirtual() const { + auto MP = getMethodKind(); + return MP != MethodKind::Vanilla && MP != MethodKind::Friend && + MP != MethodKind::Static; + } + + /// Does this member introduce a new virtual method. + bool isIntroducedVirtual() const { + auto MP = getMethodKind(); + return MP == MethodKind::IntroducingVirtual || + MP == MethodKind::PureIntroducingVirtual; + } +}; + +// Does not correspond to any tag, this is the tail of an LF_POINTER record +// if it represents a member pointer. +class MemberPointerInfo { +public: + MemberPointerInfo() {} + + MemberPointerInfo(TypeIndex ContainingType, + PointerToMemberRepresentation Representation) + : ContainingType(ContainingType), Representation(Representation) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<MemberPointerInfo> deserialize(ArrayRef<uint8_t> &Data); + + TypeIndex getContainingType() const { return ContainingType; } + PointerToMemberRepresentation getRepresentation() const { + return Representation; + } + +private: + struct Layout { + TypeIndex ClassType; + ulittle16_t Representation; // PointerToMemberRepresentation + }; + + TypeIndex ContainingType; + PointerToMemberRepresentation Representation; +}; + class TypeRecord { protected: explicit TypeRecord(TypeRecordKind Kind) : Kind(Kind) {} @@ -30,20 +111,34 @@ private: TypeRecordKind Kind; }; +// LF_MODIFIER class ModifierRecord : public TypeRecord { public: - ModifierRecord(TypeIndex ModifiedType, ModifierOptions Options) + ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers) : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), - Options(Options) {} + Modifiers(Modifiers) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ModifierRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); TypeIndex getModifiedType() const { return ModifiedType; } - ModifierOptions getOptions() const { return Options; } + ModifierOptions getModifiers() const { return Modifiers; } private: + struct Layout { + TypeIndex ModifiedType; + ulittle16_t Modifiers; // ModifierOptions + }; + TypeIndex ModifiedType; - ModifierOptions Options; + ModifierOptions Modifiers; }; +// LF_PROCEDURE class ProcedureRecord : public TypeRecord { public: ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv, @@ -53,6 +148,15 @@ public: CallConv(CallConv), Options(Options), ParameterCount(ParameterCount), ArgumentList(ArgumentList) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ProcedureRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } + TypeIndex getReturnType() const { return ReturnType; } CallingConvention getCallConv() const { return CallConv; } FunctionOptions getOptions() const { return Options; } @@ -60,6 +164,14 @@ public: TypeIndex getArgumentList() const { return ArgumentList; } private: + struct Layout { + TypeIndex ReturnType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + }; + TypeIndex ReturnType; CallingConvention CallConv; FunctionOptions Options; @@ -67,6 +179,7 @@ private: TypeIndex ArgumentList; }; +// LF_MFUNCTION class MemberFunctionRecord : public TypeRecord { public: MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType, @@ -79,6 +192,13 @@ public: ArgumentList(ArgumentList), ThisPointerAdjustment(ThisPointerAdjustment) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<MemberFunctionRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + TypeIndex getReturnType() const { return ReturnType; } TypeIndex getClassType() const { return ClassType; } TypeIndex getThisType() const { return ThisType; } @@ -89,6 +209,17 @@ public: int32_t getThisPointerAdjustment() const { return ThisPointerAdjustment; } private: + struct Layout { + TypeIndex ReturnType; + TypeIndex ClassType; + TypeIndex ThisType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + little32_t ThisAdjustment; + }; + TypeIndex ReturnType; TypeIndex ClassType; TypeIndex ThisType; @@ -99,78 +230,210 @@ private: int32_t ThisPointerAdjustment; }; -class ArgumentListRecord : public TypeRecord { +// LF_MFUNC_ID +class MemberFuncIdRecord : public TypeRecord { public: - explicit ArgumentListRecord(llvm::ArrayRef<TypeIndex> ArgumentTypes) - : TypeRecord(TypeRecordKind::ArgumentList), ArgumentTypes(ArgumentTypes) { - } + MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType, + StringRef Name) + : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType), + FunctionType(FunctionType), Name(Name) {} - llvm::ArrayRef<TypeIndex> getArgumentTypes() const { return ArgumentTypes; } + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<MemberFuncIdRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + TypeIndex getClassType() const { return ClassType; } + TypeIndex getFunctionType() const { return FunctionType; } + StringRef getName() const { return Name; } private: - llvm::ArrayRef<TypeIndex> ArgumentTypes; + struct Layout { + TypeIndex ClassType; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + TypeIndex ClassType; + TypeIndex FunctionType; + StringRef Name; }; -class PointerRecordBase : public TypeRecord { +// LF_ARGLIST, LF_SUBSTR_LIST +class ArgListRecord : public TypeRecord { public: - PointerRecordBase(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) + ArgListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices) + : TypeRecord(Kind), StringIndices(Indices) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ArgListRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + ArrayRef<TypeIndex> getIndices() const { return StringIndices; } + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } + +private: + struct Layout { + ulittle32_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + + std::vector<TypeIndex> StringIndices; +}; + +// LF_POINTER +class PointerRecord : public TypeRecord { +public: + static const uint32_t PointerKindShift = 0; + static const uint32_t PointerKindMask = 0x1F; + + static const uint32_t PointerModeShift = 5; + static const uint32_t PointerModeMask = 0x07; + + static const uint32_t PointerSizeShift = 13; + static const uint32_t PointerSizeMask = 0xFF; + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size) + : PointerRecord(ReferentType, Kind, Mode, Options, Size, + MemberPointerInfo()) {} + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size, + const MemberPointerInfo &Member) : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType), - PtrKind(Kind), Mode(Mode), Options(Options), Size(Size) {} + PtrKind(Kind), Mode(Mode), Options(Options), Size(Size), + MemberInfo(Member) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<PointerRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); TypeIndex getReferentType() const { return ReferentType; } PointerKind getPointerKind() const { return PtrKind; } PointerMode getMode() const { return Mode; } PointerOptions getOptions() const { return Options; } uint8_t getSize() const { return Size; } + MemberPointerInfo getMemberInfo() const { return MemberInfo; } + + bool isPointerToMember() const { + return Mode == PointerMode::PointerToDataMember || + Mode == PointerMode::PointerToMemberFunction; + } + bool isFlat() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Flat32)); + } + bool isConst() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Const)); + } + bool isVolatile() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Volatile)); + } + bool isUnaligned() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Unaligned)); + } private: + struct Layout { + TypeIndex PointeeType; + ulittle32_t Attrs; // pointer attributes + // if pointer to member: + // PointerToMemberTail + PointerKind getPtrKind() const { + return PointerKind(Attrs & PointerKindMask); + } + PointerMode getPtrMode() const { + return PointerMode((Attrs >> PointerModeShift) & PointerModeMask); + } + uint8_t getPtrSize() const { + return (Attrs >> PointerSizeShift) & PointerSizeMask; + } + bool isFlat() const { return Attrs & (1 << 8); } + bool isVolatile() const { return Attrs & (1 << 9); } + bool isConst() const { return Attrs & (1 << 10); } + bool isUnaligned() const { return Attrs & (1 << 11); } + + bool isPointerToDataMember() const { + return getPtrMode() == PointerMode::PointerToDataMember; + } + bool isPointerToMemberFunction() const { + return getPtrMode() == PointerMode::PointerToMemberFunction; + } + bool isPointerToMember() const { + return isPointerToMemberFunction() || isPointerToDataMember(); + } + }; + TypeIndex ReferentType; PointerKind PtrKind; PointerMode Mode; PointerOptions Options; uint8_t Size; + MemberPointerInfo MemberInfo; }; -class PointerRecord : public PointerRecordBase { +// LF_NESTTYPE +class NestedTypeRecord : public TypeRecord { public: - PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size) {} -}; + NestedTypeRecord(TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {} -class PointerToMemberRecord : public PointerRecordBase { -public: - PointerToMemberRecord(TypeIndex ReferentType, PointerKind Kind, - PointerMode Mode, PointerOptions Options, uint8_t Size, - TypeIndex ContainingType, - PointerToMemberRepresentation Representation) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size), - ContainingType(ContainingType), Representation(Representation) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getContainingType() const { return ContainingType; } - PointerToMemberRepresentation getRepresentation() const { - return Representation; - } + static ErrorOr<NestedTypeRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getNestedType() const { return Type; } + StringRef getName() const { return Name; } private: - TypeIndex ContainingType; - PointerToMemberRepresentation Representation; + struct Layout { + ulittle16_t Pad0; // Should be zero + TypeIndex Type; // Type index of nested type + // Name: Null-terminated string + }; + + TypeIndex Type; + StringRef Name; }; +// LF_ARRAY class ArrayRecord : public TypeRecord { public: ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size, - llvm::StringRef Name) + StringRef Name) : TypeRecord(TypeRecordKind::Array), ElementType(ElementType), IndexType(IndexType), Size(Size), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ArrayRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + TypeIndex getElementType() const { return ElementType; } TypeIndex getIndexType() const { return IndexType; } uint64_t getSize() const { return Size; } llvm::StringRef getName() const { return Name; } private: + struct Layout { + TypeIndex ElementType; + TypeIndex IndexType; + // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! + // Name: The null-terminated name follows. + }; + TypeIndex ElementType; TypeIndex IndexType; uint64_t Size; @@ -185,6 +448,15 @@ protected: FieldList(FieldList), Name(Name), UniqueName(UniqueName) {} public: + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static const int HfaKindShift = 11; + static const int HfaKindMask = 0x1800; + static const int WinRTKindShift = 14; + static const int WinRTKindMask = 0xC000; + uint16_t getMemberCount() const { return MemberCount; } ClassOptions getOptions() const { return Options; } TypeIndex getFieldList() const { return FieldList; } @@ -199,17 +471,24 @@ private: StringRef UniqueName; }; -class AggregateRecord : public TagRecord { +// LF_CLASS, LF_STRUCTURE, LF_INTERFACE +class ClassRecord : public TagRecord { public: - AggregateRecord(TypeRecordKind Kind, uint16_t MemberCount, - ClassOptions Options, HfaKind Hfa, - WindowsRTClassKind WinRTKind, TypeIndex FieldList, - TypeIndex DerivationList, TypeIndex VTableShape, - uint64_t Size, StringRef Name, StringRef UniqueName) + ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, + HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList, + TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size, + StringRef Name, StringRef UniqueName) : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName), Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList), VTableShape(VTableShape), Size(Size) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ClassRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + HfaKind getHfa() const { return Hfa; } WindowsRTClassKind getWinRTKind() const { return WinRTKind; } TypeIndex getDerivationList() const { return DerivationList; } @@ -217,6 +496,21 @@ public: uint64_t getSize() const { return Size; } private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes + TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + HfaKind Hfa; WindowsRTClassKind WinRTKind; TypeIndex DerivationList; @@ -224,6 +518,40 @@ private: uint64_t Size; }; +// LF_UNION +struct UnionRecord : public TagRecord { + UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa, + TypeIndex FieldList, uint64_t Size, StringRef Name, + StringRef UniqueName) + : TagRecord(TypeRecordKind::Union, MemberCount, Options, FieldList, Name, + UniqueName), + Hfa(Hfa), Size(Size) {} + + static ErrorOr<UnionRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + HfaKind getHfa() const { return Hfa; } + uint64_t getSize() const { return Size; } + +private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + + HfaKind Hfa; + uint64_t Size; +}; + +// LF_ENUM class EnumRecord : public TagRecord { public: EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList, @@ -232,38 +560,642 @@ public: UniqueName), UnderlyingType(UnderlyingType) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<EnumRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + TypeIndex getUnderlyingType() const { return UnderlyingType; } private: + struct Layout { + ulittle16_t NumEnumerators; // Number of enumerators + ulittle16_t Properties; + TypeIndex UnderlyingType; + TypeIndex FieldListType; + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + TypeIndex UnderlyingType; }; -class BitFieldRecord : TypeRecord { +// LF_BITFIELD +class BitFieldRecord : public TypeRecord { public: BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset) : TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize), BitOffset(BitOffset) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<BitFieldRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + TypeIndex getType() const { return Type; } uint8_t getBitOffset() const { return BitOffset; } uint8_t getBitSize() const { return BitSize; } private: + struct Layout { + TypeIndex Type; + uint8_t BitSize; + uint8_t BitOffset; + }; + TypeIndex Type; uint8_t BitSize; uint8_t BitOffset; }; -class VirtualTableShapeRecord : TypeRecord { +// LF_VTSHAPE +class VFTableShapeRecord : public TypeRecord { +public: + explicit VFTableShapeRecord(ArrayRef<VFTableSlotKind> Slots) + : TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {} + explicit VFTableShapeRecord(std::vector<VFTableSlotKind> Slots) + : TypeRecord(TypeRecordKind::VFTableShape), Slots(std::move(Slots)) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<VFTableShapeRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + ArrayRef<VFTableSlotKind> getSlots() const { + if (!SlotsRef.empty()) + return SlotsRef; + return Slots; + } + uint32_t getEntryCount() const { return getSlots().size(); } + +private: + struct Layout { + // Number of vftable entries. Each method may have more than one entry due + // to + // things like covariant return types. + ulittle16_t VFEntryCount; + // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. + }; + +private: + ArrayRef<VFTableSlotKind> SlotsRef; + std::vector<VFTableSlotKind> Slots; +}; + +// LF_TYPESERVER2 +class TypeServer2Record : public TypeRecord { +public: + TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name) + : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age), + Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<TypeServer2Record> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + StringRef getGuid() const { return Guid; } + + uint32_t getAge() const { return Age; } + + StringRef getName() const { return Name; } + +private: + struct Layout { + char Guid[16]; // GUID + ulittle32_t Age; + // Name: Name of the PDB as a null-terminated string + }; + + StringRef Guid; + uint32_t Age; + StringRef Name; +}; + +// LF_STRING_ID +class StringIdRecord : public TypeRecord { +public: + StringIdRecord(TypeIndex Id, StringRef String) + : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<StringIdRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getId() const { return Id; } + + StringRef getString() const { return String; } + +private: + struct Layout { + TypeIndex id; + // Name: Name of the PDB as a null-terminated string + }; + + TypeIndex Id; + StringRef String; +}; + +// LF_FUNC_ID +class FuncIdRecord : public TypeRecord { +public: + FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name) + : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope), + FunctionType(FunctionType), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<FuncIdRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getParentScope() const { return ParentScope; } + + TypeIndex getFunctionType() const { return FunctionType; } + + StringRef getName() const { return Name; } + +private: + struct Layout { + TypeIndex ParentScope; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + + TypeIndex ParentScope; + TypeIndex FunctionType; + StringRef Name; +}; + +// LF_UDT_SRC_LINE +class UdtSourceLineRecord : public TypeRecord { public: - explicit VirtualTableShapeRecord(ArrayRef<VirtualTableSlotKind> Slots) - : TypeRecord(TypeRecordKind::VirtualTableShape), Slots(Slots) {} + UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber) + : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), + SourceFile(SourceFile), LineNumber(LineNumber) {} - ArrayRef<VirtualTableSlotKind> getSlots() const { return Slots; } + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<UdtSourceLineRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getUDT() const { return UDT; } + TypeIndex getSourceFile() const { return SourceFile; } + uint32_t getLineNumber() const { return LineNumber; } private: - ArrayRef<VirtualTableSlotKind> Slots; + struct Layout { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; + }; + + TypeIndex UDT; + TypeIndex SourceFile; + uint32_t LineNumber; }; + +// LF_UDT_MOD_SRC_LINE +class UdtModSourceLineRecord : public TypeRecord { +public: + UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, + uint32_t LineNumber, uint16_t Module) + : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), + SourceFile(SourceFile), LineNumber(LineNumber), Module(Module) {} + + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<UdtModSourceLineRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + + return UdtModSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber, + L->Module); + } + + TypeIndex getUDT() const { return UDT; } + TypeIndex getSourceFile() const { return SourceFile; } + uint32_t getLineNumber() const { return LineNumber; } + uint16_t getModule() const { return Module; } + +private: + struct Layout { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; + ulittle16_t Module; // Module that contributes this UDT definition + }; + + TypeIndex UDT; + TypeIndex SourceFile; + uint32_t LineNumber; + uint16_t Module; +}; + +// LF_BUILDINFO +class BuildInfoRecord : public TypeRecord { +public: + BuildInfoRecord(ArrayRef<TypeIndex> ArgIndices) + : TypeRecord(TypeRecordKind::BuildInfo), + ArgIndices(ArgIndices.begin(), ArgIndices.end()) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<BuildInfoRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + ArrayRef<TypeIndex> getArgs() const { return ArgIndices; } + +private: + struct Layout { + ulittle16_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + SmallVector<TypeIndex, 4> ArgIndices; +}; + +// LF_VFTABLE +class VFTableRecord : public TypeRecord { +public: + VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + ArrayRef<StringRef> Methods) + : TypeRecord(TypeRecordKind::VFTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNamesRef(Methods) {} + VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + const std::vector<StringRef> &Methods) + : TypeRecord(TypeRecordKind::VFTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<VFTableRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getCompleteClass() const { return CompleteClass; } + TypeIndex getOverriddenVTable() const { return OverriddenVFTable; } + uint32_t getVFPtrOffset() const { return VFPtrOffset; } + StringRef getName() const { return Name; } + ArrayRef<StringRef> getMethodNames() const { + if (!MethodNamesRef.empty()) + return MethodNamesRef; + return MethodNames; + } + +private: + struct Layout { + TypeIndex CompleteClass; // Class that owns this vftable. + TypeIndex OverriddenVFTable; // VFTable that this overrides. + ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass + ulittle32_t NamesLen; // Length of subsequent names array in bytes. + // Names: A sequence of null-terminated strings. First string is vftable + // names. + }; + + TypeIndex CompleteClass; + TypeIndex OverriddenVFTable; + ulittle32_t VFPtrOffset; + StringRef Name; + ArrayRef<StringRef> MethodNamesRef; + std::vector<StringRef> MethodNames; +}; + +// LF_ONEMETHOD +class OneMethodRecord : public TypeRecord { +public: + OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options, + MemberAccess Access, int32_t VFTableOffset, StringRef Name) + : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind), + Options(Options), Access(Access), VFTableOffset(VFTableOffset), + Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<OneMethodRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getType() const { return Type; } + MethodKind getKind() const { return Kind; } + MethodOptions getOptions() const { return Options; } + MemberAccess getAccess() const { return Access; } + int32_t getVFTableOffset() const { return VFTableOffset; } + StringRef getName() const { return Name; } + + bool isIntroducingVirtual() const { + return Kind == MethodKind::IntroducingVirtual || + Kind == MethodKind::PureIntroducingVirtual; + } + +private: + struct Layout { + MemberAttributes Attrs; + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + // Name: Null-terminated string + }; + + TypeIndex Type; + MethodKind Kind; + MethodOptions Options; + MemberAccess Access; + int32_t VFTableOffset; + StringRef Name; +}; + +// LF_METHODLIST +class MethodOverloadListRecord : public TypeRecord { +public: + MethodOverloadListRecord(ArrayRef<OneMethodRecord> Methods) + : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<MethodOverloadListRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + ArrayRef<OneMethodRecord> getMethods() const { return Methods; } + +private: + struct Layout { + MemberAttributes Attrs; + ulittle16_t Padding; + + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + }; + + std::vector<OneMethodRecord> Methods; +}; + +/// For method overload sets. LF_METHOD +class OverloadedMethodRecord : public TypeRecord { +public: + OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList, + StringRef Name) + : TypeRecord(TypeRecordKind::OverloadedMethod), + NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<OverloadedMethodRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + uint16_t getNumOverloads() const { return NumOverloads; } + TypeIndex getMethodList() const { return MethodList; } + StringRef getName() const { return Name; } + +private: + struct Layout { + ulittle16_t MethodCount; // Size of overload set + TypeIndex MethList; // Type index of methods in overload set + // Name: Null-terminated string + }; + + uint16_t NumOverloads; + TypeIndex MethodList; + StringRef Name; +}; + +// LF_MEMBER +class DataMemberRecord : public TypeRecord { +public: + DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset, + StringRef Name) + : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type), + FieldOffset(Offset), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<DataMemberRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + uint64_t getFieldOffset() const { return FieldOffset; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // FieldOffset: LF_NUMERIC encoded byte offset + // Name: Null-terminated string + }; + + MemberAccess Access; + TypeIndex Type; + uint64_t FieldOffset; + StringRef Name; +}; + +// LF_STMEMBER +class StaticDataMemberRecord : public TypeRecord { +public: + StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access), + Type(Type), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<StaticDataMemberRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // Name: Null-terminated string + }; + + MemberAccess Access; + TypeIndex Type; + StringRef Name; +}; + +// LF_ENUMERATE +class EnumeratorRecord : public TypeRecord { +public: + EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name) + : TypeRecord(TypeRecordKind::Enumerator), Access(Access), + Value(std::move(Value)), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<EnumeratorRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + MemberAccess getAccess() const { return Access; } + APSInt getValue() const { return Value; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + // EnumValue: LF_NUMERIC encoded enumerator value + // Name: Null-terminated string + }; + + MemberAccess Access; + APSInt Value; + StringRef Name; +}; + +// LF_VFUNCTAB +class VFPtrRecord : public TypeRecord { +public: + VFPtrRecord(TypeIndex Type) + : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<VFPtrRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + TypeIndex getType() const { return Type; } + +private: + struct Layout { + ulittle16_t Pad0; + TypeIndex Type; // Type of vfptr + }; + TypeIndex Type; +}; + +// LF_BCLASS, LF_BINTERFACE +class BaseClassRecord : public TypeRecord { +public: + BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset) + : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type), + Offset(Offset) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<BaseClassRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return Type; } + uint64_t getBaseOffset() const { return Offset; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex BaseType; // Base class type + // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. + }; + MemberAccess Access; + TypeIndex Type; + uint64_t Offset; +}; + +// LF_VBCLASS, LF_IVBCLASS +class VirtualBaseClassRecord : public TypeRecord { +public: + VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType, + TypeIndex VBPtrType, uint64_t Offset, uint64_t Index) + : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access), + BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset), + VTableIndex(Index) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<VirtualBaseClassRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return BaseType; } + TypeIndex getVBPtrType() const { return VBPtrType; } + uint64_t getVBPtrOffset() const { return VBPtrOffset; } + uint64_t getVTableIndex() const { return VTableIndex; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc. + TypeIndex BaseType; // Base class type + TypeIndex VBPtrType; // Virtual base pointer type + // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. + // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. + }; + MemberAccess Access; + TypeIndex BaseType; + TypeIndex VBPtrType; + uint64_t VBPtrOffset; + uint64_t VTableIndex; +}; + +/// LF_INDEX - Used to chain two large LF_FIELDLIST or LF_METHODLIST records +/// together. The first will end in an LF_INDEX record that points to the next. +class ListContinuationRecord : public TypeRecord { +public: + ListContinuationRecord(TypeIndex ContinuationIndex) + : TypeRecord(TypeRecordKind::ListContinuation), + ContinuationIndex(ContinuationIndex) {} + + TypeIndex getContinuationIndex() const { return ContinuationIndex; } + + bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + + static ErrorOr<ListContinuationRecord> deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data); + +private: + struct Layout { + ulittle16_t Pad0; + TypeIndex ContinuationIndex; + }; + TypeIndex ContinuationIndex; +}; + +typedef CVRecord<TypeLeafKind> CVType; +typedef VarStreamArray<CVType> CVTypeArray; } } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h index 1f48cf70666d..eb7993baab89 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h @@ -10,9 +10,10 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" @@ -39,13 +40,25 @@ public: void writeEncodedInteger(int64_t Value); void writeEncodedSignedInteger(int64_t Value); void writeEncodedUnsignedInteger(uint64_t Value); - void writeNullTerminatedString(const char *Value); void writeNullTerminatedString(StringRef Value); + void writeGuid(StringRef Guid); + void writeBytes(StringRef Value) { Stream << Value; } llvm::StringRef str(); uint64_t size() const { return Stream.tell(); } + void truncate(uint64_t Size) { + // This works because raw_svector_ostream is not buffered. + assert(Size < Buffer.size()); + Buffer.resize(Size); + } + + void reset(TypeRecordKind K) { + Buffer.clear(); + writeTypeRecordKind(K); + } + private: llvm::SmallVector<char, 256> Buffer; llvm::raw_svector_ostream Stream; diff --git a/include/llvm/DebugInfo/CodeView/TypeRecords.def b/include/llvm/DebugInfo/CodeView/TypeRecords.def new file mode 100644 index 000000000000..0959f4bf19c7 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -0,0 +1,252 @@ + +//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +// If the type is known, then we have a record describing it in TypeRecord.h. + +#ifndef CV_TYPE +#define CV_TYPE(lf_ename, value) +#endif + +// If the type is known, then we have a record describing it in TypeRecord.h. +#ifndef TYPE_RECORD +#define TYPE_RECORD(lf_ename, value, name) CV_TYPE(lf_ename, value) +#endif + +#ifndef TYPE_RECORD_ALIAS +#define TYPE_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + TYPE_RECORD(lf_ename, value, name) +#endif + +#ifndef MEMBER_RECORD +#define MEMBER_RECORD(lf_ename, value, name) TYPE_RECORD(lf_ename, value, name) +#endif + +#ifndef MEMBER_RECORD_ALIAS +#define MEMBER_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + MEMBER_RECORD(lf_ename, value, name) +#endif + +TYPE_RECORD(LF_POINTER, 0x1002, Pointer) +TYPE_RECORD(LF_MODIFIER, 0x1001, Modifier) +TYPE_RECORD(LF_PROCEDURE, 0x1008, Procedure) +TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction) +TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList) + +TYPE_RECORD(LF_ARRAY, 0x1503, Array) +TYPE_RECORD(LF_CLASS, 0x1504, Class) +TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class) +TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class) +TYPE_RECORD(LF_UNION, 0x1506, Union) +TYPE_RECORD(LF_ENUM, 0x1507, Enum) +TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2) +TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable) +TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape) + +TYPE_RECORD(LF_BITFIELD, 0x1205, BitField) + +// Member type records. These are generally not length prefixed, and appear +// inside of a field list record. +MEMBER_RECORD(LF_BCLASS, 0x1400, BaseClass) +MEMBER_RECORD_ALIAS(LF_BINTERFACE, 0x151a, BaseInterface, BaseClass) + +MEMBER_RECORD(LF_VBCLASS, 0x1401, VirtualBaseClass) +MEMBER_RECORD_ALIAS(LF_IVBCLASS, 0x1402, IndirectVirtualBaseClass, + VirtualBaseClass) + +MEMBER_RECORD(LF_VFUNCTAB, 0x1409, VFPtr) +MEMBER_RECORD(LF_STMEMBER, 0x150e, StaticDataMember) +MEMBER_RECORD(LF_METHOD, 0x150f, OverloadedMethod) +MEMBER_RECORD(LF_MEMBER, 0x150d, DataMember) +MEMBER_RECORD(LF_NESTTYPE, 0x1510, NestedType) +MEMBER_RECORD(LF_ONEMETHOD, 0x1511, OneMethod) +MEMBER_RECORD(LF_ENUMERATE, 0x1502, Enumerator) +MEMBER_RECORD(LF_INDEX, 0x1404, ListContinuation) + +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. +TYPE_RECORD(LF_FUNC_ID, 0x1601, FuncId) +TYPE_RECORD(LF_MFUNC_ID, 0x1602, MemberFuncId) +TYPE_RECORD(LF_BUILDINFO, 0x1603, BuildInfo) +// FIXME: We reuse the structure of ArgListRecord for substring lists, but it +// makes for confusing dumper output. +TYPE_RECORD_ALIAS(LF_SUBSTR_LIST, 0x1604, StringList, ArgList) +TYPE_RECORD(LF_STRING_ID, 0x1605, StringId) +TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine) +TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine) + + +TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList) + + +// 16 bit type records. +CV_TYPE(LF_MODIFIER_16t, 0x0001) +CV_TYPE(LF_POINTER_16t, 0x0002) +CV_TYPE(LF_ARRAY_16t, 0x0003) +CV_TYPE(LF_CLASS_16t, 0x0004) +CV_TYPE(LF_STRUCTURE_16t, 0x0005) +CV_TYPE(LF_UNION_16t, 0x0006) +CV_TYPE(LF_ENUM_16t, 0x0007) +CV_TYPE(LF_PROCEDURE_16t, 0x0008) +CV_TYPE(LF_MFUNCTION_16t, 0x0009) +CV_TYPE(LF_COBOL0_16t, 0x000b) +CV_TYPE(LF_COBOL1, 0x000c) +CV_TYPE(LF_BARRAY_16t, 0x000d) +CV_TYPE(LF_LABEL, 0x000e) +CV_TYPE(LF_NULLLEAF, 0x000f) // LF_NULL +CV_TYPE(LF_NOTTRAN, 0x0010) +CV_TYPE(LF_DIMARRAY_16t, 0x0011) +CV_TYPE(LF_VFTPATH_16t, 0x0012) +CV_TYPE(LF_PRECOMP_16t, 0x0013) +CV_TYPE(LF_ENDPRECOMP, 0x0014) +CV_TYPE(LF_OEM_16t, 0x0015) +CV_TYPE(LF_TYPESERVER_ST, 0x0016) + +CV_TYPE(LF_SKIP_16t, 0x0200) +CV_TYPE(LF_ARGLIST_16t, 0x0201) +CV_TYPE(LF_DEFARG_16t, 0x0202) +CV_TYPE(LF_LIST, 0x0203) +CV_TYPE(LF_FIELDLIST_16t, 0x0204) +CV_TYPE(LF_DERIVED_16t, 0x0205) +CV_TYPE(LF_BITFIELD_16t, 0x0206) +CV_TYPE(LF_METHODLIST_16t, 0x0207) +CV_TYPE(LF_DIMCONU_16t, 0x0208) +CV_TYPE(LF_DIMCONLU_16t, 0x0209) +CV_TYPE(LF_DIMVARU_16t, 0x020a) +CV_TYPE(LF_DIMVARLU_16t, 0x020b) +CV_TYPE(LF_REFSYM, 0x020c) + +// 16 bit member types. Generally not length prefixed. +CV_TYPE(LF_BCLASS_16t, 0x0400) +CV_TYPE(LF_VBCLASS_16t, 0x0401) +CV_TYPE(LF_IVBCLASS_16t, 0x0402) +CV_TYPE(LF_ENUMERATE_ST, 0x0403) +CV_TYPE(LF_FRIENDFCN_16t, 0x0404) +CV_TYPE(LF_INDEX_16t, 0x0405) +CV_TYPE(LF_MEMBER_16t, 0x0406) +CV_TYPE(LF_STMEMBER_16t, 0x0407) +CV_TYPE(LF_METHOD_16t, 0x0408) +CV_TYPE(LF_NESTTYPE_16t, 0x0409) +CV_TYPE(LF_VFUNCTAB_16t, 0x040a) +CV_TYPE(LF_FRIENDCLS_16t, 0x040b) +CV_TYPE(LF_ONEMETHOD_16t, 0x040c) +CV_TYPE(LF_VFUNCOFF_16t, 0x040d) + +CV_TYPE(LF_TI16_MAX, 0x1000) + +CV_TYPE(LF_ARRAY_ST, 0x1003) +CV_TYPE(LF_CLASS_ST, 0x1004) +CV_TYPE(LF_STRUCTURE_ST, 0x1005) +CV_TYPE(LF_UNION_ST, 0x1006) +CV_TYPE(LF_ENUM_ST, 0x1007) +CV_TYPE(LF_COBOL0, 0x100a) +CV_TYPE(LF_BARRAY, 0x100b) +CV_TYPE(LF_DIMARRAY_ST, 0x100c) +CV_TYPE(LF_VFTPATH, 0x100d) +CV_TYPE(LF_PRECOMP_ST, 0x100e) +CV_TYPE(LF_OEM, 0x100f) +CV_TYPE(LF_ALIAS_ST, 0x1010) +CV_TYPE(LF_OEM2, 0x1011) + +CV_TYPE(LF_SKIP, 0x1200) +CV_TYPE(LF_DEFARG_ST, 0x1202) +CV_TYPE(LF_FIELDLIST, 0x1203) +CV_TYPE(LF_DERIVED, 0x1204) +CV_TYPE(LF_DIMCONU, 0x1207) +CV_TYPE(LF_DIMCONLU, 0x1208) +CV_TYPE(LF_DIMVARU, 0x1209) +CV_TYPE(LF_DIMVARLU, 0x120a) + +// Member type records. These are generally not length prefixed, and appear +// inside of a field list record. +CV_TYPE(LF_FRIENDFCN_ST, 0x1403) +CV_TYPE(LF_MEMBER_ST, 0x1405) +CV_TYPE(LF_STMEMBER_ST, 0x1406) +CV_TYPE(LF_METHOD_ST, 0x1407) +CV_TYPE(LF_NESTTYPE_ST, 0x1408) +CV_TYPE(LF_FRIENDCLS, 0x140a) +CV_TYPE(LF_ONEMETHOD_ST, 0x140b) +CV_TYPE(LF_VFUNCOFF, 0x140c) +CV_TYPE(LF_NESTTYPEEX_ST, 0x140d) +CV_TYPE(LF_MEMBERMODIFY_ST, 0x140e) +CV_TYPE(LF_MANAGED_ST, 0x140f) + +CV_TYPE(LF_ST_MAX, 0x1500) +CV_TYPE(LF_TYPESERVER, 0x1501) +CV_TYPE(LF_DIMARRAY, 0x1508) +CV_TYPE(LF_PRECOMP, 0x1509) +CV_TYPE(LF_ALIAS, 0x150a) +CV_TYPE(LF_DEFARG, 0x150b) +CV_TYPE(LF_FRIENDFCN, 0x150c) +CV_TYPE(LF_NESTTYPEEX, 0x1512) +CV_TYPE(LF_MEMBERMODIFY, 0x1513) +CV_TYPE(LF_MANAGED, 0x1514) +CV_TYPE(LF_STRIDED_ARRAY, 0x1516) +CV_TYPE(LF_HLSL, 0x1517) +CV_TYPE(LF_MODIFIER_EX, 0x1518) +CV_TYPE(LF_VECTOR, 0x151b) +CV_TYPE(LF_MATRIX, 0x151c) + +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. + +// Numeric leaf types. These are generally contained in other records, and not +// encountered in the main type stream. + +CV_TYPE(LF_NUMERIC, 0x8000) +CV_TYPE(LF_CHAR, 0x8000) +CV_TYPE(LF_SHORT, 0x8001) +CV_TYPE(LF_USHORT, 0x8002) +CV_TYPE(LF_LONG, 0x8003) +CV_TYPE(LF_ULONG, 0x8004) +CV_TYPE(LF_REAL32, 0x8005) +CV_TYPE(LF_REAL64, 0x8006) +CV_TYPE(LF_REAL80, 0x8007) +CV_TYPE(LF_REAL128, 0x8008) +CV_TYPE(LF_QUADWORD, 0x8009) +CV_TYPE(LF_UQUADWORD, 0x800a) +CV_TYPE(LF_REAL48, 0x800b) +CV_TYPE(LF_COMPLEX32, 0x800c) +CV_TYPE(LF_COMPLEX64, 0x800d) +CV_TYPE(LF_COMPLEX80, 0x800e) +CV_TYPE(LF_COMPLEX128, 0x800f) +CV_TYPE(LF_VARSTRING, 0x8010) +CV_TYPE(LF_OCTWORD, 0x8017) +CV_TYPE(LF_UOCTWORD, 0x8018) +CV_TYPE(LF_DECIMAL, 0x8019) +CV_TYPE(LF_DATE, 0x801a) +CV_TYPE(LF_UTF8STRING, 0x801b) +CV_TYPE(LF_REAL16, 0x801c) + +// Padding bytes. These are emitted into alignment bytes in the type stream. + +CV_TYPE(LF_PAD0, 0xf0) +CV_TYPE(LF_PAD1, 0xf1) +CV_TYPE(LF_PAD2, 0xf2) +CV_TYPE(LF_PAD3, 0xf3) +CV_TYPE(LF_PAD4, 0xf4) +CV_TYPE(LF_PAD5, 0xf5) +CV_TYPE(LF_PAD6, 0xf6) +CV_TYPE(LF_PAD7, 0xf7) +CV_TYPE(LF_PAD8, 0xf8) +CV_TYPE(LF_PAD9, 0xf9) +CV_TYPE(LF_PAD10, 0xfa) +CV_TYPE(LF_PAD11, 0xfb) +CV_TYPE(LF_PAD12, 0xfc) +CV_TYPE(LF_PAD13, 0xfd) +CV_TYPE(LF_PAD14, 0xfe) +CV_TYPE(LF_PAD15, 0xff) + +#undef CV_TYPE +#undef TYPE_RECORD +#undef TYPE_RECORD_ALIAS +#undef MEMBER_RECORD +#undef MEMBER_RECORD_ALIAS diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h new file mode 100644 index 000000000000..af396c79d074 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -0,0 +1,26 @@ +//===- TypeStreamMerger.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" + +namespace llvm { +namespace codeview { + +/// Merges one type stream into another. Returns true on success. +bool mergeTypeStreams(TypeTableBuilder &DestStream, const CVTypeArray &Types); + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h index 9de110e8236f..dfba83d62fce 100644 --- a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h +++ b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h @@ -10,11 +10,12 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" namespace llvm { +class StringRef; + namespace codeview { class TypeSymbolEmitter { diff --git a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h index 2c950e8af792..5b2aa6186147 100644 --- a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -10,13 +10,15 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/Compiler.h" namespace llvm { + +class StringRef; + namespace codeview { class FieldListRecordBuilder; @@ -38,20 +40,28 @@ public: TypeIndex writeModifier(const ModifierRecord &Record); TypeIndex writeProcedure(const ProcedureRecord &Record); TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); - TypeIndex writeArgumentList(const ArgumentListRecord &Record); - TypeIndex writeRecord(TypeRecordBuilder &builder); + TypeIndex writeArgList(const ArgListRecord &Record); TypeIndex writePointer(const PointerRecord &Record); - TypeIndex writePointerToMember(const PointerToMemberRecord &Record); TypeIndex writeArray(const ArrayRecord &Record); - TypeIndex writeAggregate(const AggregateRecord &Record); + TypeIndex writeClass(const ClassRecord &Record); + TypeIndex writeUnion(const UnionRecord &Record); TypeIndex writeEnum(const EnumRecord &Record); TypeIndex writeBitField(const BitFieldRecord &Record); - TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord &Record); + TypeIndex writeVFTableShape(const VFTableShapeRecord &Record); + TypeIndex writeStringId(const StringIdRecord &Record); + TypeIndex writeVFTable(const VFTableRecord &Record); + TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record); + TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord &Record); + TypeIndex writeFuncId(const FuncIdRecord &Record); + TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record); + TypeIndex writeBuildInfo(const BuildInfoRecord &Record); + TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record); + TypeIndex writeTypeServer2(const TypeServer2Record &Record); TypeIndex writeFieldList(FieldListRecordBuilder &FieldList); - TypeIndex writeMethodList(MethodListRecordBuilder &MethodList); -private: + TypeIndex writeRecord(TypeRecordBuilder &builder); + virtual TypeIndex writeRecord(llvm::StringRef record) = 0; }; } diff --git a/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h new file mode 100644 index 000000000000..310847ec5d2d --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -0,0 +1,63 @@ +//===- TypeVisitorCallbacks.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class TypeVisitorCallbacks { + friend class CVTypeVisitor; + +public: + virtual ~TypeVisitorCallbacks() {} + + /// Action to take on unknown types. By default, they are ignored. + virtual Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + virtual Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + virtual Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + + virtual Error visitFieldListBegin(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + + virtual Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) { + return Error::success(); + } + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + virtual Error visit##Name(Name##Record &Record) { return Error::success(); } +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 6659a97a042b..2f88371979ea 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -15,10 +15,8 @@ #ifndef LLVM_DEBUGINFO_DICONTEXT_H #define LLVM_DEBUGINFO_DICONTEXT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" #include <string> @@ -140,7 +138,8 @@ public: DIContext(DIContextKind K) : Kind(K) {} virtual ~DIContext() {} - virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) = 0; + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) = 0; virtual DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index bae3154b3b5f..bba3abe6e9e9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -19,10 +19,10 @@ public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, bool LE, - const DWARFUnitSectionBase &UnitSection, + bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} void dump(raw_ostream &OS); static const DWARFSectionKind Section = DW_SECT_INFO; // VTable anchor. diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index c91012bc9a24..741a31cb582b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -22,7 +22,6 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include <vector> namespace llvm { @@ -40,7 +39,7 @@ typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; class DWARFContext : public DIContext { DWARFUnitSection<DWARFCompileUnit> CUs; - std::vector<DWARFUnitSection<DWARFTypeUnit>> TUs; + std::deque<DWARFUnitSection<DWARFTypeUnit>> TUs; std::unique_ptr<DWARFUnitIndex> CUIndex; std::unique_ptr<DWARFUnitIndex> TUIndex; std::unique_ptr<DWARFDebugAbbrev> Abbrev; @@ -48,10 +47,11 @@ class DWARFContext : public DIContext { std::unique_ptr<DWARFDebugAranges> Aranges; std::unique_ptr<DWARFDebugLine> Line; std::unique_ptr<DWARFDebugFrame> DebugFrame; + std::unique_ptr<DWARFDebugFrame> EHFrame; std::unique_ptr<DWARFDebugMacro> Macro; DWARFUnitSection<DWARFCompileUnit> DWOCUs; - std::vector<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; + std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO; std::unique_ptr<DWARFDebugLocDWO> LocDWO; @@ -81,11 +81,12 @@ public: return DICtx->getKind() == CK_DWARF; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range; typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range; - typedef iterator_range<std::vector<DWARFUnitSection<DWARFTypeUnit>>::iterator> tu_section_iterator_range; + typedef iterator_range<decltype(TUs)::iterator> tu_section_iterator_range; /// Get compile units in this context. cu_iterator_range compile_units() { @@ -168,6 +169,9 @@ public: /// Get a pointer to the parsed frame information object. const DWARFDebugFrame *getDebugFrame(); + /// Get a pointer to the parsed eh frame information object. + const DWARFDebugFrame *getEHFrame(); + /// Get a pointer to the parsed DebugMacro object. const DWARFDebugMacro *getDebugMacro(); @@ -191,6 +195,7 @@ public: virtual const DWARFSection &getLocSection() = 0; virtual StringRef getARangeSection() = 0; virtual StringRef getDebugFrameSection() = 0; + virtual StringRef getEHFrameSection() = 0; virtual const DWARFSection &getLineSection() = 0; virtual StringRef getStringSection() = 0; virtual StringRef getRangeSection() = 0; @@ -242,6 +247,7 @@ class DWARFContextInMemory : public DWARFContext { DWARFSection LocSection; StringRef ARangeSection; StringRef DebugFrameSection; + StringRef EHFrameSection; DWARFSection LineSection; StringRef StringSection; StringRef RangeSection; @@ -281,6 +287,7 @@ public: const DWARFSection &getLocSection() override { return LocSection; } StringRef getARangeSection() override { return ARangeSection; } StringRef getDebugFrameSection() override { return DebugFrameSection; } + StringRef getEHFrameSection() override { return EHFrameSection; } const DWARFSection &getLineSection() override { return LineSection; } StringRef getStringSection() override { return StringSection; } StringRef getRangeSection() override { return RangeSection; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index 21142089da6b..67c4a2bb3e67 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -11,7 +11,6 @@ #define LLVM_LIB_DEBUGINFO_DWARFDEBUGABBREV_H #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include <list> #include <map> #include <vector> diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index be925cbe7519..cd76c909ddae 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -19,11 +19,13 @@ namespace llvm { class FrameEntry; -/// \brief A parsed .debug_frame section +/// \brief A parsed .debug_frame or .eh_frame section /// class DWARFDebugFrame { + // True if this is parsing an eh_frame section. + bool IsEH; public: - DWARFDebugFrame(); + DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); /// \brief Dump the section data into the given stream. diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index f7910962a03f..731c521b9edb 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -11,7 +11,6 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Dwarf.h"
diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 3c32a3e5b794..b2f750dd7945 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -10,12 +10,12 @@ #ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H #define LLVM_DEBUGINFO_DWARFFORMVALUE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/DataExtractor.h" namespace llvm { +template <typename T> class ArrayRef; class DWARFUnit; class raw_ostream; diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index 894a88dce440..a697edd32072 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -21,11 +21,11 @@ private: public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} uint32_t getHeaderSize() const override { return DWARFUnit::getHeaderSize() + 12; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 681b2aa19a79..9c3fe3be6aa6 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -47,7 +47,7 @@ protected: virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool isLittleEndian) = 0; + bool isLittleEndian, bool isDWO) = 0; ~DWARFUnitSectionBase() = default; }; @@ -59,13 +59,9 @@ const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, template<typename UnitType> class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>, public DWARFUnitSectionBase { - bool Parsed; + bool Parsed = false; public: - DWARFUnitSection() : Parsed(false) {} - DWARFUnitSection(DWARFUnitSection &&DUS) : - SmallVector<std::unique_ptr<UnitType>, 1>(std::move(DUS)), Parsed(DUS.Parsed) {} - typedef llvm::SmallVectorImpl<std::unique_ptr<UnitType>> UnitVector; typedef typename UnitVector::iterator iterator; typedef llvm::iterator_range<typename UnitVector::iterator> iterator_range; @@ -84,7 +80,8 @@ public: private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE) override { + StringRef SOS, StringRef AOS, StringRef LS, bool LE, + bool IsDWO) override { if (Parsed) return; const auto &Index = getDWARFUnitIndex(Context, UnitType::Section); @@ -92,7 +89,7 @@ private: uint32_t Offset = 0; while (Data.isValidOffset(Offset)) { auto U = llvm::make_unique<UnitType>(Context, Section, DA, RS, SS, SOS, - AOS, LS, LE, *this, + AOS, LS, LE, IsDWO, *this, Index.getFromOffset(Offset)); if (!U->extract(Data, &Offset)) break; @@ -117,6 +114,7 @@ class DWARFUnit { StringRef AddrOffsetSection; uint32_t AddrOffsetSectionBase; bool isLittleEndian; + bool isDWO; const DWARFUnitSectionBase &UnitSection; uint32_t Offset; @@ -148,7 +146,7 @@ protected: public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry = nullptr); @@ -249,7 +247,7 @@ public: /// \brief Return the DIE object for a given offset inside the /// unit's DIE vector. /// - /// The unit needs to have his DIEs extracted for this method to work. + /// The unit needs to have its DIEs extracted for this method to work. const DWARFDebugInfoEntryMinimal *getDIEForOffset(uint32_t Offset) const { assert(!DieArray.empty()); auto it = std::lower_bound( diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h index a85c2f9f0a23..9f051cd7081c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -10,6 +10,7 @@ #ifndef LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H #define LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -56,6 +57,10 @@ public: public: const SectionContribution *getOffset(DWARFSectionKind Sec) const; const SectionContribution *getOffset() const; + const SectionContribution *getOffsets() const { + return Contributions.get(); + } + uint64_t getSignature() const { return Signature; } }; private: @@ -75,6 +80,12 @@ public: : InfoColumnKind(InfoColumnKind) {} void dump(raw_ostream &OS) const; const Entry *getFromOffset(uint32_t Offset) const; + ArrayRef<DWARFSectionKind> getColumnKinds() const { + return makeArrayRef(ColumnKinds.get(), Header.NumColumns); + } + ArrayRef<Entry> getRows() const { + return makeArrayRef(Rows.get(), Header.NumBuckets); + } }; } diff --git a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h index b5fa8c33414d..50f5c40bcac9 100644 --- a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h +++ b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h @@ -15,6 +15,7 @@ #include <memory> namespace llvm { +namespace pdb { template <typename ChildType> class ConcreteSymbolEnumerator : public IPDBEnumChildren<ChildType> { @@ -55,5 +56,6 @@ private: std::unique_ptr<IPDBEnumSymbols> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h index 7b2bc146b32d..930bea6060b2 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBDataStream.h" namespace llvm { +namespace pdb { class DIADataStream : public IPDBDataStream { public: explicit DIADataStream(CComPtr<IDiaEnumDebugStreamData> DiaStreamData); @@ -29,5 +30,6 @@ private: CComPtr<IDiaEnumDebugStreamData> StreamData; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h index 375bcdd7e3bd..941e16a35fac 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { +namespace pdb { class IPDBDataStream; @@ -31,5 +32,6 @@ private: CComPtr<IDiaEnumDebugStreams> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h index 4cc85eda477f..106b84cecfff 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class IPDBLineNumber; class DIAEnumLineNumbers : public IPDBEnumChildren<IPDBLineNumber> { @@ -31,5 +31,6 @@ private: CComPtr<IDiaEnumLineNumbers> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h index 88625f64e49e..6c00d6a5e29d 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSourceFiles : public IPDBEnumChildren<IPDBSourceFile> { @@ -33,5 +33,6 @@ private: CComPtr<IDiaEnumSourceFiles> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h index fe343f778aad..b206ff59a6a4 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSymbols : public IPDBEnumChildren<PDBSymbol> { @@ -33,5 +33,6 @@ private: CComPtr<IDiaEnumSymbols> Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAError.h b/include/llvm/DebugInfo/PDB/DIA/DIAError.h new file mode 100644 index 000000000000..f198d07e99d4 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAError.h @@ -0,0 +1,46 @@ +//===- DIAError.h - Error extensions for PDB DIA implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H + +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace pdb { +enum class dia_error_code { + unspecified = 1, + could_not_create_impl, + invalid_file_format, + invalid_parameter, + already_loaded, + debug_info_mismatch, +}; + +/// Base class for errors originating in DIA SDK, e.g. COM calls +class DIAError : public ErrorInfo<DIAError> { +public: + static char ID; + DIAError(dia_error_code C); + DIAError(const std::string &Context); + DIAError(dia_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + dia_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h index 5950a0d3835f..a59e3a19c8c2 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" namespace llvm { +namespace pdb { class DIALineNumber : public IPDBLineNumber { public: explicit DIALineNumber(CComPtr<IDiaLineNumber> DiaLineNumber); @@ -35,5 +36,5 @@ private: CComPtr<IDiaLineNumber> LineNumber; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 9308b8e82657..1e40c46f8a27 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" namespace llvm { +namespace pdb { class DIASession; class DIARawSymbol : public IPDBRawSymbol { public: @@ -58,7 +59,7 @@ public: uint32_t getLiveRangeStartAddressOffset() const override; uint32_t getLiveRangeStartAddressSection() const override; uint32_t getLiveRangeStartRelativeVirtualAddress() const override; - PDB_RegisterId getLocalBasePointerRegisterId() const override; + codeview::RegisterId getLocalBasePointerRegisterId() const override; uint32_t getLowerBoundId() const override; uint32_t getMemorySpaceKind() const override; std::string getName() const override; @@ -73,7 +74,7 @@ public: uint32_t getOffsetInUdt() const override; PDB_Cpu getPlatform() const override; uint32_t getRank() const override; - PDB_RegisterId getRegisterId() const override; + codeview::RegisterId getRegisterId() const override; uint32_t getRegisterType() const override; uint32_t getRelativeVirtualAddress() const override; uint32_t getSamplerSlot() const override; @@ -109,7 +110,7 @@ public: int32_t getVirtualBasePointerOffset() const override; PDB_LocType getLocationType() const override; PDB_Machine getMachineType() const override; - PDB_ThunkOrdinal getThunkOrdinal() const override; + codeview::ThunkOrdinal getThunkOrdinal() const override; uint64_t getLength() const override; uint64_t getLiveRangeLength() const override; uint64_t getVirtualAddress() const override; @@ -202,5 +203,6 @@ private: CComPtr<IDiaSymbol> Symbol; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 9a8600fb85ec..3f5818631e7b 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -11,18 +11,23 @@ #define LLVM_DEBUGINFO_PDB_DIA_DIASESSION_H #include "DIASupport.h" -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +#include <system_error> namespace llvm { +class StringRef; + +namespace pdb { class DIASession : public IPDBSession { public: explicit DIASession(CComPtr<IDiaSession> DiaSession); - static PDB_ErrorCode createFromPdb(StringRef Path, - std::unique_ptr<IPDBSession> &Session); - static PDB_ErrorCode createFromExe(StringRef Path, - std::unique_ptr<IPDBSession> &Session); + static Error createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; @@ -33,8 +38,24 @@ public: findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const override; + std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override; std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland( const PDBSymbolCompiland &Compiland) const override; @@ -47,5 +68,5 @@ private: CComPtr<IDiaSession> Session; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h index c424e27493c1..1088ea54981c 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" namespace llvm { +namespace pdb { class DIASession; class DIASourceFile : public IPDBSourceFile { @@ -25,12 +26,16 @@ public: uint32_t getUniqueId() const override; std::string getChecksum() const override; PDB_Checksum getChecksumType() const override; - std::unique_ptr<IPDBEnumSymbols> getCompilands() const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + getCompilands() const override; + + CComPtr<IDiaSourceFile> getDiaFile() const { return SourceFile; } private: const DIASession &Session; CComPtr<IDiaSourceFile> SourceFile; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h index 407a34551cc7..3b4a348289df 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -22,6 +22,14 @@ #define NOMINMAX #endif +// llvm/Support/Debug.h unconditionally #defines DEBUG as a macro. +// DIA headers #define it if it is not already defined, so we have +// an order of includes problem. The real fix is to make LLVM use +// something less generic than DEBUG, such as LLVM_DEBUG(), but it's +// fairly prevalent. So for now, we save the definition state and +// restore it. +#pragma push_macro("DEBUG") + // atlbase.h has to come before windows.h #include <atlbase.h> #include <windows.h> @@ -29,5 +37,8 @@ // DIA headers must come after windows headers. #include <cvconst.h> #include <dia2.h> +#include <diacreate.h> + +#pragma pop_macro("DEBUG") #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H diff --git a/include/llvm/DebugInfo/PDB/GenericError.h b/include/llvm/DebugInfo/PDB/GenericError.h new file mode 100644 index 000000000000..959c26161044 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/GenericError.h @@ -0,0 +1,42 @@ +//===- Error.h - system_error extensions for PDB ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_ERROR_H +#define LLVM_DEBUGINFO_PDB_ERROR_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { + +enum class generic_error_code { + invalid_path = 1, + dia_sdk_not_present, + unspecified, +}; + +/// Base class for errors originating when parsing raw PDB files +class GenericError : public ErrorInfo<GenericError> { +public: + static char ID; + GenericError(generic_error_code C); + GenericError(const std::string &Context); + GenericError(generic_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + generic_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/IPDBDataStream.h b/include/llvm/DebugInfo/PDB/IPDBDataStream.h index 808a0f3ec3a9..9594dc1591a7 100644 --- a/include/llvm/DebugInfo/PDB/IPDBDataStream.h +++ b/include/llvm/DebugInfo/PDB/IPDBDataStream.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" namespace llvm { +namespace pdb { /// IPDBDataStream defines an interface used to represent a stream consisting /// of a name and a series of records whose formats depend on the particular @@ -33,5 +34,6 @@ public: virtual IPDBDataStream *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h index 645ac96e23a5..8e9f6f883679 100644 --- a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h +++ b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h @@ -14,6 +14,7 @@ #include <memory> namespace llvm { +namespace pdb { template <typename ChildType> class IPDBEnumChildren { public: @@ -29,5 +30,6 @@ public: virtual MyType *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h index 92cd58d86649..e20080f2fbfc 100644 --- a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h +++ b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h @@ -13,7 +13,7 @@ #include "PDBTypes.h" namespace llvm { - +namespace pdb { class IPDBLineNumber { public: virtual ~IPDBLineNumber(); @@ -32,5 +32,6 @@ public: virtual bool isStatement() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 139bff56fd5d..49866b8bb2f2 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -13,12 +13,14 @@ #include "PDBTypes.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include <memory> namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBRawSymbol defines an interface used to represent an arbitrary symbol. /// It exposes a monolithic interface consisting of accessors for the union of /// all properties that are valid for any symbol type. This interface is then @@ -66,7 +68,7 @@ public: virtual uint32_t getLiveRangeStartAddressOffset() const = 0; virtual uint32_t getLiveRangeStartAddressSection() const = 0; virtual uint32_t getLiveRangeStartRelativeVirtualAddress() const = 0; - virtual PDB_RegisterId getLocalBasePointerRegisterId() const = 0; + virtual codeview::RegisterId getLocalBasePointerRegisterId() const = 0; virtual uint32_t getLowerBoundId() const = 0; virtual uint32_t getMemorySpaceKind() const = 0; virtual std::string getName() const = 0; @@ -81,7 +83,7 @@ public: virtual uint32_t getOffsetInUdt() const = 0; virtual PDB_Cpu getPlatform() const = 0; virtual uint32_t getRank() const = 0; - virtual PDB_RegisterId getRegisterId() const = 0; + virtual codeview::RegisterId getRegisterId() const = 0; virtual uint32_t getRegisterType() const = 0; virtual uint32_t getRelativeVirtualAddress() const = 0; virtual uint32_t getSamplerSlot() const = 0; @@ -117,7 +119,7 @@ public: virtual int32_t getVirtualBasePointerOffset() const = 0; virtual PDB_LocType getLocationType() const = 0; virtual PDB_Machine getMachineType() const = 0; - virtual PDB_ThunkOrdinal getThunkOrdinal() const = 0; + virtual codeview::ThunkOrdinal getThunkOrdinal() const = 0; virtual uint64_t getLength() const = 0; virtual uint64_t getLiveRangeLength() const = 0; virtual uint64_t getVirtualAddress() const = 0; @@ -206,6 +208,7 @@ public: virtual std::string getUnused() const = 0; }; +} // namespace pdb } // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index a130a38a6538..3d2c37eff2e3 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -11,11 +11,12 @@ #define LLVM_DEBUGINFO_PDB_IPDBSESSION_H #include "PDBTypes.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include <memory> namespace llvm { - +namespace pdb { class PDBSymbolCompiland; class PDBSymbolExe; @@ -45,9 +46,27 @@ public: virtual std::unique_ptr<PDBSymbol> findSymbolByAddress(uint64_t Address, PDB_SymType Type) const = 0; + + virtual std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const = 0; virtual std::unique_ptr<IPDBEnumLineNumbers> findLineNumbersByAddress(uint64_t Address, uint32_t Length) const = 0; + virtual std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const = 0; + virtual std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const = 0; virtual std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland(const PDBSymbolCompiland &Compiland) const = 0; @@ -57,5 +76,6 @@ public: virtual std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h index 55000eff02f0..3676c4030b13 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h +++ b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h @@ -15,9 +15,10 @@ #include <string> namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBSourceFile defines an interface used to represent source files whose /// information are stored in the PDB. class IPDBSourceFile { @@ -30,8 +31,10 @@ public: virtual uint32_t getUniqueId() const = 0; virtual std::string getChecksum() const = 0; virtual PDB_Checksum getChecksumType() const = 0; - virtual std::unique_ptr<IPDBEnumSymbols> getCompilands() const = 0; + virtual std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + getCompilands() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDB.h b/include/llvm/DebugInfo/PDB/PDB.h index 5df3be85e381..1f5a066b9a1b 100644 --- a/include/llvm/DebugInfo/PDB/PDB.h +++ b/include/llvm/DebugInfo/PDB/PDB.h @@ -11,16 +11,20 @@ #define LLVM_DEBUGINFO_PDB_PDB_H #include "PDBTypes.h" +#include "llvm/Support/Error.h" #include <memory> +#include <system_error> namespace llvm { class StringRef; -PDB_ErrorCode loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session); +namespace pdb { -PDB_ErrorCode loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session); -} +Error loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session); +Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session); +} +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBContext.h b/include/llvm/DebugInfo/PDB/PDBContext.h index 9404a5922449..836e39248438 100644 --- a/include/llvm/DebugInfo/PDB/PDBContext.h +++ b/include/llvm/DebugInfo/PDB/PDBContext.h @@ -17,43 +17,46 @@ namespace llvm { namespace object { class COFFObjectFile; -} - -/// PDBContext -/// This data structure is the top level entity that deals with PDB debug -/// information parsing. This data structure exists only when there is a -/// need for a transparent interface to different debug information formats -/// (e.g. PDB and DWARF). More control and power over the debug information -/// access can be had by using the PDB interfaces directly. -class PDBContext : public DIContext { - - PDBContext(PDBContext &) = delete; - PDBContext &operator=(PDBContext &) = delete; - -public: - PDBContext(const object::COFFObjectFile &Object, - std::unique_ptr<IPDBSession> PDBSession); - - static bool classof(const DIContext *DICtx) { - return DICtx->getKind() == CK_PDB; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; - - DILineInfo getLineInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DILineInfoTable getLineInfoForAddressRange( - uint64_t Address, uint64_t Size, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DIInliningInfo getInliningInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - -private: - std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; - std::unique_ptr<IPDBSession> Session; -}; + namespace pdb { + /// PDBContext + /// This data structure is the top level entity that deals with PDB debug + /// information parsing. This data structure exists only when there is a + /// need for a transparent interface to different debug information formats + /// (e.g. PDB and DWARF). More control and power over the debug information + /// access can be had by using the PDB interfaces directly. + class PDBContext : public DIContext { + + PDBContext(PDBContext &) = delete; + PDBContext &operator=(PDBContext &) = delete; + + public: + PDBContext(const object::COFFObjectFile &Object, + std::unique_ptr<IPDBSession> PDBSession); + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == CK_PDB; + } + + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; + + DILineInfo getLineInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DILineInfoTable getLineInfoForAddressRange( + uint64_t Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DIInliningInfo getInliningInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + + private: + std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; + std::unique_ptr<IPDBSession> Session; + }; + } } #endif diff --git a/include/llvm/DebugInfo/PDB/PDBExtras.h b/include/llvm/DebugInfo/PDB/PDBExtras.h index 48ce1c127196..5a7422d9e9e4 100644 --- a/include/llvm/DebugInfo/PDB/PDBExtras.h +++ b/include/llvm/DebugInfo/PDB/PDBExtras.h @@ -11,28 +11,33 @@ #define LLVM_DEBUGINFO_PDB_PDBEXTRAS_H #include "PDBTypes.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/Support/raw_ostream.h" #include <unordered_map> namespace llvm { + +namespace pdb { typedef std::unordered_map<PDB_SymType, int> TagStats; raw_ostream &operator<<(raw_ostream &OS, const PDB_VariantType &Value); raw_ostream &operator<<(raw_ostream &OS, const PDB_CallingConv &Conv); raw_ostream &operator<<(raw_ostream &OS, const PDB_DataKind &Data); -raw_ostream &operator<<(raw_ostream &OS, const PDB_RegisterId &Reg); +raw_ostream &operator<<(raw_ostream &OS, const codeview::RegisterId &Reg); raw_ostream &operator<<(raw_ostream &OS, const PDB_LocType &Loc); -raw_ostream &operator<<(raw_ostream &OS, const PDB_ThunkOrdinal &Thunk); +raw_ostream &operator<<(raw_ostream &OS, const codeview::ThunkOrdinal &Thunk); raw_ostream &operator<<(raw_ostream &OS, const PDB_Checksum &Checksum); raw_ostream &operator<<(raw_ostream &OS, const PDB_Lang &Lang); raw_ostream &operator<<(raw_ostream &OS, const PDB_SymType &Tag); raw_ostream &operator<<(raw_ostream &OS, const PDB_MemberAccess &Access); raw_ostream &operator<<(raw_ostream &OS, const PDB_UdtType &Type); raw_ostream &operator<<(raw_ostream &OS, const PDB_UniqueId &Id); +raw_ostream &operator<<(raw_ostream &OS, const PDB_Machine &Machine); raw_ostream &operator<<(raw_ostream &OS, const Variant &Value); raw_ostream &operator<<(raw_ostream &OS, const VersionInfo &Version); raw_ostream &operator<<(raw_ostream &OS, const TagStats &Stats); } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymDumper.h b/include/llvm/DebugInfo/PDB/PDBSymDumper.h index 65110f39366f..095c33cfe8b5 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymDumper.h +++ b/include/llvm/DebugInfo/PDB/PDBSymDumper.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymDumper { public: @@ -57,5 +58,6 @@ private: bool RequireImpl; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index 4360c5431e69..bf5118806540 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -15,9 +15,7 @@ #include "PDBExtras.h" #include "PDBTypes.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" -#include <unordered_map> #define FORWARD_SYMBOL_METHOD(MethodName) \ auto MethodName() const->decltype(RawSymbol->MethodName()) { \ @@ -26,9 +24,12 @@ namespace llvm { -class IPDBRawSymbol; +class StringRef; class raw_ostream; +namespace pdb { +class IPDBRawSymbol; + #define DECLARE_PDB_SYMBOL_CONCRETE_TYPE(TagValue) \ static const PDB_SymType Tag = TagValue; \ static bool classof(const PDBSymbol *S) { return S->getSymTag() == Tag; } @@ -41,7 +42,8 @@ class raw_ostream; /// https://msdn.microsoft.com/en-us/library/370hs6k4.aspx class PDBSymbol { protected: - PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol); + PDBSymbol(const IPDBSession &PDBSession, + std::unique_ptr<IPDBRawSymbol> Symbol); public: static std::unique_ptr<PDBSymbol> @@ -57,6 +59,7 @@ public: void defaultDump(raw_ostream &OS, int Indent) const; PDB_SymType getSymTag() const; + uint32_t getSymIndexId() const; template <typename T> std::unique_ptr<T> findOneChild() const { auto Enumerator(findAllChildren<T>()); @@ -93,5 +96,6 @@ protected: }; } // namespace llvm +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h index c055dd7f3d49..3169146e5b12 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h @@ -11,11 +11,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolAnnotation : public PDBSymbol { public: @@ -30,10 +30,10 @@ public: FORWARD_SYMBOL_METHOD(getAddressSection) FORWARD_SYMBOL_METHOD(getDataKind) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) // FORWARD_SYMBOL_METHOD(getValue) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLANNOTATION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h index 2ca12501d9f6..d0ff62ca7c3f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h @@ -11,12 +11,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolBlock : public PDBSymbol { public: PDBSymbolBlock(const IPDBSession &PDBSession, @@ -33,9 +34,9 @@ public: FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLBLOCK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h index f8c796ae5bdc..f1983b3f7bf5 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolCompiland : public PDBSymbol { public: PDBSymbolCompiland(const IPDBSession &PDBSession, @@ -30,9 +32,10 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getLibraryName) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSourceFileName) - FORWARD_SYMBOL_METHOD(getSymIndexId) + + std::string getSourceFileName() const; }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILAND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h index 7f29d6bde990..bb4a78f68e2f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolCompilandDetails : public PDBSymbol { public: @@ -47,9 +48,10 @@ public: FORWARD_SYMBOL_METHOD(getLanguage) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getPlatform) - FORWARD_SYMBOL_METHOD(getSymIndexId) + FORWARD_SYMBOL_METHOD(getSourceFileName) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBFUNCTION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h index 7e2ea9018edb..a71a0ba2df58 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h @@ -16,7 +16,7 @@ namespace llvm { class raw_ostream; - +namespace pdb { class PDBSymbolCompilandEnv : public PDBSymbol { public: PDBSymbolCompilandEnv(const IPDBSession &PDBSession, @@ -28,10 +28,10 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) std::string getValue() const; }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILANDENV_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h index 86bfd5707a31..54f089404262 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h @@ -18,6 +18,7 @@ namespace llvm { class raw_ostream; +namespace pdb { /// PDBSymbolCustom represents symbols that are compiler-specific and do not /// fit anywhere else in the lexical hierarchy. /// https://msdn.microsoft.com/en-us/library/d88sf09h.aspx @@ -31,9 +32,9 @@ public: void dump(PDBSymDumper &Dumper) const override; void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes); - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolData.h b/include/llvm/DebugInfo/PDB/PDBSymbolData.h index 79cbbf0e1683..36f32ab51c11 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolData.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolData.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolData : public PDBSymbol { public: PDBSymbolData(const IPDBSession &PDBSession, @@ -47,7 +49,6 @@ public: FORWARD_SYMBOL_METHOD(getRegisterId) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getSlot) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getToken) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -57,5 +58,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h index 7c5f302ad634..5b3f50d153eb 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h @@ -12,12 +12,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolExe : public PDBSymbol { public: PDBSymbolExe(const IPDBSession &PDBSession, @@ -35,12 +36,12 @@ public: FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getSignature) FORWARD_SYMBOL_METHOD(getSymbolsFileName) - FORWARD_SYMBOL_METHOD(getSymIndexId) private: void dumpChildren(raw_ostream &OS, StringRef Label, PDB_SymType ChildType, int Indent) const; }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLEXE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index 9db41d53532a..7170bcbe846c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFunc : public PDBSymbol { public: PDBSymbolFunc(const IPDBSession &PDBSession, @@ -64,7 +66,6 @@ public: FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getToken) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -76,5 +77,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h index 34d551cda74c..464389503bef 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFuncDebugEnd : public PDBSymbol { public: PDBSymbolFuncDebugEnd(const IPDBSession &PDBSession, @@ -40,10 +42,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h index 7671be480dac..c2e3dd39be6c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolFuncDebugStart : public PDBSymbol { public: @@ -40,10 +41,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGSTART_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h index 9d9903a11b0c..3aeae10b47bc 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolLabel : public PDBSymbol { public: @@ -40,10 +41,10 @@ public: FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOptimizedCodeDebugInfo) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLLABEL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h index 70dfcb5ddf4c..be0734445973 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolPublicSymbol : public PDBSymbol { public: @@ -36,12 +37,12 @@ public: FORWARD_SYMBOL_METHOD(isManagedCode) FORWARD_SYMBOL_METHOD(isMSILCode) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getVirtualAddress) FORWARD_SYMBOL_METHOD(getUndecoratedName) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLPUBLICSYMBOL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h index bd5a9b2aa8b3..63f7a09fc881 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h @@ -12,11 +12,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include <string> namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolThunk : public PDBSymbol { public: @@ -39,7 +39,6 @@ public: FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTargetOffset) FORWARD_SYMBOL_METHOD(getTargetRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getTargetVirtualAddress) @@ -53,5 +52,6 @@ public: FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTHUNK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h index 513a9ec05ff8..57db03661fb7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeArray : public PDBSymbol { public: @@ -34,12 +35,12 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getRank) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEARRAY_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h index 2a9a8a0788a8..aaa3ab7988d7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBaseClass : public PDBSymbol { public: @@ -42,7 +43,6 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -56,5 +56,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBASECLASS_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h index 69a2028a1b1d..c8f59f1f140a 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBuiltin : public PDBSymbol { public: @@ -30,11 +31,11 @@ public: FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBUILTIN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h index c41c48933e0d..199b3f8b304e 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeCustom : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getOemId) FORWARD_SYMBOL_METHOD(getOemSymbolId) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPECUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h index 3f22ed8d731e..e635eb5bbf6f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeDimension : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getLowerBoundId) FORWARD_SYMBOL_METHOD(getUpperBoundId) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEDIMENSION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h index 3188c711915c..ade2887bac14 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeEnum : public PDBSymbol { public: @@ -44,12 +45,12 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h index 4d393d7b6c5c..196d149ed2a2 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFriend : public PDBSymbol { public: @@ -28,10 +29,10 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFRIEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h index 14f79d99b6f8..5561341d7e77 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionArg : public PDBSymbol { public: @@ -28,10 +29,10 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONARG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h index 4bb4265a22f6..516011ff8b3d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionSig : public PDBSymbol { public: @@ -38,7 +39,6 @@ public: FORWARD_SYMBOL_METHOD(getCount) FORWARD_SYMBOL_METHOD(getLexicalParentId) // FORWARD_SYMBOL_METHOD(getObjectPointerType) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getThisAdjust) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -46,5 +46,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONSIG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h index cbfcec82a637..31cf5363dde1 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeManaged : public PDBSymbol { public: @@ -27,9 +28,9 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEMANAGED_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index 33578bad0245..7a57272adb79 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypePointer : public PDBSymbol { public: @@ -32,12 +33,12 @@ public: FORWARD_SYMBOL_METHOD(getLength) FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(isReference) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEPOINTER_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h index 5ad83bb1ec26..5ed4f8d21d90 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeTypedef : public PDBSymbol { public: @@ -41,7 +42,6 @@ public: FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isReference) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -50,5 +50,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPETYPEDEF_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index 99cc307a83e3..1874dfef34f7 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -17,6 +17,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeUDT : public PDBSymbol { public: PDBSymbolTypeUDT(const IPDBSession &PDBSession, @@ -40,13 +41,12 @@ public: FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) FORWARD_SYMBOL_METHOD(isVolatileType) }; - +} } // namespace llvm #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h index 6efc549f0cb7..baf7ab79d60e 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTable : public PDBSymbol { public: @@ -29,12 +30,12 @@ public: FORWARD_SYMBOL_METHOD(getClassParentId) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(getTypeId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h index f407595a4cc8..431fc1ac8625 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTableShape : public PDBSymbol { public: @@ -29,11 +30,11 @@ public: FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getCount) FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getSymIndexId) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLESHAPE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h index 94bd2c14079f..de43e47badbd 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUnknown : public PDBSymbol { public: @@ -30,5 +31,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUNKNOWN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h index 7072f342bef3..a273fe159c12 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUsingNamespace : public PDBSymbol { public: @@ -28,9 +29,9 @@ public: FORWARD_SYMBOL_METHOD(getLexicalParentId) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getSymIndexId) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUSINGNAMESPACE_H diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index a932a56bb953..a9325a434366 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -11,11 +11,13 @@ #define LLVM_DEBUGINFO_PDB_PDBTYPES_H #include "llvm/Config/llvm-config.h" -#include "llvm/Support/Endian.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include <functional> -#include <stdint.h> +#include <cstdint> +#include <cstring> namespace llvm { +namespace pdb { class PDBSymDumper; class PDBSymbol; @@ -68,14 +70,14 @@ class PDBSymbolUnknown; /// of PDB_ReaderType::DIA is supported. enum class PDB_ReaderType { DIA = 0, + Raw = 1, }; /// Defines a 128-bit unique identifier. This maps to a GUID on Windows, but /// is abstracted here for the purposes of non-Windows platforms that don't have /// the GUID structure defined. struct PDB_UniqueId { - uint64_t HighPart; - uint64_t LowPart; + char Guid[16]; }; /// An enumeration indicating the type of data contained in this table. @@ -108,67 +110,7 @@ enum class PDB_Checksum { None = 0, MD5 = 1, SHA1 = 2 }; /// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx -enum class PDB_Cpu { - Intel8080 = 0x0, - Intel8086 = 0x1, - Intel80286 = 0x2, - Intel80386 = 0x3, - Intel80486 = 0x4, - Pentium = 0x5, - PentiumPro = 0x6, - Pentium3 = 0x7, - MIPS = 0x10, - MIPS16 = 0x11, - MIPS32 = 0x12, - MIPS64 = 0x13, - MIPSI = 0x14, - MIPSII = 0x15, - MIPSIII = 0x16, - MIPSIV = 0x17, - MIPSV = 0x18, - M68000 = 0x20, - M68010 = 0x21, - M68020 = 0x22, - M68030 = 0x23, - M68040 = 0x24, - Alpha = 0x30, - Alpha21164 = 0x31, - Alpha21164A = 0x32, - Alpha21264 = 0x33, - Alpha21364 = 0x34, - PPC601 = 0x40, - PPC603 = 0x41, - PPC604 = 0x42, - PPC620 = 0x43, - PPCFP = 0x44, - PPCBE = 0x45, - SH3 = 0x50, - SH3E = 0x51, - SH3DSP = 0x52, - SH4 = 0x53, - SHMedia = 0x54, - ARM3 = 0x60, - ARM4 = 0x61, - ARM4T = 0x62, - ARM5 = 0x63, - ARM5T = 0x64, - ARM6 = 0x65, - ARM_XMAC = 0x66, - ARM_WMMX = 0x67, - ARM7 = 0x68, - Omni = 0x70, - Ia64 = 0x80, - Ia64_2 = 0x81, - CEE = 0x90, - AM33 = 0xa0, - M32R = 0xb0, - TriCore = 0xc0, - X64 = 0xd0, - EBC = 0xe0, - Thumb = 0xf0, - ARMNT = 0xf4, - D3D11_Shader = 0x100, -}; +typedef codeview::CPUType PDB_Cpu; enum class PDB_Machine { Invalid = 0xffff, @@ -200,56 +142,11 @@ enum class PDB_Machine { /// https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680207(v=vs.85).aspx /// -enum class PDB_CallingConv { - NearCdecl = 0x00, - FarCdecl = 0x01, - NearPascal = 0x02, - FarPascal = 0x03, - NearFastcall = 0x04, - FarFastcall = 0x05, - Skipped = 0x06, - NearStdcall = 0x07, - FarStdcall = 0x08, - NearSyscall = 0x09, - FarSyscall = 0x0a, - Thiscall = 0x0b, - MipsCall = 0x0c, - Generic = 0x0d, - Alphacall = 0x0e, - Ppccall = 0x0f, - SuperHCall = 0x10, - Armcall = 0x11, - AM33call = 0x12, - Tricall = 0x13, - Sh5call = 0x14, - M32R = 0x15, - Clrcall = 0x16, - Inline = 0x17, - NearVectorcall = 0x18, - Reserved = 0x19, -}; +typedef codeview::CallingConvention PDB_CallingConv; /// These values correspond to the CV_CFL_LANG enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx -enum class PDB_Lang { - C = 0x00, - Cpp = 0x01, - Fortran = 0x02, - Masm = 0x03, - Pascal = 0x04, - Basic = 0x05, - Cobol = 0x06, - Link = 0x07, - Cvtres = 0x08, - Cvtpgd = 0x09, - CSharp = 0x0a, - VB = 0x0b, - ILAsm = 0x0c, - Java = 0x0d, - JScript = 0x0e, - MSIL = 0x0f, - HLSL = 0x10 -}; +typedef codeview::SourceLanguage PDB_Lang; /// These values correspond to the DataKind enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2x2t313.aspx @@ -320,18 +217,6 @@ enum class PDB_LocType { Max }; -/// These values correspond to the THUNK_ORDINAL enumeration, and are documented -/// here: https://msdn.microsoft.com/en-us/library/dh0k8hft.aspx -enum class PDB_ThunkOrdinal { - Standard, - ThisAdjustor, - Vcall, - Pcode, - UnknownLoad, - TrampIncremental, - BranchIsland -}; - /// These values correspond to the UdtKind enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/wcstk66t.aspx enum class PDB_UdtType { Struct, Class, Union, Interface }; @@ -367,72 +252,8 @@ enum class PDB_BuiltinType { HResult = 31 }; -enum class PDB_RegisterId { - Unknown = 0, - VFrame = 30006, - AL = 1, - CL = 2, - DL = 3, - BL = 4, - AH = 5, - CH = 6, - DH = 7, - BH = 8, - AX = 9, - CX = 10, - DX = 11, - BX = 12, - SP = 13, - BP = 14, - SI = 15, - DI = 16, - EAX = 17, - ECX = 18, - EDX = 19, - EBX = 20, - ESP = 21, - EBP = 22, - ESI = 23, - EDI = 24, - ES = 25, - CS = 26, - SS = 27, - DS = 28, - FS = 29, - GS = 30, - IP = 31, - RAX = 328, - RBX = 329, - RCX = 330, - RDX = 331, - RSI = 332, - RDI = 333, - RBP = 334, - RSP = 335, - R8 = 336, - R9 = 337, - R10 = 338, - R11 = 339, - R12 = 340, - R13 = 341, - R14 = 342, - R15 = 343, -}; - enum class PDB_MemberAccess { Private = 1, Protected = 2, Public = 3 }; -enum class PDB_ErrorCode { - Success, - NoPdbImpl, - InvalidPath, - InvalidFileFormat, - InvalidParameter, - AlreadyLoaded, - UnknownError, - NoMemory, - DebugInfoMismatch -}; - struct VersionInfo { uint32_t Major; uint32_t Minor; @@ -454,11 +275,19 @@ enum PDB_VariantType { UInt32, UInt64, Bool, + String }; struct Variant { - Variant() - : Type(PDB_VariantType::Empty) { + Variant() : Type(PDB_VariantType::Empty) {} + + Variant(const Variant &Other) : Type(PDB_VariantType::Empty) { + *this = Other; + } + + ~Variant() { + if (Type == PDB_VariantType::String) + delete[] Value.String; } PDB_VariantType Type; @@ -474,10 +303,13 @@ struct Variant { uint16_t UInt16; uint32_t UInt32; uint64_t UInt64; - }; + char *String; + } Value; + #define VARIANT_EQUAL_CASE(Enum) \ case PDB_VariantType::Enum: \ - return Enum == Other.Enum; + return Value.Enum == Other.Value.Enum; + bool operator==(const Variant &Other) const { if (Type != Other.Type) return false; @@ -493,55 +325,43 @@ struct Variant { VARIANT_EQUAL_CASE(UInt16) VARIANT_EQUAL_CASE(UInt32) VARIANT_EQUAL_CASE(UInt64) + VARIANT_EQUAL_CASE(String) default: return true; } } + #undef VARIANT_EQUAL_CASE + bool operator!=(const Variant &Other) const { return !(*this == Other); } + Variant &operator=(const Variant &Other) { + if (this == &Other) + return *this; + if (Type == PDB_VariantType::String) + delete[] Value.String; + Type = Other.Type; + Value = Other.Value; + if (Other.Type == PDB_VariantType::String && + Other.Value.String != nullptr) { + Value.String = new char[strlen(Other.Value.String) + 1]; + ::strcpy(Value.String, Other.Value.String); + } + return *this; + } }; -namespace PDB { -static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', - 't', ' ', 'C', '/', 'C', '+', '+', ' ', - 'M', 'S', 'F', ' ', '7', '.', '0', '0', - '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; - -// The superblock is overlaid at the beginning of the file (offset 0). -// It starts with a magic header and is followed by information which describes -// the layout of the file system. -struct SuperBlock { - char MagicBytes[sizeof(Magic)]; - // The file system is split into a variable number of fixed size elements. - // These elements are referred to as blocks. The size of a block may vary - // from system to system. - support::ulittle32_t BlockSize; - // This field's purpose is not yet known. - support::ulittle32_t Unknown0; - // This contains the number of blocks resident in the file system. In - // practice, NumBlocks * BlockSize is equivalent to the size of the PDB file. - support::ulittle32_t NumBlocks; - // This contains the number of bytes which make up the directory. - support::ulittle32_t NumDirectoryBytes; - // This field's purpose is not yet known. - support::ulittle32_t Unknown1; - // This contains the block # of the block map. - support::ulittle32_t BlockMapAddr; -}; +} // end namespace llvm } -} // namespace llvm - namespace std { -template <> struct hash<llvm::PDB_SymType> { - typedef llvm::PDB_SymType argument_type; +template <> struct hash<llvm::pdb::PDB_SymType> { + typedef llvm::pdb::PDB_SymType argument_type; typedef std::size_t result_type; result_type operator()(const argument_type &Arg) const { return std::hash<int>()(static_cast<int>(Arg)); } }; -} - +} // end namespace std -#endif +#endif // LLVM_DEBUGINFO_PDB_PDBTYPES_H diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h new file mode 100644 index 000000000000..6ab3c8067558 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -0,0 +1,149 @@ +//===- DbiStream.h - PDB Dbi Stream (Stream 3) Access -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H + +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace object { +struct FpoData; +struct coff_section; +} + +namespace pdb { +class DbiStreamBuilder; +class PDBFile; +class ISectionContribVisitor; + +class DbiStream { + friend class DbiStreamBuilder; + + struct HeaderInfo { + support::little32_t VersionSignature; + support::ulittle32_t VersionHeader; + support::ulittle32_t Age; // Should match InfoStream. + support::ulittle16_t GlobalSymbolStreamIndex; // Global symbol stream # + support::ulittle16_t BuildNumber; // See DbiBuildNo structure. + support::ulittle16_t PublicSymbolStreamIndex; // Public symbols stream # + support::ulittle16_t PdbDllVersion; // version of mspdbNNN.dll + support::ulittle16_t SymRecordStreamIndex; // Symbol records stream # + support::ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll + support::little32_t ModiSubstreamSize; // Size of module info stream + support::little32_t SecContrSubstreamSize; // Size of sec. contrib stream + support::little32_t SectionMapSize; // Size of sec. map substream + support::little32_t FileInfoSize; // Size of file info substream + support::little32_t TypeServerSize; // Size of type server map + support::ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server + support::little32_t OptionalDbgHdrSize; // Size of DbgHeader info + support::little32_t ECSubstreamSize; // Size of EC stream (what is EC?) + support::ulittle16_t Flags; // See DbiFlags enum. + support::ulittle16_t MachineType; // See PDB_MachineType enum. + + support::ulittle32_t Reserved; // Pad to 64 bytes + }; + +public: + DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~DbiStream(); + Error reload(); + + PdbRaw_DbiVer getDbiVersion() const; + uint32_t getAge() const; + uint16_t getPublicSymbolStreamIndex() const; + uint16_t getGlobalSymbolStreamIndex() const; + + uint16_t getFlags() const; + bool isIncrementallyLinked() const; + bool hasCTypes() const; + bool isStripped() const; + + uint16_t getBuildNumber() const; + uint16_t getBuildMajorVersion() const; + uint16_t getBuildMinorVersion() const; + + uint16_t getPdbDllRbld() const; + uint32_t getPdbDllVersion() const; + + uint32_t getSymRecordStreamIndex() const; + + PDB_Machine getMachineType() const; + + enum { InvalidStreamIndex = 0xffff }; + + /// If the given stream type is present, returns its stream index. If it is + /// not present, returns InvalidStreamIndex. + uint32_t getDebugStreamIndex(DbgHeaderType Type) const; + + ArrayRef<ModuleInfoEx> modules() const; + + Expected<StringRef> getFileNameForIndex(uint32_t Index) const; + + codeview::FixedStreamArray<object::coff_section> getSectionHeaders(); + + codeview::FixedStreamArray<object::FpoData> getFpoRecords(); + + codeview::FixedStreamArray<SecMapEntry> getSectionMap() const; + void visitSectionContributions(ISectionContribVisitor &Visitor) const; + + Error commit(); + +private: + Error initializeSectionContributionData(); + Error initializeSectionHeadersData(); + Error initializeSectionMapData(); + Error initializeFileInfo(); + Error initializeFpoRecords(); + + PDBFile &Pdb; + std::unique_ptr<MappedBlockStream> Stream; + + std::vector<ModuleInfoEx> ModuleInfos; + NameHashTable ECNames; + + codeview::StreamRef ModInfoSubstream; + codeview::StreamRef SecContrSubstream; + codeview::StreamRef SecMapSubstream; + codeview::StreamRef FileInfoSubstream; + codeview::StreamRef TypeServerMapSubstream; + codeview::StreamRef ECSubstream; + + codeview::StreamRef NamesBuffer; + + codeview::FixedStreamArray<support::ulittle16_t> DbgStreams; + + PdbRaw_DbiSecContribVer SectionContribVersion; + codeview::FixedStreamArray<SectionContrib> SectionContribs; + codeview::FixedStreamArray<SectionContrib2> SectionContribs2; + codeview::FixedStreamArray<SecMapEntry> SectionMap; + codeview::FixedStreamArray<support::little32_t> FileNameOffsets; + + std::unique_ptr<MappedBlockStream> SectionHeaderStream; + codeview::FixedStreamArray<object::coff_section> SectionHeaders; + + std::unique_ptr<MappedBlockStream> FpoStream; + codeview::FixedStreamArray<object::FpoData> FpoRecords; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h new file mode 100644 index 000000000000..2c7350f3c3e7 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h @@ -0,0 +1,56 @@ +//===- DbiStreamBuilder.h - PDB Dbi Stream Creation -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class DbiStreamBuilder { +public: + DbiStreamBuilder(); + + DbiStreamBuilder(const DbiStreamBuilder &) = delete; + DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; + + void setVersionHeader(PdbRaw_DbiVer V); + void setAge(uint32_t A); + void setBuildNumber(uint16_t B); + void setPdbDllVersion(uint16_t V); + void setPdbDllRbld(uint16_t R); + void setFlags(uint16_t F); + void setMachineType(PDB_Machine M); + + uint32_t calculateSerializedLength() const; + + Expected<std::unique_ptr<DbiStream>> build(PDBFile &File); + +private: + Optional<PdbRaw_DbiVer> VerHeader; + uint32_t Age; + uint16_t BuildNumber; + uint16_t PdbDllVersion; + uint16_t PdbDllRbld; + uint16_t Flags; + PDB_Machine MachineType; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h new file mode 100644 index 000000000000..0f354315122c --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h @@ -0,0 +1,37 @@ +//===- DirectoryStreamData.h ---------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_DIRECTORYSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_DIRECTORYSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class DirectoryStreamData : public IPDBStreamData { +public: + DirectoryStreamData(const PDBFile &File) : File(File) {} + + virtual uint32_t getLength() { return File.getNumDirectoryBytes(); } + virtual llvm::ArrayRef<llvm::support::ulittle32_t> getStreamBlocks() { + return File.getDirectoryBlockArray(); + } + +private: + const PDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/EnumTables.h b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h new file mode 100644 index 000000000000..c018445630fe --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h @@ -0,0 +1,22 @@ +//===- EnumTables.h - Enum to string conversion tables ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H +#define LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace pdb { +ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames(); +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H diff --git a/include/llvm/DebugInfo/PDB/Raw/Hash.h b/include/llvm/DebugInfo/PDB/Raw/Hash.h new file mode 100644 index 000000000000..0340554d7b0b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/Hash.h @@ -0,0 +1,25 @@ +//===- Hash.h - PDB hash functions ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_HASH_H +#define LLVM_DEBUGINFO_PDB_RAW_HASH_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <stdint.h> + +namespace llvm { +namespace pdb { +uint32_t hashStringV1(StringRef Str); +uint32_t hashStringV2(StringRef Str); +uint32_t hashBufferV8(ArrayRef<uint8_t> Data); +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h new file mode 100644 index 000000000000..fccea2ac2470 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h @@ -0,0 +1,44 @@ +//===- IPDBFile.h - Abstract base class for a PDB file ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <stdint.h> + +namespace llvm { +namespace pdb { + +class IPDBFile { +public: + virtual ~IPDBFile() {} + + virtual uint32_t getBlockSize() const = 0; + virtual uint32_t getBlockCount() const = 0; + + virtual uint32_t getNumStreams() const = 0; + virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0; + virtual ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const = 0; + + virtual Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const = 0; + virtual Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const = 0; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h new file mode 100644 index 000000000000..ab3c9f770755 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h @@ -0,0 +1,38 @@ +//===- IPDBStreamData.h - Base interface for PDB Stream Data ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +/// IPDBStream abstracts the notion of PDB stream data. Although we already +/// have another stream abstraction (namely in the form of StreamInterface +/// and MappedBlockStream), they assume that the stream data is referenced +/// the same way. Namely, by looking in the directory to get the list of +/// stream blocks, and by looking in the array of stream lengths to get the +/// length. This breaks down for the directory itself, however, since its +/// length and list of blocks are stored elsewhere. By abstracting the +/// notion of stream data further, we can use a MappedBlockStream to read +/// from the directory itself, or from an indexed stream which references +/// the directory. +class IPDBStreamData { +public: + virtual ~IPDBStreamData() {} + + virtual uint32_t getLength() = 0; + virtual ArrayRef<support::ulittle32_t> getStreamBlocks() = 0; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h new file mode 100644 index 000000000000..355a25a38ef8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h @@ -0,0 +1,28 @@ +//===- ISectionContribVisitor.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H +#define LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H + +namespace llvm { +namespace pdb { +struct SectionContrib; +struct SectionContrib2; + +class ISectionContribVisitor { +public: + virtual ~ISectionContribVisitor() {} + + virtual void visit(const SectionContrib &C) = 0; + virtual void visit(const SectionContrib2 &C) = 0; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h new file mode 100644 index 000000000000..30563bc5b898 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h @@ -0,0 +1,34 @@ +//===- IndexedStreamData.h - Standard PDB Stream Data -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H + +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class IndexedStreamData : public IPDBStreamData { +public: + IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File); + virtual ~IndexedStreamData() {} + + uint32_t getLength() override; + ArrayRef<support::ulittle32_t> getStreamBlocks() override; + +private: + uint32_t StreamIdx; + const IPDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h new file mode 100644 index 000000000000..1980bec7153e --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -0,0 +1,77 @@ +//===- InfoStream.h - PDB Info Stream (Stream 1) Access ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/NameMap.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class InfoStreamBuilder; +class PDBFile; + +class InfoStream { + friend class InfoStreamBuilder; + + struct HeaderInfo { + support::ulittle32_t Version; + support::ulittle32_t Signature; + support::ulittle32_t Age; + PDB_UniqueId Guid; + }; + +public: + InfoStream(std::unique_ptr<MappedBlockStream> Stream); + + Error reload(); + Error commit(); + + PdbRaw_ImplVer getVersion() const; + uint32_t getSignature() const; + uint32_t getAge() const; + PDB_UniqueId getGuid() const; + + uint32_t getNamedStreamIndex(llvm::StringRef Name) const; + iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; + +private: + std::unique_ptr<MappedBlockStream> Stream; + + // PDB file format version. We only support VC70. See the enumeration + // `PdbRaw_ImplVer` for the other possible values. + uint32_t Version; + + // A 32-bit signature unique across all PDBs. This is generated with + // a call to time() when the PDB is written, but obviously this is not + // universally unique. + uint32_t Signature; + + // The number of times the PDB has been written. Might also be used to + // ensure that the PDB matches the executable. + uint32_t Age; + + // Due to the aforementioned limitations with `Signature`, this is a new + // signature present on VC70 and higher PDBs which is guaranteed to be + // universally unique. + PDB_UniqueId Guid; + + NameMap NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h new file mode 100644 index 000000000000..e9869bb27863 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h @@ -0,0 +1,53 @@ +//===- InfoStreamBuilder.h - PDB Info Stream Creation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class InfoStreamBuilder { +public: + InfoStreamBuilder(); + InfoStreamBuilder(const InfoStreamBuilder &) = delete; + InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; + + void setVersion(PdbRaw_ImplVer V); + void setSignature(uint32_t S); + void setAge(uint32_t A); + void setGuid(PDB_UniqueId G); + + NameMapBuilder &getNamedStreamsBuilder(); + + uint32_t calculateSerializedLength() const; + + Expected<std::unique_ptr<InfoStream>> build(PDBFile &File); + +private: + Optional<PdbRaw_ImplVer> Ver; + Optional<uint32_t> Sig; + Optional<uint32_t> Age; + Optional<PDB_UniqueId> Guid; + + NameMapBuilder NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h new file mode 100644 index 000000000000..36424c0d16ab --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -0,0 +1,68 @@ +//===- MappedBlockStream.h - Reads stream data from a PDBFile ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace pdb { + +class IPDBFile; +class PDBFile; + +class MappedBlockStream : public codeview::StreamInterface { +public: + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) const override; + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override; + + uint32_t getLength() const override; + Error commit() const override; + + uint32_t getNumBytesCopied() const; + + static Expected<std::unique_ptr<MappedBlockStream>> + createIndexedStream(uint32_t StreamIdx, const IPDBFile &File); + static Expected<std::unique_ptr<MappedBlockStream>> + createDirectoryStream(const PDBFile &File); + + llvm::BumpPtrAllocator &getAllocator() { return Pool; } + +protected: + MappedBlockStream(std::unique_ptr<IPDBStreamData> Data, const IPDBFile &File); + + Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const; + bool tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const; + + const IPDBFile &Pdb; + std::unique_ptr<IPDBStreamData> Data; + + typedef MutableArrayRef<uint8_t> CacheEntry; + mutable llvm::BumpPtrAllocator Pool; + mutable DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h new file mode 100644 index 000000000000..b8da0bfabf38 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -0,0 +1,79 @@ +//===- ModInfo.h - PDB module information -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MODINFO_H +#define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace pdb { + +class ModInfo { +private: + struct FileLayout; + +public: + ModInfo(); + ModInfo(const ModInfo &Info); + ~ModInfo(); + + static Error initialize(codeview::StreamRef Stream, ModInfo &Info); + + bool hasECInfo() const; + uint16_t getTypeServerIndex() const; + uint16_t getModuleStreamIndex() const; + uint32_t getSymbolDebugInfoByteSize() const; + uint32_t getLineInfoByteSize() const; + uint32_t getC13LineInfoByteSize() const; + uint32_t getNumberOfFiles() const; + uint32_t getSourceFileNameIndex() const; + uint32_t getPdbFilePathNameIndex() const; + + StringRef getModuleName() const; + StringRef getObjFileName() const; + + uint32_t getRecordLength() const; + +private: + StringRef ModuleName; + StringRef ObjFileName; + const FileLayout *Layout; +}; + +struct ModuleInfoEx { + ModuleInfoEx(const ModInfo &Info) : Info(Info) {} + ModuleInfoEx(const ModuleInfoEx &Ex) + : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} + + ModInfo Info; + std::vector<StringRef> SourceFiles; +}; + +} // end namespace pdb + +namespace codeview { +template <> struct VarStreamArrayExtractor<pdb::ModInfo> { + Error operator()(StreamRef Stream, uint32_t &Length, + pdb::ModInfo &Info) const { + if (auto EC = pdb::ModInfo::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/include/llvm/DebugInfo/PDB/Raw/ModStream.h new file mode 100644 index 000000000000..d22962cc1e28 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -0,0 +1,57 @@ +//===- ModStream.h - PDB Module Info Stream Access ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; +class ModInfo; + +class ModStream { +public: + ModStream(const ModInfo &Module, std::unique_ptr<MappedBlockStream> Stream); + ~ModStream(); + + Error reload(); + + iterator_range<codeview::CVSymbolArray::Iterator> + symbols(bool *HadError) const; + + iterator_range<codeview::ModuleSubstreamArray::Iterator> + lines(bool *HadError) const; + + Error commit(); + +private: + const ModInfo &Mod; + + std::unique_ptr<MappedBlockStream> Stream; + + codeview::CVSymbolArray SymbolsSubstream; + codeview::StreamRef LinesSubstream; + codeview::StreamRef C13LinesSubstream; + codeview::StreamRef GlobalRefsSubstream; + + codeview::ModuleSubstreamArray LineInfo; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h b/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h new file mode 100644 index 000000000000..92d9bc042cce --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h @@ -0,0 +1,141 @@ +//===- MSFBuilder.h - MSF Directory & Metadata Builder ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <utility> +#include <vector> + +namespace llvm { +namespace pdb { +class MsfBuilder { +public: + /// \brief Create a new `MsfBuilder`. + /// + /// \param BlockSize The internal block size used by the PDB file. See + /// isValidBlockSize() for a list of valid block sizes. + /// + /// \param MinBlockCount Causes the builder to reserve up front space for + /// at least `MinBlockCount` blocks. This is useful when using `MsfBuilder` + /// to read an existing PDB that you want to write back out later. The + /// original PDB file's SuperBlock contains the exact number of blocks used + /// by the file, so is a good hint as to how many blocks the new PDB file + /// will contain. Furthermore, it is actually necessary in this case. To + /// preserve stability of the file's layout, it is helpful to try to keep + /// all streams mapped to their original block numbers. To ensure that this + /// is possible, space for all blocks must be allocated beforehand so that + /// streams can be assigned to them. + /// + /// \param CanGrow If true, any operation which results in an attempt to + /// locate a free block when all available blocks have been exhausted will + /// allocate a new block, thereby growing the size of the final PDB file. + /// When false, any such attempt will result in an error. This is especially + /// useful in testing scenarios when you know your test isn't going to do + /// anything to increase the size of the file, so having an Error returned if + /// it were to happen would catch a programming error + /// + /// \returns an llvm::Error representing whether the operation succeeded or + /// failed. Currently the only way this can fail is if an invalid block size + /// is specified, or `MinBlockCount` does not leave enough room for the + /// mandatory reserved blocks required by an MSF file. + static Expected<MsfBuilder> create(BumpPtrAllocator &Allocator, + uint32_t BlockSize, + uint32_t MinBlockCount = 0, + bool CanGrow = true); + + /// Request the block map to be at a specific block address. This is useful + /// when editing a PDB and you want the layout to be as stable as possible. + Error setBlockMapAddr(uint32_t Addr); + Error setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks); + void setFreePageMap(uint32_t Fpm); + void setUnknown1(uint32_t Unk1); + + /// Add a stream to the MSF file with the given size, occupying the given + /// list of blocks. This is useful when reading a PDB file and you want a + /// particular stream to occupy the original set of blocks. If the given + /// blocks are already allocated, or if the number of blocks specified is + /// incorrect for the given stream size, this function will return an Error. + Error addStream(uint32_t Size, ArrayRef<uint32_t> Blocks); + + /// Add a stream to the MSF file with the given size, occupying any available + /// blocks that the builder decides to use. This is useful when building a + /// new PDB file from scratch and you don't care what blocks a stream occupies + /// but you just want it to work. + Error addStream(uint32_t Size); + + /// Update the size of an existing stream. This will allocate or deallocate + /// blocks as needed to match the requested size. This can fail if `CanGrow` + /// was set to false when initializing the `MsfBuilder`. + Error setStreamSize(uint32_t Idx, uint32_t Size); + + /// Get the total number of streams in the MSF layout. This should return 1 + /// for every call to `addStream`. + uint32_t getNumStreams() const; + + /// Get the size of a stream by index. + uint32_t getStreamSize(uint32_t StreamIdx) const; + + /// Get the list of blocks allocated to a particular stream. + ArrayRef<uint32_t> getStreamBlocks(uint32_t StreamIdx) const; + + /// Get the total number of blocks that will be allocated to actual data in + /// this MSF file. + uint32_t getNumUsedBlocks() const; + + /// Get the total number of blocks that exist in the MSF file but are not + /// allocated to any valid data. + uint32_t getNumFreeBlocks() const; + + /// Get the total number of blocks in the MSF file. In practice this is equal + /// to `getNumUsedBlocks() + getNumFreeBlocks()`. + uint32_t getTotalBlockCount() const; + + /// Check whether a particular block is allocated or free. + bool isBlockFree(uint32_t Idx) const; + + /// Finalize the layout and build the headers and structures that describe the + /// MSF layout and can be written directly to the MSF file. + Expected<msf::Layout> build(); + +private: + MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, + BumpPtrAllocator &Allocator); + + Error allocateBlocks(uint32_t NumBlocks, MutableArrayRef<uint32_t> Blocks); + uint32_t computeDirectoryByteSize() const; + + typedef std::vector<uint32_t> BlockList; + + BumpPtrAllocator &Allocator; + + bool IsGrowable; + uint32_t FreePageMap; + uint32_t Unknown1; + uint32_t BlockSize; + uint32_t MininumBlocks; + uint32_t BlockMapAddr; + BitVector FreeBlocks; + std::vector<uint32_t> DirectoryBlocks; + std::vector<std::pair<uint32_t, BlockList>> StreamData; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h b/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h new file mode 100644 index 000000000000..2f6a6986eba9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h @@ -0,0 +1,90 @@ +//===- MsfCommon.h - Common types and functions for MSF files ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MSFCOMMON_H +#define LLVM_DEBUGINFO_PDB_RAW_MSFCOMMON_H + +#include "llvm/ADT/ArrayRef.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include <vector> + +namespace llvm { +namespace pdb { +namespace msf { +static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'C', '/', 'C', '+', '+', ' ', + 'M', 'S', 'F', ' ', '7', '.', '0', '0', + '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; + +// The superblock is overlaid at the beginning of the file (offset 0). +// It starts with a magic header and is followed by information which +// describes the layout of the file system. +struct SuperBlock { + char MagicBytes[sizeof(Magic)]; + // The file system is split into a variable number of fixed size elements. + // These elements are referred to as blocks. The size of a block may vary + // from system to system. + support::ulittle32_t BlockSize; + // The index of the free block map. + support::ulittle32_t FreeBlockMapBlock; + // This contains the number of blocks resident in the file system. In + // practice, NumBlocks * BlockSize is equivalent to the size of the PDB + // file. + support::ulittle32_t NumBlocks; + // This contains the number of bytes which make up the directory. + support::ulittle32_t NumDirectoryBytes; + // This field's purpose is not yet known. + support::ulittle32_t Unknown1; + // This contains the block # of the block map. + support::ulittle32_t BlockMapAddr; +}; + +struct Layout { + SuperBlock *SB; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + ArrayRef<support::ulittle32_t> StreamSizes; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; +}; + +inline bool isValidBlockSize(uint32_t Size) { + switch (Size) { + case 512: + case 1024: + case 2048: + case 4096: + return true; + } + return false; +} + +// Super Block, Fpm0, Fpm1, and Block Map +inline uint32_t getMinimumBlockCount() { return 4; } + +// Super Block, Fpm0, and Fpm1 are reserved. The Block Map, although required +// need not be at block 3. +inline uint32_t getFirstUnreservedBlock() { return 3; } + +inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { + return alignTo(NumBytes, BlockSize) / BlockSize; +} + +inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { + return BlockNumber * BlockSize; +} + +Error validateSuperBlock(const SuperBlock &SB); +} +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h new file mode 100644 index 000000000000..c9e060a3a70f --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -0,0 +1,54 @@ +//===- NameHashTable.h - PDB Name Hash Table --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <vector> + +namespace llvm { +namespace codeview { +class StreamReader; +} +namespace pdb { + +class NameHashTable { +public: + NameHashTable(); + + Error load(codeview::StreamReader &Stream); + + uint32_t getNameCount() const { return NameCount; } + uint32_t getHashVersion() const { return HashVersion; } + uint32_t getSignature() const { return Signature; } + + StringRef getStringForID(uint32_t ID) const; + uint32_t getIDForString(StringRef Str) const; + + codeview::FixedStreamArray<support::ulittle32_t> name_ids() const; + +private: + codeview::StreamRef NamesBuffer; + codeview::FixedStreamArray<support::ulittle32_t> IDs; + uint32_t Signature; + uint32_t HashVersion; + uint32_t NameCount; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMap.h b/include/llvm/DebugInfo/PDB/Raw/NameMap.h new file mode 100644 index 000000000000..8a9b0d187ace --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameMap.h @@ -0,0 +1,45 @@ +//===- NameMap.h - PDB Name Map ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { +namespace codeview { +class StreamReader; +class StreamWriter; +} +namespace pdb { +class NameMapBuilder; +class NameMap { + friend NameMapBuilder; + +public: + NameMap(); + + Error load(codeview::StreamReader &Stream); + Error commit(codeview::StreamWriter &Writer); + + bool tryGetValue(StringRef Name, uint32_t &Value) const; + + iterator_range<StringMapConstIterator<uint32_t>> entries() const; + +private: + StringMap<uint32_t> Mapping; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h b/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h new file mode 100644 index 000000000000..bf49bfd9bf2e --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h @@ -0,0 +1,41 @@ +//===- NameMapBuilder.h - PDB Name Map Builder ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Error.h" + +#include <cstdint> +#include <memory> + +namespace llvm { +namespace pdb { +class NameMap; + +class NameMapBuilder { +public: + NameMapBuilder(); + + void addMapping(StringRef Name, uint32_t Mapping); + + Expected<std::unique_ptr<NameMap>> build(); + + uint32_t calculateSerializedLength() const; + +private: + StringMap<uint32_t> Map; + uint32_t StringDataBytes = 0; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h new file mode 100644 index 000000000000..f4d7eb47d3b9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -0,0 +1,113 @@ +//===- PDBFile.h - Low level interface to a PDB file ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include <memory> + +namespace llvm { + +namespace codeview { +class StreamInterface; +} + +namespace pdb { +class DbiStream; +class InfoStream; +class MappedBlockStream; +class NameHashTable; +class PDBFileBuilder; +class PublicsStream; +class SymbolStream; +class TpiStream; + +class PDBFile : public IPDBFile { + friend PDBFileBuilder; + +public: + explicit PDBFile(std::unique_ptr<codeview::StreamInterface> PdbFileBuffer); + ~PDBFile() override; + + uint32_t getFreeBlockMapBlock() const; + uint32_t getUnknown1() const; + + uint32_t getBlockSize() const override; + uint32_t getBlockCount() const override; + uint32_t getNumDirectoryBytes() const; + uint32_t getBlockMapIndex() const; + uint32_t getNumDirectoryBlocks() const; + uint64_t getBlockMapOffset() const; + + uint32_t getNumStreams() const override; + uint32_t getStreamByteSize(uint32_t StreamIndex) const override; + ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const override; + uint32_t getFileSize() const; + + Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const override; + Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const override; + + ArrayRef<support::ulittle32_t> getStreamSizes() const { return StreamSizes; } + ArrayRef<ArrayRef<support::ulittle32_t>> getStreamMap() const { + return StreamMap; + } + + ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; + + Error parseFileHeaders(); + Error parseStreamData(); + + Expected<InfoStream &> getPDBInfoStream(); + Expected<DbiStream &> getPDBDbiStream(); + Expected<TpiStream &> getPDBTpiStream(); + Expected<TpiStream &> getPDBIpiStream(); + Expected<PublicsStream &> getPDBPublicsStream(); + Expected<SymbolStream &> getPDBSymbolStream(); + Expected<NameHashTable &> getStringTable(); + + Error commit(); + +private: + Error setSuperBlock(const msf::SuperBlock *Block); + + BumpPtrAllocator Allocator; + + std::unique_ptr<codeview::StreamInterface> Buffer; + const msf::SuperBlock *SB; + ArrayRef<support::ulittle32_t> StreamSizes; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; + + std::unique_ptr<InfoStream> Info; + std::unique_ptr<DbiStream> Dbi; + std::unique_ptr<TpiStream> Tpi; + std::unique_ptr<TpiStream> Ipi; + std::unique_ptr<PublicsStream> Publics; + std::unique_ptr<SymbolStream> Symbols; + std::unique_ptr<MappedBlockStream> DirectoryStream; + std::unique_ptr<MappedBlockStream> StringTableStream; + std::unique_ptr<NameHashTable> StringTable; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h new file mode 100644 index 000000000000..47c755b43269 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h @@ -0,0 +1,59 @@ +//===- PDBFileBuilder.h - PDB File Creation ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { +class StreamInterface; +} +namespace pdb { +class DbiStreamBuilder; +class InfoStreamBuilder; +class PDBFile; + +class PDBFileBuilder { +public: + explicit PDBFileBuilder( + std::unique_ptr<codeview::StreamInterface> FileBuffer); + PDBFileBuilder(const PDBFileBuilder &) = delete; + PDBFileBuilder &operator=(const PDBFileBuilder &) = delete; + + Error initialize(const msf::SuperBlock &Super); + + MsfBuilder &getMsfBuilder(); + InfoStreamBuilder &getInfoBuilder(); + DbiStreamBuilder &getDbiBuilder(); + + Expected<std::unique_ptr<PDBFile>> build(); + +private: + std::unique_ptr<InfoStreamBuilder> Info; + std::unique_ptr<DbiStreamBuilder> Dbi; + + std::unique_ptr<PDBFile> File; + std::unique_ptr<MsfBuilder> Msf; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h new file mode 100644 index 000000000000..f5bfb0ed60a9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h @@ -0,0 +1,74 @@ +//===- PublicsStream.h - PDB Public Symbol Stream -------- ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class PublicsStream { + struct GSIHashHeader; + struct HeaderInfo; + +public: + PublicsStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~PublicsStream(); + Error reload(); + + uint32_t getSymHash() const; + uint32_t getAddrMap() const; + uint32_t getNumBuckets() const { return NumBuckets; } + iterator_range<codeview::CVSymbolArray::Iterator> + getSymbols(bool *HadError) const; + codeview::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { + return HashBuckets; + } + codeview::FixedStreamArray<support::ulittle32_t> getAddressMap() const { + return AddressMap; + } + codeview::FixedStreamArray<support::ulittle32_t> getThunkMap() const { + return ThunkMap; + } + codeview::FixedStreamArray<SectionOffset> getSectionOffsets() const { + return SectionOffsets; + } + + Error commit(); + +private: + PDBFile &Pdb; + + std::unique_ptr<MappedBlockStream> Stream; + uint32_t NumBuckets = 0; + ArrayRef<uint8_t> Bitmap; + codeview::FixedStreamArray<PSHashRecord> HashRecords; + codeview::FixedStreamArray<support::ulittle32_t> HashBuckets; + codeview::FixedStreamArray<support::ulittle32_t> AddressMap; + codeview::FixedStreamArray<support::ulittle32_t> ThunkMap; + codeview::FixedStreamArray<SectionOffset> SectionOffsets; + + const HeaderInfo *Header; + const GSIHashHeader *HashHdr; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawConstants.h b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h new file mode 100644 index 000000000000..8daaf47882d8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h @@ -0,0 +1,94 @@ +//===- RawConstants.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" + +#include <cstdint> + +namespace llvm { +namespace pdb { + +enum PdbRaw_ImplVer : uint32_t { + PdbImplVC2 = 19941610, + PdbImplVC4 = 19950623, + PdbImplVC41 = 19950814, + PdbImplVC50 = 19960307, + PdbImplVC98 = 19970604, + PdbImplVC70Dep = 19990604, // deprecated + PdbImplVC70 = 20000404, + PdbImplVC80 = 20030901, + PdbImplVC110 = 20091201, + PdbImplVC140 = 20140508, +}; + +enum PdbRaw_DbiVer : uint32_t { + PdbDbiVC41 = 930803, + PdbDbiV50 = 19960307, + PdbDbiV60 = 19970606, + PdbDbiV70 = 19990903, + PdbDbiV110 = 20091201 +}; + +enum PdbRaw_TpiVer : uint32_t { + PdbTpiV40 = 19950410, + PdbTpiV41 = 19951122, + PdbTpiV50 = 19961031, + PdbTpiV70 = 19990903, + PdbTpiV80 = 20040203, +}; + +enum PdbRaw_DbiSecContribVer : uint32_t { + DbiSecContribVer60 = 0xeffe0000 + 19970605, + DbiSecContribV2 = 0xeffe0000 + 20140516 +}; + +enum SpecialStream : uint32_t { + // Stream 0 contains the copy of previous version of the MSF directory. + // We are not currently using it, but technically if we find the main + // MSF is corrupted, we could fallback to it. + OldMSFDirectory = 0, + + StreamPDB = 1, + StreamTPI = 2, + StreamDBI = 3, + StreamIPI = 4, +}; + +enum class DbgHeaderType : uint16_t { + FPO, + Exception, + Fixup, + OmapToSrc, + OmapFromSrc, + SectionHdr, + TokenRidMap, + Xdata, + Pdata, + NewFPO, + SectionHdrOrig, + Max +}; + +enum class OMFSegDescFlags : uint16_t { + Read = 1 << 0, // Segment is readable. + Write = 1 << 1, // Segment is writable. + Execute = 1 << 2, // Segment is executable. + AddressIs32Bit = 1 << 3, // Descriptor describes a 32-bit linear address. + IsSelector = 1 << 8, // Frame represents a selector. + IsAbsoluteAddress = 1 << 9, // Frame represents an absolute address. + IsGroup = 1 << 10 // If set, descriptor represents a group. +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H diff --git a/include/llvm/DebugInfo/PDB/Raw/RawError.h b/include/llvm/DebugInfo/PDB/Raw/RawError.h new file mode 100644 index 000000000000..b0687cddbf48 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -0,0 +1,49 @@ +//===- RawError.h - Error extensions for raw PDB implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H + +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +namespace pdb { +enum class raw_error_code { + unspecified = 1, + feature_unsupported, + corrupt_file, + insufficient_buffer, + no_stream, + index_out_of_bounds, + invalid_block_address, + not_writable, + invalid_tpi_hash, +}; + +/// Base class for errors originating when parsing raw PDB files +class RawError : public ErrorInfo<RawError> { +public: + static char ID; + RawError(raw_error_code C); + RawError(const std::string &Context); + RawError(raw_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + raw_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawSession.h b/include/llvm/DebugInfo/PDB/Raw/RawSession.h new file mode 100644 index 000000000000..73d281eab1a7 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -0,0 +1,75 @@ +//===- RawSession.h - Native implementation of IPDBSession ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWSESSION_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWSESSION_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class RawSession : public IPDBSession { +public: + explicit RawSession(std::unique_ptr<PDBFile> PdbFile); + ~RawSession() override; + + static Error createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session); + + uint64_t getLoadAddress() const override; + void setLoadAddress(uint64_t Address) override; + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override; + std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; + + std::unique_ptr<PDBSymbol> + findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; + + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const override; + std::unique_ptr<IPDBEnumLineNumbers> + findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + + std::unique_ptr<IPDBEnumSourceFiles> + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBSourceFile> + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<PDBSymbolCompiland> + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override; + std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const override; + std::unique_ptr<IPDBSourceFile> + getSourceFileById(uint32_t FileId) const override; + + std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override; + + PDBFile &getPDBFile() { return *Pdb; } + const PDBFile &getPDBFile() const { return *Pdb; } + +private: + std::unique_ptr<PDBFile> Pdb; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawTypes.h b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h new file mode 100644 index 000000000000..afcfe9405c0f --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -0,0 +1,86 @@ +//===- RawTypes.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWTYPES_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWTYPES_H + +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +// This struct is defined as "SO" in langapi/include/pdb.h. +struct SectionOffset { + support::ulittle32_t Off; + support::ulittle16_t Isect; + char Padding[2]; +}; + +// This is HRFile. +struct PSHashRecord { + support::ulittle32_t Off; // Offset in the symbol record stream + support::ulittle32_t CRef; +}; + +// This struct is defined as `SC` in include/dbicommon.h +struct SectionContrib { + support::ulittle16_t ISect; + char Padding[2]; + support::little32_t Off; + support::little32_t Size; + support::ulittle32_t Characteristics; + support::ulittle16_t Imod; + char Padding2[2]; + support::ulittle32_t DataCrc; + support::ulittle32_t RelocCrc; +}; + +// This struct is defined as `SC2` in include/dbicommon.h +struct SectionContrib2 { + // To guarantee SectionContrib2 is standard layout, we cannot use inheritance. + SectionContrib Base; + support::ulittle32_t ISectCoff; +}; + +// This corresponds to the `OMFSegMap` structure. +struct SecMapHeader { + support::ulittle16_t SecCount; // Number of segment descriptors in table + support::ulittle16_t SecCountLog; // Number of logical segment descriptors +}; + +// This corresponds to the `OMFSegMapDesc` structure. The definition is not +// present in the reference implementation, but the layout is derived from +// code that accesses the fields. +struct SecMapEntry { + support::ulittle16_t Flags; // Descriptor flags. See OMFSegDescFlags + support::ulittle16_t Ovl; // Logical overlay number. + support::ulittle16_t Group; // Group index into descriptor array. + support::ulittle16_t Frame; + support::ulittle16_t SecName; // Byte index of the segment or group name + // in the sstSegName table, or 0xFFFF. + support::ulittle16_t ClassName; // Byte index of the class name in the + // sstSegName table, or 0xFFFF. + support::ulittle32_t Offset; // Byte offset of the logical segment + // within the specified physical segment. + // If group is set in flags, offset is the + // offset of the group. + support::ulittle32_t SecByteLength; // Byte count of the segment or group. +}; + +// Used for serialized hash table in TPI stream. +// In the reference, it is an array of TI and cbOff pair. +struct TypeIndexOffset { + codeview::TypeIndex Type; + support::ulittle32_t Offset; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h new file mode 100644 index 000000000000..685a23411a3b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -0,0 +1,41 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class SymbolStream { +public: + SymbolStream(std::unique_ptr<MappedBlockStream> Stream); + ~SymbolStream(); + Error reload(); + + iterator_range<codeview::CVSymbolArray::Iterator> + getSymbols(bool *HadError) const; + + Error commit(); + +private: + codeview::CVSymbolArray SymbolRecords; + std::unique_ptr<MappedBlockStream> Stream; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h new file mode 100644 index 000000000000..4f36d70aabed --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -0,0 +1,72 @@ +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class TpiStream { + struct HeaderInfo; + +public: + TpiStream(const PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); + ~TpiStream(); + Error reload(); + + PdbRaw_TpiVer getTpiVersion() const; + + uint32_t TypeIndexBegin() const; + uint32_t TypeIndexEnd() const; + uint32_t NumTypeRecords() const; + uint16_t getTypeHashStreamIndex() const; + uint16_t getTypeHashStreamAuxIndex() const; + + uint32_t getHashKeySize() const; + uint32_t NumHashBuckets() const; + codeview::FixedStreamArray<support::ulittle32_t> getHashValues() const; + codeview::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; + codeview::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const; + + iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const; + + Error commit(); + +private: + Error verifyHashValues(); + + const PDBFile &Pdb; + std::unique_ptr<MappedBlockStream> Stream; + + codeview::CVTypeArray TypeRecords; + + std::unique_ptr<MappedBlockStream> HashStream; + codeview::FixedStreamArray<support::ulittle32_t> HashValues; + codeview::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; + codeview::FixedStreamArray<TypeIndexOffset> HashAdjustments; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/include/llvm/DebugInfo/Symbolize/DIPrinter.h index 3098199bb4da..49f86eae01cf 100644 --- a/include/llvm/DebugInfo/Symbolize/DIPrinter.h +++ b/include/llvm/DebugInfo/Symbolize/DIPrinter.h @@ -31,7 +31,7 @@ class DIPrinter { int PrintSourceContext; void print(const DILineInfo &Info, bool Inlined); - void printContext(std::string FileName, int64_t Line); + void printContext(const std::string &FileName, int64_t Line); public: DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true, diff --git a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h index ff9cc808875d..e0bec6f6cf85 100644 --- a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h +++ b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h @@ -14,8 +14,6 @@ #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEMODULE_H #include "llvm/DebugInfo/DIContext.h" -#include <memory> -#include <string> namespace llvm { namespace object { diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h index ec3ae002659c..9253adf7eedd 100644 --- a/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -19,6 +19,7 @@ #include <map> #include <memory> #include <string> +#include <utility> namespace llvm { namespace symbolize { @@ -40,7 +41,7 @@ public: bool RelativeAddresses = false, std::string DefaultArch = "") : PrintFunctions(PrintFunctions), UseSymbolTable(UseSymbolTable), Demangle(Demangle), RelativeAddresses(RelativeAddresses), - DefaultArch(DefaultArch) {} + DefaultArch(std::move(DefaultArch)) {} }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} @@ -48,12 +49,12 @@ public: flush(); } - ErrorOr<DILineInfo> symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr<DIGlobal> symbolizeData(const std::string &ModuleName, - uint64_t ModuleOffset); + Expected<DILineInfo> symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected<DIGlobal> symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset); void flush(); static std::string DemangleName(const std::string &Name, const SymbolizableModule *ModInfo); @@ -63,8 +64,13 @@ private: // corresponding debug info. These objects can be the same. typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair; - ErrorOr<SymbolizableModule *> + /// Returns a SymbolizableModule or an error if loading debug info failed. + /// Only one attempt is made to load a module, and errors during loading are + /// only reported once. Subsequent calls to get module info for a module that + /// failed to load will return nullptr. + Expected<SymbolizableModule *> getOrCreateModuleInfo(const std::string &ModuleName); + ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj, const std::string &ArchName); @@ -73,27 +79,27 @@ private: const std::string &ArchName); /// \brief Returns pair of pointers to object and debug object. - ErrorOr<ObjectPair> getOrCreateObjectPair(const std::string &Path, + Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path, const std::string &ArchName); /// \brief Return a pointer to object file at specified path, for a specified /// architecture (e.g. if path refers to a Mach-O universal binary, only one /// object file from it will be returned). - ErrorOr<ObjectFile *> getOrCreateObject(const std::string &Path, + Expected<ObjectFile *> getOrCreateObject(const std::string &Path, const std::string &ArchName); - std::map<std::string, ErrorOr<std::unique_ptr<SymbolizableModule>>> Modules; + std::map<std::string, std::unique_ptr<SymbolizableModule>> Modules; /// \brief Contains cached results of getOrCreateObjectPair(). - std::map<std::pair<std::string, std::string>, ErrorOr<ObjectPair>> + std::map<std::pair<std::string, std::string>, ObjectPair> ObjectPairForPathArch; /// \brief Contains parsed binary for each path, or parsing error. - std::map<std::string, ErrorOr<OwningBinary<Binary>>> BinaryForPath; + std::map<std::string, OwningBinary<Binary>> BinaryForPath; /// \brief Parsed object file for path/architecture pair, where "path" refers /// to Mach-O universal binary. - std::map<std::pair<std::string, std::string>, ErrorOr<std::unique_ptr<ObjectFile>>> + std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>> ObjectForUBPathAndArch; Options Opts; diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index a7302602dcd8..ab13028b3ae0 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -22,7 +22,6 @@ #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/ValueMap.h" -#include "llvm/MC/MCCodeGenInfo.h" #include "llvm/Object/Binary.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Mutex.h" @@ -290,7 +289,8 @@ public: /// at the specified location. This is used internally as functions are JIT'd /// and as global variables are laid out in memory. It can and should also be /// used by clients of the EE that want to have an LLVM global overlay - /// existing data in memory. Mappings are automatically removed when their + /// existing data in memory. Values to be mapped should be named, and have + /// external or weak linkage. Mappings are automatically removed when their /// GlobalValue is destroyed. void addGlobalMapping(const GlobalValue *GV, void *Addr); void addGlobalMapping(StringRef Name, uint64_t Addr); @@ -477,11 +477,11 @@ public: /// specified function pointer is invoked to create it. If it returns null, /// the JIT will abort. void InstallLazyFunctionCreator(FunctionCreator C) { - LazyFunctionCreator = C; + LazyFunctionCreator = std::move(C); } protected: - ExecutionEngine(const DataLayout DL) : DL(std::move(DL)){} + ExecutionEngine(DataLayout DL) : DL(std::move(DL)) {} explicit ExecutionEngine(DataLayout DL, std::unique_ptr<Module> M); explicit ExecutionEngine(std::unique_ptr<Module> M); @@ -518,7 +518,7 @@ private: std::shared_ptr<MCJITMemoryManager> MemMgr; std::shared_ptr<RuntimeDyld::SymbolResolver> Resolver; TargetOptions Options; - Reloc::Model RelocModel; + Optional<Reloc::Model> RelocModel; CodeModel::Model CMModel; std::string MArch; std::string MCPU; diff --git a/include/llvm/ExecutionEngine/GenericValue.h b/include/llvm/ExecutionEngine/GenericValue.h index 0e92f79eba8f..537745519ddb 100644 --- a/include/llvm/ExecutionEngine/GenericValue.h +++ b/include/llvm/ExecutionEngine/GenericValue.h @@ -17,6 +17,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/Support/DataTypes.h" +#include <vector> namespace llvm { diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h index c3edec868783..be7c0448bb78 100644 --- a/include/llvm/ExecutionEngine/JITEventListener.h +++ b/include/llvm/ExecutionEngine/JITEventListener.h @@ -81,7 +81,7 @@ public: // Get a pointe to the GDB debugger registration listener. static JITEventListener *createGDBRegistrationListener(); -#if LLVM_USE_INTEL_JITEVENTS +#if defined(LLVM_USE_INTEL_JITEVENTS) && LLVM_USE_INTEL_JITEVENTS // Construct an IntelJITEventListener static JITEventListener *createIntelJITEventListener(); @@ -97,7 +97,7 @@ public: } #endif // USE_INTEL_JITEVENTS -#if LLVM_USE_OPROFILE +#if defined(LLVM_USE_OPROFILE) && LLVM_USE_OPROFILE // Construct an OProfileJITEventListener static JITEventListener *createOProfileJITEventListener(); diff --git a/include/llvm/ExecutionEngine/JITSymbolFlags.h b/include/llvm/ExecutionEngine/JITSymbolFlags.h index 450e9481fa00..7e1d57dabc81 100644 --- a/include/llvm/ExecutionEngine/JITSymbolFlags.h +++ b/include/llvm/ExecutionEngine/JITSymbolFlags.h @@ -15,6 +15,7 @@ #define LLVM_EXECUTIONENGINE_JITSYMBOLFLAGS_H #include "llvm/IR/GlobalValue.h" +#include "llvm/Object/SymbolicFile.h" namespace llvm { @@ -69,7 +70,16 @@ public: if (!GV.hasLocalLinkage() && !GV.hasHiddenVisibility()) Flags |= JITSymbolFlags::Exported; return Flags; + } + static JITSymbolFlags + flagsFromObjectSymbol(const object::BasicSymbolRef &Symbol) { + JITSymbolFlags Flags = JITSymbolFlags::None; + if (Symbol.getFlags() & object::BasicSymbolRef::SF_Weak) + Flags |= JITSymbolFlags::Weak; + if (Symbol.getFlags() & object::BasicSymbolRef::SF_Exported) + Flags |= JITSymbolFlags::Exported; + return Flags; } private: diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 84af4728b350..ef88dd03ad4f 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -19,12 +19,12 @@ #include "LambdaResolver.h" #include "LogicalDylib.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/Cloning.h" #include <list> #include <memory> #include <set> - -#include "llvm/Support/Debug.h" +#include <utility> namespace llvm { namespace orc { @@ -46,7 +46,7 @@ private: class LambdaMaterializer final : public ValueMaterializer { public: LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} - Value *materializeDeclFor(Value *V) final { return M(V); } + Value *materialize(Value *V) final { return M(V); } private: MaterializerFtor M; @@ -145,7 +145,7 @@ private: return *this; } - SymbolResolverFtor ExternalSymbolResolver; + std::unique_ptr<RuntimeDyld::SymbolResolver> ExternalSymbolResolver; std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr; ModuleAdderFtor ModuleAdder; }; @@ -173,7 +173,7 @@ public: CompileCallbackMgrT &CallbackMgr, IndirectStubsManagerBuilderT CreateIndirectStubsManager, bool CloneStubsIntoPartitions = true) - : BaseLayer(BaseLayer), Partition(Partition), + : BaseLayer(BaseLayer), Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr), CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} @@ -188,10 +188,7 @@ public: LogicalDylibs.push_back(CODLogicalDylib(BaseLayer)); auto &LDResources = LogicalDylibs.back().getDylibResources(); - LDResources.ExternalSymbolResolver = - [Resolver](const std::string &Name) { - return Resolver->findSymbol(Name); - }; + LDResources.ExternalSymbolResolver = std::move(Resolver); auto &MemMgrRef = *MemMgr; LDResources.MemMgr = @@ -256,14 +253,8 @@ private: Module &SrcM = LMResources.SourceModule->getResource(); - // Create the GlobalValues module. + // Create stub functions. const DataLayout &DL = SrcM.getDataLayout(); - auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(), - SrcM.getContext()); - GVsM->setDataLayout(DL); - - // Create function stubs. - ValueToValueMapTy VMap; { typename IndirectStubsMgrT::StubInitsMap StubInits; for (auto &F : SrcM) { @@ -295,6 +286,19 @@ private: assert(!EC && "Error generating stubs"); } + // If this module doesn't contain any globals or aliases we can bail out + // early and avoid the overhead of creating and managing an empty globals + // module. + if (SrcM.global_empty() && SrcM.alias_empty()) + return; + + // Create the GlobalValues module. + auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(), + SrcM.getContext()); + GVsM->setDataLayout(DL); + + ValueToValueMapTy VMap; + // Clone global variable decls. for (auto &GV : SrcM.globals()) if (!GV.isDeclaration() && !VMap.count(&GV)) @@ -356,16 +360,17 @@ private: [&LD, LMH](const std::string &Name) { auto &LMResources = LD.getLogicalModuleResources(LMH); if (auto Sym = LMResources.StubsMgr->findStub(Name, false)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); - return LD.getDylibResources().ExternalSymbolResolver(Name); + return Sym.toRuntimeDyldSymbol(); + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbolInLogicalDylib(Name); }, - [](const std::string &Name) { - return RuntimeDyld::SymbolInfo(nullptr); + [&LD](const std::string &Name) { + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbol(Name); }); - auto GVsH = - LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM), - std::move(GVsResolver)); + auto GVsH = LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM), + std::move(GVsResolver)); LD.addToLogicalModule(LMH, GVsH); } @@ -481,20 +486,18 @@ private: // Create memory manager and symbol resolver. auto Resolver = createLambdaResolver( [this, &LD, LMH](const std::string &Name) { - if (auto Symbol = LD.findSymbolInternally(LMH, Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - return LD.getDylibResources().ExternalSymbolResolver(Name); + if (auto Sym = LD.findSymbolInternally(LMH, Name)) + return Sym.toRuntimeDyldSymbol(); + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbolInLogicalDylib(Name); }, - [this, &LD, LMH](const std::string &Name) { - if (auto Symbol = LD.findSymbolInternally(LMH, Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - return RuntimeDyld::SymbolInfo(nullptr); + [this, &LD](const std::string &Name) { + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbol(Name); }); return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M), - std::move(Resolver)); + std::move(Resolver)); } BaseLayerT &BaseLayer; diff --git a/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/include/llvm/ExecutionEngine/Orc/CompileUtils.h index 1e7d211196f5..ce0864fbd9c9 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -42,12 +42,13 @@ public: PM.run(M); std::unique_ptr<MemoryBuffer> ObjBuffer( new ObjectMemoryBuffer(std::move(ObjBufferSV))); - ErrorOr<std::unique_ptr<object::ObjectFile>> Obj = + Expected<std::unique_ptr<object::ObjectFile>> Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - // TODO: Actually report errors helpfully. typedef object::OwningBinary<object::ObjectFile> OwningObj; if (Obj) return OwningObj(std::move(*Obj), std::move(ObjBuffer)); + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); return OwningObj(nullptr, nullptr); } diff --git a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index e4bed95fdabf..e6ce18a42b8b 100644 --- a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -37,9 +37,6 @@ public: private: typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT; - typedef std::vector<std::unique_ptr<object::ObjectFile>> OwningObjectVec; - typedef std::vector<std::unique_ptr<MemoryBuffer>> OwningBufferVec; - public: /// @brief Handle to a set of compiled modules. typedef ObjSetHandleT ModuleSetHandleT; @@ -62,28 +59,29 @@ public: ModuleSetHandleT addModuleSet(ModuleSetT Ms, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { - OwningObjectVec Objects; - OwningBufferVec Buffers; + std::vector<std::unique_ptr<object::OwningBinary<object::ObjectFile>>> + Objects; for (const auto &M : Ms) { - std::unique_ptr<object::ObjectFile> Object; - std::unique_ptr<MemoryBuffer> Buffer; + auto Object = + llvm::make_unique<object::OwningBinary<object::ObjectFile>>(); if (ObjCache) - std::tie(Object, Buffer) = tryToLoadFromObjectCache(*M).takeBinary(); + *Object = tryToLoadFromObjectCache(*M); - if (!Object) { - std::tie(Object, Buffer) = Compile(*M).takeBinary(); + if (!Object->getBinary()) { + *Object = Compile(*M); if (ObjCache) - ObjCache->notifyObjectCompiled(&*M, Buffer->getMemBufferRef()); + ObjCache->notifyObjectCompiled(&*M, + Object->getBinary()->getMemoryBufferRef()); } Objects.push_back(std::move(Object)); - Buffers.push_back(std::move(Buffer)); } ModuleSetHandleT H = - BaseLayer.addObjectSet(Objects, std::move(MemMgr), std::move(Resolver)); + BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr), + std::move(Resolver)); return H; } @@ -126,10 +124,13 @@ private: if (!ObjBuffer) return object::OwningBinary<object::ObjectFile>(); - ErrorOr<std::unique_ptr<object::ObjectFile>> Obj = + Expected<std::unique_ptr<object::ObjectFile>> Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - if (!Obj) + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); return object::OwningBinary<object::ObjectFile>(); + } return object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(ObjBuffer)); diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index e17630fa05ff..51172c51e136 100644 --- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -16,14 +16,12 @@ #include "JITSymbol.h" #include "LambdaResolver.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" -#include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Support/Process.h" -#include <sstream> +#include "llvm/Transforms/Utils/ValueMapper.h" namespace llvm { namespace orc { @@ -31,7 +29,6 @@ namespace orc { /// @brief Target-independent base class for compile callback management. class JITCompileCallbackManager { public: - typedef std::function<TargetAddress()> CompileFtor; /// @brief Handle to a newly created compile callback. Can be used to get an @@ -40,12 +37,13 @@ public: class CompileCallbackInfo { public: CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile) - : Addr(Addr), Compile(Compile) {} + : Addr(Addr), Compile(Compile) {} TargetAddress getAddress() const { return Addr; } void setCompileAction(CompileFtor Compile) { this->Compile = std::move(Compile); } + private: TargetAddress Addr; CompileFtor &Compile; @@ -55,7 +53,7 @@ public: /// @param ErrorHandlerAddress The address of an error handler in the target /// process to be used if a compile callback fails. JITCompileCallbackManager(TargetAddress ErrorHandlerAddress) - : ErrorHandlerAddress(ErrorHandlerAddress) {} + : ErrorHandlerAddress(ErrorHandlerAddress) {} virtual ~JITCompileCallbackManager() {} @@ -71,8 +69,10 @@ public: // Found a callback handler. Yank this trampoline out of the active list and // put it back in the available trampolines list, then try to run the // handler's compile and update actions. - // Moving the trampoline ID back to the available list first means there's at - // least one available trampoline if the compile action triggers a request for + // Moving the trampoline ID back to the available list first means there's + // at + // least one available trampoline if the compile action triggers a request + // for // a new one. auto Compile = std::move(I->second); ActiveTrampolines.erase(I); @@ -118,7 +118,6 @@ protected: std::vector<TargetAddress> AvailableTrampolines; private: - TargetAddress getAvailableTrampolineAddr() { if (this->AvailableTrampolines.empty()) grow(); @@ -139,20 +138,17 @@ private: template <typename TargetT> class LocalJITCompileCallbackManager : public JITCompileCallbackManager { public: - /// @brief Construct a InProcessJITCompileCallbackManager. /// @param ErrorHandlerAddress The address of an error handler in the target /// process to be used if a compile callback fails. LocalJITCompileCallbackManager(TargetAddress ErrorHandlerAddress) - : JITCompileCallbackManager(ErrorHandlerAddress) { + : JITCompileCallbackManager(ErrorHandlerAddress) { /// Set up the resolver block. std::error_code EC; - ResolverBlock = - sys::OwningMemoryBlock( - sys::Memory::allocateMappedMemory(TargetT::ResolverCodeSize, nullptr, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, EC)); + ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( + TargetT::ResolverCodeSize, nullptr, + sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); assert(!EC && "Failed to allocate resolver block"); TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), @@ -165,13 +161,11 @@ public: } private: - static TargetAddress reenter(void *CCMgr, void *TrampolineId) { JITCompileCallbackManager *Mgr = - static_cast<JITCompileCallbackManager*>(CCMgr); + static_cast<JITCompileCallbackManager *>(CCMgr); return Mgr->executeCompileCallback( - static_cast<TargetAddress>( - reinterpret_cast<uintptr_t>(TrampolineId))); + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineId))); } void grow() override { @@ -179,18 +173,16 @@ private: std::error_code EC; auto TrampolineBlock = - sys::OwningMemoryBlock( - sys::Memory::allocateMappedMemory(sys::Process::getPageSize(), nullptr, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, EC)); + sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( + sys::Process::getPageSize(), nullptr, + sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); assert(!EC && "Failed to allocate trampoline block"); - unsigned NumTrampolines = - (sys::Process::getPageSize() - TargetT::PointerSize) / + (sys::Process::getPageSize() - TargetT::PointerSize) / TargetT::TrampolineSize; - uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base()); + uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base()); TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(), NumTrampolines); @@ -214,19 +206,18 @@ private: /// @brief Base class for managing collections of named indirect stubs. class IndirectStubsManager { public: - /// @brief Map type for initializing the manager. See init. typedef StringMap<std::pair<TargetAddress, JITSymbolFlags>> StubInitsMap; virtual ~IndirectStubsManager() {} /// @brief Create a single stub with the given name, target address and flags. - virtual std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) = 0; + virtual Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) = 0; /// @brief Create StubInits.size() stubs with the given names, target /// addresses, and flags. - virtual std::error_code createStubs(const StubInitsMap &StubInits) = 0; + virtual Error createStubs(const StubInitsMap &StubInits) = 0; /// @brief Find the stub with the given name. If ExportedStubsOnly is true, /// this will only return a result if the stub's flags indicate that it @@ -237,7 +228,8 @@ public: virtual JITSymbol findPointer(StringRef Name) = 0; /// @brief Change the value of the implementation pointer for the stub. - virtual std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) = 0; + virtual Error updatePointer(StringRef Name, TargetAddress NewAddr) = 0; + private: virtual void anchor(); }; @@ -247,26 +239,25 @@ private: template <typename TargetT> class LocalIndirectStubsManager : public IndirectStubsManager { public: - - std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) override { - if (auto EC = reserveStubs(1)) - return EC; + Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) override { + if (auto Err = reserveStubs(1)) + return Err; createStubInternal(StubName, StubAddr, StubFlags); - return std::error_code(); + return Error::success(); } - std::error_code createStubs(const StubInitsMap &StubInits) override { - if (auto EC = reserveStubs(StubInits.size())) - return EC; + Error createStubs(const StubInitsMap &StubInits) override { + if (auto Err = reserveStubs(StubInits.size())) + return Err; for (auto &Entry : StubInits) createStubInternal(Entry.first(), Entry.second.first, Entry.second.second); - return std::error_code(); + return Error::success(); } JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { @@ -277,7 +268,7 @@ public: void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second); assert(StubAddr && "Missing stub address"); auto StubTargetAddr = - static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(StubAddr)); + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(StubAddr)); auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second); if (ExportedStubsOnly && !StubSymbol.isExported()) return nullptr; @@ -292,35 +283,34 @@ public: void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); assert(PtrAddr && "Missing pointer address"); auto PtrTargetAddr = - static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); return JITSymbol(PtrTargetAddr, I->second.second); } - std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override { + Error updatePointer(StringRef Name, TargetAddress NewAddr) override { auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; *IndirectStubsInfos[Key.first].getPtr(Key.second) = - reinterpret_cast<void*>(static_cast<uintptr_t>(NewAddr)); - return std::error_code(); + reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr)); + return Error::success(); } private: - - std::error_code reserveStubs(unsigned NumStubs) { + Error reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) - return std::error_code(); + return Error::success(); unsigned NewStubsRequired = NumStubs - FreeStubs.size(); unsigned NewBlockId = IndirectStubsInfos.size(); typename TargetT::IndirectStubsInfo ISI; - if (auto EC = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, - nullptr)) - return EC; + if (auto Err = + TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr)) + return Err; for (unsigned I = 0; I < ISI.getNumStubs(); ++I) FreeStubs.push_back(std::make_pair(NewBlockId, I)); IndirectStubsInfos.push_back(std::move(ISI)); - return std::error_code(); + return Error::success(); } void createStubInternal(StringRef StubName, TargetAddress InitAddr, @@ -328,7 +318,7 @@ private: auto Key = FreeStubs.back(); FreeStubs.pop_back(); *IndirectStubsInfos[Key.first].getPtr(Key.second) = - reinterpret_cast<void*>(static_cast<uintptr_t>(InitAddr)); + reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr)); StubIndexes[StubName] = std::make_pair(Key, StubFlags); } @@ -338,17 +328,32 @@ private: StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; }; +/// @brief Create a local compile callback manager. +/// +/// The given target triple will determine the ABI, and the given +/// ErrorHandlerAddress will be used by the resulting compile callback +/// manager if a compile callback fails. +std::unique_ptr<JITCompileCallbackManager> +createLocalCompileCallbackManager(const Triple &T, + TargetAddress ErrorHandlerAddress); + +/// @brief Create a local indriect stubs manager builder. +/// +/// The given target triple will determine the ABI. +std::function<std::unique_ptr<IndirectStubsManager>()> +createLocalIndirectStubsManagerBuilder(const Triple &T); + /// @brief Build a function pointer of FunctionType with the given constant /// address. /// /// Usage example: Turn a trampoline address into a function pointer constant /// for use in a stub. -Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr); +Constant *createIRTypedAddress(FunctionType &FT, TargetAddress Addr); /// @brief Create a function pointer with the given type, name, and initializer /// in the given Module. -GlobalVariable* createImplPointer(PointerType &PT, Module &M, - const Twine &Name, Constant *Initializer); +GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name, + Constant *Initializer); /// @brief Turn a function declaration into a stub function that makes an /// indirect call using the given function pointer. @@ -373,7 +378,7 @@ void makeAllSymbolsExternallyAccessible(Module &M); /// modules with these utilities, all decls should be cloned (and added to a /// single VMap) before any bodies are moved. This will ensure that references /// between functions all refer to the versions in the new module. -Function* cloneFunctionDecl(Module &Dst, const Function &F, +Function *cloneFunctionDecl(Module &Dst, const Function &F, ValueToValueMapTy *VMap = nullptr); /// @brief Move the body of function 'F' to a cloned function declaration in a @@ -389,7 +394,7 @@ void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, Function *NewF = nullptr); /// @brief Clone a global variable declaration into a new module. -GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, +GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, ValueToValueMapTy *VMap = nullptr); /// @brief Move global variable GV from its parent module to cloned global @@ -406,7 +411,7 @@ void moveGlobalVariableInitializer(GlobalVariable &OrigGV, GlobalVariable *NewGV = nullptr); /// @brief Clone -GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, +GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, ValueToValueMapTy &VMap); } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/JITSymbol.h b/include/llvm/ExecutionEngine/Orc/JITSymbol.h index 422a3761837c..464417e4e6d5 100644 --- a/include/llvm/ExecutionEngine/Orc/JITSymbol.h +++ b/include/llvm/ExecutionEngine/Orc/JITSymbol.h @@ -15,6 +15,7 @@ #define LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H #include "llvm/ExecutionEngine/JITSymbolFlags.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/Support/DataTypes.h" #include <cassert> #include <functional> @@ -52,6 +53,10 @@ public: JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags) : JITSymbolBase(Flags), GetAddress(std::move(GetAddress)), CachedAddr(0) {} + /// @brief Create a JITSymbol from a RuntimeDyld::SymbolInfo. + JITSymbol(const RuntimeDyld::SymbolInfo &Sym) + : JITSymbolBase(Sym.getFlags()), CachedAddr(Sym.getAddress()) {} + /// @brief Returns true if the symbol exists, false otherwise. explicit operator bool() const { return CachedAddr || GetAddress; } @@ -66,6 +71,11 @@ public: return CachedAddr; } + /// @brief Convert this JITSymbol to a RuntimeDyld::SymbolInfo. + RuntimeDyld::SymbolInfo toRuntimeDyldSymbol() { + return RuntimeDyld::SymbolInfo(getAddress(), getFlags()); + } + private: GetAddressFtor GetAddress; TargetAddress CachedAddr; diff --git a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h index faa23658524f..a42b9d5c29d1 100644 --- a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -18,42 +18,41 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include <memory> -#include <vector> namespace llvm { namespace orc { -template <typename ExternalLookupFtorT, typename DylibLookupFtorT> +template <typename DylibLookupFtorT, typename ExternalLookupFtorT> class LambdaResolver : public RuntimeDyld::SymbolResolver { public: - LambdaResolver(ExternalLookupFtorT ExternalLookupFtor, - DylibLookupFtorT DylibLookupFtor) - : ExternalLookupFtor(ExternalLookupFtor), - DylibLookupFtor(DylibLookupFtor) {} - - RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) final { - return ExternalLookupFtor(Name); - } + LambdaResolver(DylibLookupFtorT DylibLookupFtor, + ExternalLookupFtorT ExternalLookupFtor) + : DylibLookupFtor(DylibLookupFtor), + ExternalLookupFtor(ExternalLookupFtor) {} RuntimeDyld::SymbolInfo findSymbolInLogicalDylib(const std::string &Name) final { return DylibLookupFtor(Name); } + RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) final { + return ExternalLookupFtor(Name); + } + private: - ExternalLookupFtorT ExternalLookupFtor; DylibLookupFtorT DylibLookupFtor; + ExternalLookupFtorT ExternalLookupFtor; }; -template <typename ExternalLookupFtorT, - typename DylibLookupFtorT> -std::unique_ptr<LambdaResolver<ExternalLookupFtorT, DylibLookupFtorT>> -createLambdaResolver(ExternalLookupFtorT ExternalLookupFtor, - DylibLookupFtorT DylibLookupFtor) { - typedef LambdaResolver<ExternalLookupFtorT, DylibLookupFtorT> LR; - return make_unique<LR>(std::move(ExternalLookupFtor), - std::move(DylibLookupFtor)); +template <typename DylibLookupFtorT, + typename ExternalLookupFtorT> +std::unique_ptr<LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>> +createLambdaResolver(DylibLookupFtorT DylibLookupFtor, + ExternalLookupFtorT ExternalLookupFtor) { + typedef LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT> LR; + return make_unique<LR>(std::move(DylibLookupFtor), + std::move(ExternalLookupFtor)); } } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h index a5286ff9adde..c5fb6b847b30 100644 --- a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -195,13 +195,8 @@ private: for (const auto &M : Ms) { Mangler Mang; - for (const auto &V : M->globals()) - if (auto GV = addGlobalValue(*Symbols, V, Mang, SearchName, - ExportedSymbolsOnly)) - return GV; - - for (const auto &F : *M) - if (auto GV = addGlobalValue(*Symbols, F, Mang, SearchName, + for (const auto &GO : M->global_objects()) + if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName, ExportedSymbolsOnly)) return GV; } diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index 4dc48f114883..a7798d8beb8d 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -26,7 +26,6 @@ namespace orc { class ObjectLinkingLayerBase { protected: - /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. /// /// An instance of this class will be created for each set of objects added @@ -38,38 +37,31 @@ protected: LinkedObjectSet(const LinkedObjectSet&) = delete; void operator=(const LinkedObjectSet&) = delete; public: - LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr, - RuntimeDyld::SymbolResolver &Resolver, - bool ProcessAllSections) - : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)), - State(Raw) { - RTDyld->setProcessAllSections(ProcessAllSections); - } - + LinkedObjectSet() = default; virtual ~LinkedObjectSet() {} - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> - addObject(const object::ObjectFile &Obj) { - return RTDyld->loadObject(Obj); - } - - RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const { - return RTDyld->getSymbol(Name); - } + virtual void finalize() = 0; - bool NeedsFinalization() const { return (State == Raw); } + virtual JITSymbol::GetAddressFtor + getSymbolMaterializer(std::string Name) = 0; - virtual void Finalize() = 0; + virtual void mapSectionAddress(const void *LocalAddress, + TargetAddress TargetAddr) const = 0; - void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) { - assert((State != Finalized) && - "Attempting to remap sections for finalized objects."); - RTDyld->mapSectionAddress(LocalAddress, TargetAddr); + JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) { + auto SymEntry = SymbolTable.find(Name); + if (SymEntry == SymbolTable.end()) + return nullptr; + if (!SymEntry->second.isExported() && ExportedSymbolsOnly) + return nullptr; + if (!Finalized) + return JITSymbol(getSymbolMaterializer(Name), + SymEntry->second.getFlags()); + return JITSymbol(SymEntry->second); } - protected: - std::unique_ptr<RuntimeDyld> RTDyld; - enum { Raw, Finalizing, Finalized } State; + StringMap<RuntimeDyld::SymbolInfo> SymbolTable; + bool Finalized = false; }; typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT; @@ -79,6 +71,7 @@ public: typedef LinkedObjectSetListT::iterator ObjSetHandleT; }; + /// @brief Default (no-op) action to perform when loading objects. class DoNothingOnNotifyLoaded { public: @@ -95,34 +88,126 @@ public: /// symbols. template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded> class ObjectLinkingLayer : public ObjectLinkingLayerBase { +public: + + /// @brief Functor for receiving finalization notifications. + typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor; + private: - template <typename MemoryManagerPtrT, typename SymbolResolverPtrT> + template <typename ObjSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT, typename FinalizerFtor> class ConcreteLinkedObjectSet : public LinkedObjectSet { public: - ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr, + ConcreteLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver, + FinalizerFtor Finalizer, bool ProcessAllSections) - : LinkedObjectSet(*MemMgr, *Resolver, ProcessAllSections), - MemMgr(std::move(MemMgr)), Resolver(std::move(Resolver)) { } + : MemMgr(std::move(MemMgr)), + PFC(llvm::make_unique<PreFinalizeContents>(std::move(Objects), + std::move(Resolver), + std::move(Finalizer), + ProcessAllSections)) { + buildInitialSymbolTable(PFC->Objects); + } + + void setHandle(ObjSetHandleT H) { + PFC->Handle = H; + } + + void finalize() override { + assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); + + RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver); + RTDyld.setProcessAllSections(PFC->ProcessAllSections); + PFC->RTDyld = &RTDyld; - void Finalize() override { - State = Finalizing; - RTDyld->finalizeWithMemoryManagerLocking(); - State = Finalized; + PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects), + [&]() { + this->updateSymbolTable(RTDyld); + this->Finalized = true; + }); + + // Release resources. + PFC = nullptr; + } + + JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override { + return + [this, Name]() { + // The symbol may be materialized between the creation of this lambda + // and its execution, so we need to double check. + if (!this->Finalized) + this->finalize(); + return this->getSymbol(Name, false).getAddress(); + }; + } + + void mapSectionAddress(const void *LocalAddress, + TargetAddress TargetAddr) const override { + assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); + assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet"); + PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); } private: + + void buildInitialSymbolTable(const ObjSetT &Objects) { + for (const auto &Obj : Objects) + for (auto &Symbol : getObject(*Obj).symbols()) { + if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) + continue; + Expected<StringRef> SymbolName = Symbol.getName(); + // FIXME: Raise an error for bad symbols. + if (!SymbolName) { + consumeError(SymbolName.takeError()); + continue; + } + auto Flags = JITSymbol::flagsFromObjectSymbol(Symbol); + SymbolTable.insert( + std::make_pair(*SymbolName, RuntimeDyld::SymbolInfo(0, Flags))); + } + } + + void updateSymbolTable(const RuntimeDyld &RTDyld) { + for (auto &SymEntry : SymbolTable) + SymEntry.second = RTDyld.getSymbol(SymEntry.first()); + } + + // Contains the information needed prior to finalization: the object files, + // memory manager, resolver, and flags needed for RuntimeDyld. + struct PreFinalizeContents { + PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver, + FinalizerFtor Finalizer, bool ProcessAllSections) + : Objects(std::move(Objects)), Resolver(std::move(Resolver)), + Finalizer(std::move(Finalizer)), + ProcessAllSections(ProcessAllSections) {} + + ObjSetT Objects; + SymbolResolverPtrT Resolver; + FinalizerFtor Finalizer; + bool ProcessAllSections; + ObjSetHandleT Handle; + RuntimeDyld *RTDyld; + }; + MemoryManagerPtrT MemMgr; - SymbolResolverPtrT Resolver; + std::unique_ptr<PreFinalizeContents> PFC; }; - template <typename MemoryManagerPtrT, typename SymbolResolverPtrT> - std::unique_ptr<LinkedObjectSet> - createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver, + template <typename ObjSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT, typename FinalizerFtor> + std::unique_ptr< + ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, + SymbolResolverPtrT, FinalizerFtor>> + createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver, + FinalizerFtor Finalizer, bool ProcessAllSections) { - typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS; - return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver), + typedef ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, + SymbolResolverPtrT, FinalizerFtor> LOS; + return llvm::make_unique<LOS>(std::move(Objects), std::move(MemMgr), + std::move(Resolver), std::move(Finalizer), ProcessAllSections); } @@ -133,9 +218,6 @@ public: typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>> LoadedObjInfoList; - /// @brief Functor for receiving finalization notifications. - typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor; - /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, /// and NotifyFinalized functors. ObjectLinkingLayer( @@ -158,33 +240,44 @@ public: /// @brief Add a set of objects (or archives) that will be treated as a unit /// for the purposes of symbol lookup and memory management. /// - /// @return A pair containing (1) A handle that can be used to free the memory - /// allocated for the objects, and (2) a LoadedObjInfoList containing - /// one LoadedObjInfo instance for each object at the corresponding - /// index in the Objects list. - /// - /// This version of this method allows the client to pass in an - /// RTDyldMemoryManager instance that will be used to allocate memory and look - /// up external symbol addresses for the given objects. + /// @return A handle that can be used to refer to the loaded objects (for + /// symbol searching, finalization, freeing memory, etc.). template <typename ObjSetT, typename MemoryManagerPtrT, typename SymbolResolverPtrT> - ObjSetHandleT addObjectSet(const ObjSetT &Objects, + ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { - ObjSetHandleT Handle = - LinkedObjSetList.insert( - LinkedObjSetList.end(), - createLinkedObjectSet(std::move(MemMgr), std::move(Resolver), - ProcessAllSections)); - LinkedObjectSet &LOS = **Handle; - LoadedObjInfoList LoadedObjInfos; + auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld, + const ObjSetT &Objs, + std::function<void()> LOSHandleLoad) { + LoadedObjInfoList LoadedObjInfos; + + for (auto &Obj : Objs) + LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj))); + + LOSHandleLoad(); - for (auto &Obj : Objects) - LoadedObjInfos.push_back(LOS.addObject(*Obj)); + this->NotifyLoaded(H, Objs, LoadedObjInfos); - NotifyLoaded(Handle, Objects, LoadedObjInfos); + RTDyld.finalizeWithMemoryManagerLocking(); + + if (this->NotifyFinalized) + this->NotifyFinalized(H); + }; + + auto LOS = + createLinkedObjectSet(std::move(Objects), std::move(MemMgr), + std::move(Resolver), std::move(Finalizer), + ProcessAllSections); + // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle + // below. + auto *LOSPtr = LOS.get(); + + ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(), + std::move(LOS)); + LOSPtr->setHandle(Handle); return Handle; } @@ -224,33 +317,7 @@ public: /// given object set. JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, bool ExportedSymbolsOnly) { - if (auto Sym = (*H)->getSymbol(Name)) { - if (Sym.isExported() || !ExportedSymbolsOnly) { - auto Addr = Sym.getAddress(); - auto Flags = Sym.getFlags(); - if (!(*H)->NeedsFinalization()) { - // If this instance has already been finalized then we can just return - // the address. - return JITSymbol(Addr, Flags); - } else { - // If this instance needs finalization return a functor that will do - // it. The functor still needs to double-check whether finalization is - // required, in case someone else finalizes this set before the - // functor is called. - auto GetAddress = - [this, Addr, H]() { - if ((*H)->NeedsFinalization()) { - (*H)->Finalize(); - if (NotifyFinalized) - NotifyFinalized(H); - } - return Addr; - }; - return JITSymbol(std::move(GetAddress), Flags); - } - } - } - return nullptr; + return (*H)->getSymbol(Name, ExportedSymbolsOnly); } /// @brief Map section addresses for the objects associated with the handle H. @@ -263,12 +330,21 @@ public: /// given handle. /// @param H Handle for object set to emit/finalize. void emitAndFinalize(ObjSetHandleT H) { - (*H)->Finalize(); - if (NotifyFinalized) - NotifyFinalized(H); + (*H)->finalize(); } private: + + static const object::ObjectFile& getObject(const object::ObjectFile &Obj) { + return Obj; + } + + template <typename ObjT> + static const object::ObjectFile& + getObject(const object::OwningBinary<ObjT> &Obj) { + return *Obj.getBinary(); + } + LinkedObjectSetListT LinkedObjSetList; NotifyLoadedFtor NotifyLoaded; NotifyFinalizedFtor NotifyFinalized; diff --git a/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h index f96e83ed5a1a..2ffe71c94356 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h @@ -42,13 +42,13 @@ public: /// @return A handle for the added objects. template <typename ObjSetT, typename MemoryManagerPtrT, typename SymbolResolverPtrT> - ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr, + ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { for (auto I = Objects.begin(), E = Objects.end(); I != E; ++I) *I = Transform(std::move(*I)); - return BaseLayer.addObjectSet(Objects, std::move(MemMgr), + return BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr), std::move(Resolver)); } diff --git a/include/llvm/ExecutionEngine/Orc/OrcABISupport.h b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h new file mode 100644 index 000000000000..4a8d0b0b801c --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h @@ -0,0 +1,232 @@ +//===-------------- OrcABISupport.h - ABI support code ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ABI specific code for Orc, e.g. callback assembly. +// +// ABI classes should be part of the JIT *target* process, not the host +// process (except where you're doing hosted JITing and the two are one and the +// same). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H +#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H + +#include "IndirectionUtils.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/Process.h" + +namespace llvm { +namespace orc { + +/// Generic ORC ABI support. +/// +/// This class can be substituted as the target architecure support class for +/// ORC templates that require one (e.g. IndirectStubsManagers). It does not +/// support lazy JITing however, and any attempt to use that functionality +/// will result in execution of an llvm_unreachable. +class OrcGenericABI { +public: + static const unsigned PointerSize = sizeof(uintptr_t); + static const unsigned TrampolineSize = 1; + static const unsigned ResolverCodeSize = 1; + + typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr) { + llvm_unreachable("writeResolverCode is not supported by the generic host " + "support class"); + } + + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines) { + llvm_unreachable("writeTrampolines is not supported by the generic host " + "support class"); + } + + class IndirectStubsInfo { + public: + const static unsigned StubSize = 1; + unsigned getNumStubs() const { llvm_unreachable("Not supported"); } + void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); } + void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); } + }; + + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal) { + llvm_unreachable("emitIndirectStubsBlock is not supported by the generic " + "host support class"); + } +}; + +/// @brief Provide information about stub blocks generated by the +/// makeIndirectStubsBlock function. +template <unsigned StubSizeVal> class GenericIndirectStubsInfo { +public: + const static unsigned StubSize = StubSizeVal; + + GenericIndirectStubsInfo() : NumStubs(0) {} + GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem) + : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {} + GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other) + : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) { + Other.NumStubs = 0; + } + GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) { + NumStubs = Other.NumStubs; + Other.NumStubs = 0; + StubsMem = std::move(Other.StubsMem); + return *this; + } + + /// @brief Number of stubs in this block. + unsigned getNumStubs() const { return NumStubs; } + + /// @brief Get a pointer to the stub at the given index, which must be in + /// the range 0 .. getNumStubs() - 1. + void *getStub(unsigned Idx) const { + return static_cast<char *>(StubsMem.base()) + Idx * StubSize; + } + + /// @brief Get a pointer to the implementation-pointer at the given index, + /// which must be in the range 0 .. getNumStubs() - 1. + void **getPtr(unsigned Idx) const { + char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize; + return reinterpret_cast<void **>(PtrsBase) + Idx; + } + +private: + unsigned NumStubs; + sys::OwningMemoryBlock StubsMem; +}; + +class OrcAArch64 { +public: + static const unsigned PointerSize = 8; + static const unsigned TrampolineSize = 12; + static const unsigned ResolverCodeSize = 0x120; + + typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + + typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); + + /// @brief Write the requsted number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines); + + /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to + /// the nearest page size. + /// + /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k + /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 + /// will return a block of 1024 (2-pages worth). + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); +}; + +/// @brief X86_64 code that's common to all ABIs. +/// +/// X86_64 supports lazy JITing. +class OrcX86_64_Base { +public: + static const unsigned PointerSize = 8; + static const unsigned TrampolineSize = 8; + + typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + + /// @brief Write the requsted number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines); + + /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to + /// the nearest page size. + /// + /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k + /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 + /// will return a block of 1024 (2-pages worth). + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); +}; + +/// @brief X86_64 support for SysV ABI (Linux, MacOSX). +/// +/// X86_64_SysV supports lazy JITing. +class OrcX86_64_SysV : public OrcX86_64_Base { +public: + static const unsigned ResolverCodeSize = 0x6C; + typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); +}; + +/// @brief X86_64 support for Win32. +/// +/// X86_64_Win32 supports lazy JITing. +class OrcX86_64_Win32 : public OrcX86_64_Base { +public: + static const unsigned ResolverCodeSize = 0x74; + typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); +}; + +/// @brief I386 support. +/// +/// I386 supports lazy JITing. +class OrcI386 { +public: + static const unsigned PointerSize = 4; + static const unsigned TrampolineSize = 8; + static const unsigned ResolverCodeSize = 0x4a; + + typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + + typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); + + /// @brief Write the requsted number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines); + + /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to + /// the nearest page size. + /// + /// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k + /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 + /// will return a block of 1024 (2-pages worth). + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H diff --git a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h b/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h deleted file mode 100644 index 1b0488bcf00d..000000000000 --- a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h +++ /dev/null @@ -1,148 +0,0 @@ -//===-- OrcArchitectureSupport.h - Architecture support code ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Architecture specific code for Orc, e.g. callback assembly. -// -// Architecture classes should be part of the JIT *target* process, not the host -// process (except where you're doing hosted JITing and the two are one and the -// same). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H -#define LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H - -#include "IndirectionUtils.h" -#include "llvm/Support/Memory.h" -#include "llvm/Support/Process.h" - -namespace llvm { -namespace orc { - -/// Generic ORC Architecture support. -/// -/// This class can be substituted as the target architecure support class for -/// ORC templates that require one (e.g. IndirectStubsManagers). It does not -/// support lazy JITing however, and any attempt to use that functionality -/// will result in execution of an llvm_unreachable. -class OrcGenericArchitecture { -public: - static const unsigned PointerSize = sizeof(uintptr_t); - static const unsigned TrampolineSize = 1; - static const unsigned ResolverCodeSize = 1; - - typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); - - static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, - void *CallbackMgr) { - llvm_unreachable("writeResolverCode is not supported by the generic host " - "support class"); - } - - static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, - unsigned NumTrampolines) { - llvm_unreachable("writeTrampolines is not supported by the generic host " - "support class"); - } - - class IndirectStubsInfo { - public: - const static unsigned StubSize = 1; - unsigned getNumStubs() const { llvm_unreachable("Not supported"); } - void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); } - void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); } - }; - - static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, - unsigned MinStubs, - void *InitialPtrVal) { - llvm_unreachable("emitIndirectStubsBlock is not supported by the generic " - "host support class"); - } -}; - -/// @brief X86_64 support. -/// -/// X86_64 supports lazy JITing. -class OrcX86_64 { -public: - static const unsigned PointerSize = 8; - static const unsigned TrampolineSize = 8; - static const unsigned ResolverCodeSize = 0x78; - - typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); - - /// @brief Write the resolver code into the given memory. The user is be - /// responsible for allocating the memory and setting permissions. - static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, - void *CallbackMgr); - - /// @brief Write the requsted number of trampolines into the given memory, - /// which must be big enough to hold 1 pointer, plus NumTrampolines - /// trampolines. - static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, - unsigned NumTrampolines); - - /// @brief Provide information about stub blocks generated by the - /// makeIndirectStubsBlock function. - class IndirectStubsInfo { - friend class OrcX86_64; - - public: - const static unsigned StubSize = 8; - - IndirectStubsInfo() : NumStubs(0) {} - IndirectStubsInfo(IndirectStubsInfo &&Other) - : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) { - Other.NumStubs = 0; - } - IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) { - NumStubs = Other.NumStubs; - Other.NumStubs = 0; - StubsMem = std::move(Other.StubsMem); - return *this; - } - - /// @brief Number of stubs in this block. - unsigned getNumStubs() const { return NumStubs; } - - /// @brief Get a pointer to the stub at the given index, which must be in - /// the range 0 .. getNumStubs() - 1. - void *getStub(unsigned Idx) const { - return static_cast<uint64_t *>(StubsMem.base()) + Idx; - } - - /// @brief Get a pointer to the implementation-pointer at the given index, - /// which must be in the range 0 .. getNumStubs() - 1. - void **getPtr(unsigned Idx) const { - char *PtrsBase = - static_cast<char *>(StubsMem.base()) + NumStubs * StubSize; - return reinterpret_cast<void **>(PtrsBase) + Idx; - } - - private: - unsigned NumStubs; - sys::OwningMemoryBlock StubsMem; - }; - - /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to - /// the nearest page size. - /// - /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k - /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 - /// will return a block of 1024 (2-pages worth). - static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, - unsigned MinStubs, - void *InitialPtrVal); -}; - -} // End namespace orc. -} // End namespace llvm. - -#endif // LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h index 48f35d6b39be..1b3f25fae162 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcError.h +++ b/include/llvm/ExecutionEngine/Orc/OrcError.h @@ -14,6 +14,7 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H #define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H +#include "llvm/Support/Error.h" #include <system_error> namespace llvm { @@ -26,10 +27,11 @@ enum class OrcErrorCode : int { RemoteMProtectAddrUnrecognized, RemoteIndirectStubsOwnerDoesNotExist, RemoteIndirectStubsOwnerIdAlreadyInUse, - UnexpectedRPCCall + UnexpectedRPCCall, + UnexpectedRPCResponse, }; -std::error_code orcError(OrcErrorCode ErrCode); +Error orcError(OrcErrorCode ErrCode); } // End namespace orc. } // End namespace llvm. diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h index d7640b8e8b5f..5c867e7e7fd4 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -36,6 +36,23 @@ namespace remote { template <typename ChannelT> class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { public: + // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. + + OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete; + OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete; + + OrcRemoteTargetClient(OrcRemoteTargetClient &&Other) + : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)), + RemoteTargetTriple(std::move(Other.RemoteTargetTriple)), + RemotePointerSize(std::move(Other.RemotePointerSize)), + RemotePageSize(std::move(Other.RemotePageSize)), + RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)), + RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)), + AllocatorIds(std::move(Other.AllocatorIds)), + IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)) {} + + OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete; + /// Remote memory manager. class RCMemoryManager : public RuntimeDyld::MemoryManager { public: @@ -57,7 +74,7 @@ public: return *this; } - ~RCMemoryManager() { + ~RCMemoryManager() override { Client.destroyRemoteAllocator(Id); DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n"); } @@ -105,11 +122,13 @@ public: DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); if (CodeSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr, - Id, CodeSize, CodeAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign)) + Unmapped.back().RemoteCodeAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " code: " << format("0x%016x", Unmapped.back().RemoteCodeAddr) << " (" << CodeSize << " bytes, alignment " << CodeAlign @@ -117,11 +136,13 @@ public: } if (RODataSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr, - Id, RODataSize, RODataAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign)) + Unmapped.back().RemoteRODataAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " ro-data: " << format("0x%016x", Unmapped.back().RemoteRODataAddr) << " (" << RODataSize << " bytes, alignment " @@ -129,11 +150,13 @@ public: } if (RWDataSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr, - Id, RWDataSize, RWDataAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign)) + Unmapped.back().RemoteRWDataAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " rw-data: " << format("0x%016x", Unmapped.back().RemoteRWDataAddr) << " (" << RWDataSize << " bytes, alignment " @@ -144,10 +167,18 @@ public: bool needsToReserveAllocationSpace() override { return true; } void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, - size_t Size) override {} + size_t Size) override { + UnfinalizedEHFrames.push_back( + std::make_pair(LoadAddr, static_cast<uint32_t>(Size))); + } - void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr, - size_t Size) override {} + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override { + auto Err = Client.deregisterEHFrames(LoadAddr, Size); + // FIXME: Add error poll. + assert(!Err && "Failed to register remote EH frames."); + (void)Err; + } void notifyObjectLoaded(RuntimeDyld &Dyld, const object::ObjectFile &Obj) override { @@ -156,7 +187,7 @@ public: { TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr; for (auto &Alloc : ObjAllocs.CodeAllocs) { - NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign()); + NextCodeAddr = alignTo(NextCodeAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr); DEBUG(dbgs() << " code: " << static_cast<void *>(Alloc.getLocalAddress()) @@ -168,8 +199,7 @@ public: { TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr; for (auto &Alloc : ObjAllocs.RODataAllocs) { - NextRODataAddr = - RoundUpToAlignment(NextRODataAddr, Alloc.getAlign()); + NextRODataAddr = alignTo(NextRODataAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr); DEBUG(dbgs() << " ro-data: " << static_cast<void *>(Alloc.getLocalAddress()) @@ -182,8 +212,7 @@ public: { TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr; for (auto &Alloc : ObjAllocs.RWDataAllocs) { - NextRWDataAddr = - RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign()); + NextRWDataAddr = alignTo(NextRWDataAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr); DEBUG(dbgs() << " rw-data: " << static_cast<void *>(Alloc.getLocalAddress()) @@ -208,15 +237,35 @@ public: << static_cast<void *>(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } if (ObjAllocs.RemoteCodeAddr) { DEBUG(dbgs() << " setting R-X permissions on code block: " << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, + sys::Memory::MF_READ | + sys::Memory::MF_EXEC)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } for (auto &Alloc : ObjAllocs.RODataAllocs) { @@ -224,16 +273,35 @@ public: << static_cast<void *>(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } if (ObjAllocs.RemoteRODataAddr) { DEBUG(dbgs() << " setting R-- permissions on ro-data block: " << format("0x%016x", ObjAllocs.RemoteRODataAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, - sys::Memory::MF_READ); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, + sys::Memory::MF_READ)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } for (auto &Alloc : ObjAllocs.RWDataAllocs) { @@ -241,20 +309,54 @@ public: << static_cast<void *>(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } if (ObjAllocs.RemoteRWDataAddr) { DEBUG(dbgs() << " setting RW- permissions on rw-data block: " << format("0x%016x", ObjAllocs.RemoteRWDataAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, - sys::Memory::MF_READ | sys::Memory::MF_WRITE); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } } Unfinalized.clear(); + for (auto &EHFrame : UnfinalizedEHFrames) { + if (auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } + } + UnfinalizedEHFrames.clear(); + return false; } @@ -262,8 +364,7 @@ public: class Alloc { public: Alloc(uint64_t Size, unsigned Align) - : Size(Size), Align(Align), Contents(new char[Size + Align - 1]), - RemoteAddr(0) {} + : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {} Alloc(Alloc &&Other) : Size(std::move(Other.Size)), Align(std::move(Other.Align)), @@ -284,7 +385,7 @@ public: char *getLocalAddress() const { uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get()); - LocalAddr = RoundUpToAlignment(LocalAddr, Align); + LocalAddr = alignTo(LocalAddr, Align); return reinterpret_cast<char *>(LocalAddr); } @@ -298,12 +399,11 @@ public: uint64_t Size; unsigned Align; std::unique_ptr<char[]> Contents; - TargetAddress RemoteAddr; + TargetAddress RemoteAddr = 0; }; struct ObjectAllocs { - ObjectAllocs() - : RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {} + ObjectAllocs() = default; ObjectAllocs(ObjectAllocs &&Other) : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)), @@ -323,9 +423,9 @@ public: return *this; } - TargetAddress RemoteCodeAddr; - TargetAddress RemoteRODataAddr; - TargetAddress RemoteRWDataAddr; + TargetAddress RemoteCodeAddr = 0; + TargetAddress RemoteRODataAddr = 0; + TargetAddress RemoteRWDataAddr = 0; std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs; }; @@ -333,6 +433,7 @@ public: ResourceIdMgr::ResourceId Id; std::vector<ObjectAllocs> Unmapped; std::vector<ObjectAllocs> Unfinalized; + std::vector<std::pair<uint64_t, uint32_t>> UnfinalizedEHFrames; }; /// Remote indirect stubs manager. @@ -342,26 +443,31 @@ public: ResourceIdMgr::ResourceId Id) : Remote(Remote), Id(Id) {} - ~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); } + ~RCIndirectStubsManager() override { + if (auto Err = Remote.destroyIndirectStubsManager(Id)) { + // FIXME: Thread this error back to clients. + consumeError(std::move(Err)); + } + } - std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) override { - if (auto EC = reserveStubs(1)) - return EC; + Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) override { + if (auto Err = reserveStubs(1)) + return Err; return createStubInternal(StubName, StubAddr, StubFlags); } - std::error_code createStubs(const StubInitsMap &StubInits) override { - if (auto EC = reserveStubs(StubInits.size())) - return EC; + Error createStubs(const StubInitsMap &StubInits) override { + if (auto Err = reserveStubs(StubInits.size())) + return Err; for (auto &Entry : StubInits) - if (auto EC = createStubInternal(Entry.first(), Entry.second.first, - Entry.second.second)) - return EC; + if (auto Err = createStubInternal(Entry.first(), Entry.second.first, + Entry.second.second)) + return Err; - return std::error_code(); + return Error::success(); } JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { @@ -385,8 +491,7 @@ public: return JITSymbol(getPtrAddr(Key), Flags); } - std::error_code updatePointer(StringRef Name, - TargetAddress NewAddr) override { + Error updatePointer(StringRef Name, TargetAddress NewAddr) override { auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; @@ -395,9 +500,6 @@ public: private: struct RemoteIndirectStubsInfo { - RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase, - unsigned NumStubs) - : StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {} TargetAddress StubBase; TargetAddress PtrBase; unsigned NumStubs; @@ -410,31 +512,31 @@ public: std::vector<StubKey> FreeStubs; StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; - std::error_code reserveStubs(unsigned NumStubs) { + Error reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) - return std::error_code(); + return Error::success(); unsigned NewStubsRequired = NumStubs - FreeStubs.size(); TargetAddress StubBase; TargetAddress PtrBase; unsigned NumStubsEmitted; - Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id, - NewStubsRequired); + if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired)) + std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr; + else + return StubInfoOrErr.takeError(); unsigned NewBlockId = RemoteIndirectStubsInfos.size(); - RemoteIndirectStubsInfos.push_back( - RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted)); + RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted}); for (unsigned I = 0; I < NumStubsEmitted; ++I) FreeStubs.push_back(std::make_pair(NewBlockId, I)); - return std::error_code(); + return Error::success(); } - std::error_code createStubInternal(StringRef StubName, - TargetAddress InitAddr, - JITSymbolFlags StubFlags) { + Error createStubInternal(StringRef StubName, TargetAddress InitAddr, + JITSymbolFlags StubFlags) { auto Key = FreeStubs.back(); FreeStubs.pop_back(); StubIndexes[StubName] = std::make_pair(Key, StubFlags); @@ -461,20 +563,18 @@ public: public: RCCompileCallbackManager(TargetAddress ErrorHandlerAddress, OrcRemoteTargetClient &Remote) - : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) { - assert(!Remote.CompileCallback && "Compile callback already set"); - Remote.CompileCallback = [this](TargetAddress TrampolineAddr) { - return executeCompileCallback(TrampolineAddr); - }; - Remote.emitResolverBlock(); - } + : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {} private: - void grow() { + void grow() override { TargetAddress BlockAddr = 0; uint32_t NumTrampolines = 0; - auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines); - assert(!EC && "Failed to create trampolines"); + if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock()) + std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr; + else { + // FIXME: Return error. + llvm_unreachable("Failed to create trampolines"); + } uint32_t TrampolineSize = Remote.getTrampolineSize(); for (unsigned I = 0; I < NumTrampolines; ++I) @@ -487,143 +587,123 @@ public: /// Create an OrcRemoteTargetClient. /// Channel is the ChannelT instance to communicate on. It is assumed that /// the channel is ready to be read from and written to. - static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) { - std::error_code EC; - OrcRemoteTargetClient H(Channel, EC); - if (EC) - return EC; - return H; + static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) { + Error Err; + OrcRemoteTargetClient H(Channel, Err); + if (Err) + return std::move(Err); + return Expected<OrcRemoteTargetClient>(std::move(H)); } /// Call the int(void) function at the given address in the target and return /// its result. - std::error_code callIntVoid(int &Result, TargetAddress Addr) { + Expected<int> callIntVoid(TargetAddress Addr) { DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call<CallIntVoid>(Channel, Addr)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallIntVoidResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle<CallIntVoidResponse>(Channel, [&](int R) { - Result = R; - DEBUG(dbgs() << "Result: " << R << "\n"); - return std::error_code(); - }); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling<CallIntVoid>(Channel, Listen, Addr); } /// Call the int(int, char*[]) function at the given address in the target and /// return its result. - std::error_code callMain(int &Result, TargetAddress Addr, - const std::vector<std::string> &Args) { + Expected<int> callMain(TargetAddress Addr, + const std::vector<std::string> &Args) { DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call<CallMain>(Channel, Addr, Args)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallMainResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle<CallMainResponse>(Channel, [&](int R) { - Result = R; - DEBUG(dbgs() << "Result: " << R << "\n"); - return std::error_code(); - }); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling<CallMain>(Channel, Listen, Addr, Args); } /// Call the void() function at the given address in the target and wait for /// it to finish. - std::error_code callVoidVoid(TargetAddress Addr) { + Error callVoidVoid(TargetAddress Addr) { DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call<CallVoidVoid>(Channel, Addr)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallVoidVoidResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle<CallVoidVoidResponse>(Channel, doNothing); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling<CallVoidVoid>(Channel, Listen, Addr); } /// Create an RCMemoryManager which will allocate its memory on the remote /// target. - std::error_code - createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) { + Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) { assert(!MM && "MemoryManager should be null before creation."); auto Id = AllocatorIds.getNext(); - if (auto EC = call<CreateRemoteAllocator>(Channel, Id)) - return EC; + if (auto Err = callST<CreateRemoteAllocator>(Channel, Id)) + return Err; MM = llvm::make_unique<RCMemoryManager>(*this, Id); - return std::error_code(); + return Error::success(); } /// Create an RCIndirectStubsManager that will allocate stubs on the remote /// target. - std::error_code - createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) { + Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) { assert(!I && "Indirect stubs manager should be null before creation."); auto Id = IndirectStubOwnerIds.getNext(); - if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id)) - return EC; + if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id)) + return Err; I = llvm::make_unique<RCIndirectStubsManager>(*this, Id); - return std::error_code(); + return Error::success(); + } + + Expected<RCCompileCallbackManager &> + enableCompileCallbacks(TargetAddress ErrorHandlerAddress) { + // Check for an 'out-of-band' error, e.g. from an MM destructor. + if (ExistingError) + return std::move(ExistingError); + + // Emit the resolver block on the JIT server. + if (auto Err = callST<EmitResolverBlock>(Channel)) + return std::move(Err); + + // Create the callback manager. + CallbackManager.emplace(ErrorHandlerAddress, *this); + RCCompileCallbackManager &Mgr = *CallbackManager; + return Mgr; } /// Search for symbols in the remote process. Note: This should be used by /// symbol resolvers *after* they've searched the local symbol table in the /// JIT stack. - std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) { + Expected<TargetAddress> getSymbolAddress(StringRef Name) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - // Request remote symbol address. - if (auto EC = call<GetSymbolAddress>(Channel, Name)) - return EC; - - return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) { - Addr = A; - DEBUG(dbgs() << "Remote address lookup " << Name << " = " - << format("0x%016x", Addr) << "\n"); - return std::error_code(); - }); + return std::move(ExistingError); + + return callST<GetSymbolAddress>(Channel, Name); } /// Get the triple for the remote target. const std::string &getTargetTriple() const { return RemoteTargetTriple; } - std::error_code terminateSession() { return call<TerminateSession>(Channel); } + Error terminateSession() { return callST<TerminateSession>(Channel); } private: - OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC) - : Channel(Channel), RemotePointerSize(0), RemotePageSize(0), - RemoteTrampolineSize(0), RemoteIndirectStubSize(0) { - if ((EC = call<GetRemoteInfo>(Channel))) - return; - - EC = expect<GetRemoteInfoResponse>( - Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize, - RemoteTrampolineSize, RemoteIndirectStubSize)); + OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) { + ErrorAsOutParameter EAO(Err); + if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) { + std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize, + RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr; + Err = Error::success(); + } else { + Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError)); + } + } + + Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) { + return callST<RegisterEHFrames>(Channel, Addr, Size); } void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { - if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) { + if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) { // FIXME: This will be triggered by a removeModuleSet call: Propagate // error return up through that. llvm_unreachable("Failed to destroy remote allocator."); @@ -631,46 +711,22 @@ private: } } - std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { + Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { IndirectStubOwnerIds.release(Id); - return call<DestroyIndirectStubsOwner>(Channel, Id); + return callST<DestroyIndirectStubsOwner>(Channel, Id); } - std::error_code emitIndirectStubs(TargetAddress &StubBase, - TargetAddress &PtrBase, - uint32_t &NumStubsEmitted, - ResourceIdMgr::ResourceId Id, - uint32_t NumStubsRequired) { - if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired)) - return EC; - - return expect<EmitIndirectStubsResponse>( - Channel, readArgs(StubBase, PtrBase, NumStubsEmitted)); + Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>> + emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { + return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired); } - std::error_code emitResolverBlock() { + Expected<std::tuple<TargetAddress, uint32_t>> emitTrampolineBlock() { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; + return std::move(ExistingError); - return call<EmitResolverBlock>(Channel); - } - - std::error_code emitTrampolineBlock(TargetAddress &BlockAddr, - uint32_t &NumTrampolines) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return ExistingError; - - if (auto EC = call<EmitTrampolineBlock>(Channel)) - return EC; - - return expect<EmitTrampolineBlockResponse>( - Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) { - BlockAddr = BAddr; - NumTrampolines = NTrampolines; - return std::error_code(); - }); + return callST<EmitTrampolineBlock>(Channel); } uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } @@ -679,100 +735,86 @@ private: uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } - std::error_code listenForCompileRequests(uint32_t &NextId) { + Error listenForCompileRequests(RPCChannel &C, uint32_t &Id) { + assert(CallbackManager && + "No calback manager. enableCompileCallbacks must be called first"); + // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - if (auto EC = getNextProcId(Channel, NextId)) - return EC; - - while (NextId == RequestCompileId) { - TargetAddress TrampolineAddr = 0; - if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr))) - return EC; - - TargetAddress ImplAddr = CompileCallback(TrampolineAddr); - if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr)) - return EC; + return std::move(ExistingError); + + // FIXME: CompileCallback could be an anonymous lambda defined at the use + // site below, but that triggers a GCC 4.7 ICE. When we move off + // GCC 4.7, tidy this up. + auto CompileCallback = + [this](TargetAddress Addr) -> Expected<TargetAddress> { + return this->CallbackManager->executeCompileCallback(Addr); + }; - if (auto EC = getNextProcId(Channel, NextId)) - return EC; + if (Id == RequestCompileId) { + if (auto Err = handle<RequestCompile>(C, CompileCallback)) + return Err; + return Error::success(); } - - return std::error_code(); + // else + return orcError(OrcErrorCode::UnexpectedRPCCall); } - std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) { + Expected<std::vector<char>> readMem(char *Dst, TargetAddress Src, + uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - if (auto EC = call<ReadMem>(Channel, Src, Size)) - return EC; + return std::move(ExistingError); - if (auto EC = expect<ReadMemResponse>( - Channel, [&]() { return Channel.readBytes(Dst, Size); })) - return EC; + return callST<ReadMem>(Channel, Src, Size); + } - return std::error_code(); + Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) { + return callST<RegisterEHFrames>(Channel, RAddr, Size); } - std::error_code reserveMem(TargetAddress &RemoteAddr, - ResourceIdMgr::ResourceId Id, uint64_t Size, - uint32_t Align) { + Expected<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id, + uint64_t Size, uint32_t Align) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - if (std::error_code EC = call<ReserveMem>(Channel, Id, Size, Align)) - return EC; + return std::move(ExistingError); - return expect<ReserveMemResponse>(Channel, readArgs(RemoteAddr)); + return callST<ReserveMem>(Channel, Id, Size, Align); } - std::error_code setProtections(ResourceIdMgr::ResourceId Id, - TargetAddress RemoteSegAddr, - unsigned ProtFlags) { - return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags); + Error setProtections(ResourceIdMgr::ResourceId Id, + TargetAddress RemoteSegAddr, unsigned ProtFlags) { + return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags); } - std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { + Error writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - // Make the send call. - if (auto EC = call<WriteMem>(Channel, Addr, Size)) - return EC; - - // Follow this up with the section contents. - if (auto EC = Channel.appendBytes(Src, Size)) - return EC; + return std::move(ExistingError); - return Channel.send(); + return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size)); } - std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) { + Error writePointer(TargetAddress Addr, TargetAddress PtrVal) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; + return std::move(ExistingError); - return call<WritePtr>(Channel, Addr, PtrVal); + return callST<WritePtr>(Channel, Addr, PtrVal); } - static std::error_code doNothing() { return std::error_code(); } + static Error doNothing() { return Error::success(); } ChannelT &Channel; - std::error_code ExistingError; + Error ExistingError; std::string RemoteTargetTriple; - uint32_t RemotePointerSize; - uint32_t RemotePageSize; - uint32_t RemoteTrampolineSize; - uint32_t RemoteIndirectStubSize; + uint32_t RemotePointerSize = 0; + uint32_t RemotePageSize = 0; + uint32_t RemoteTrampolineSize = 0; + uint32_t RemoteIndirectStubSize = 0; ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; - std::function<TargetAddress(TargetAddress)> CompileCallback; + Optional<RCCompileCallbackManager> CallbackManager; }; } // end namespace remote @@ -781,4 +823,4 @@ private: #undef DEBUG_TYPE -#endif +#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h index 96dc24251026..74d851522f79 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h @@ -24,12 +24,51 @@ namespace llvm { namespace orc { namespace remote { +class DirectBufferWriter { +public: + DirectBufferWriter() = default; + DirectBufferWriter(const char *Src, TargetAddress Dst, uint64_t Size) + : Src(Src), Dst(Dst), Size(Size) {} + + const char *getSrc() const { return Src; } + TargetAddress getDst() const { return Dst; } + uint64_t getSize() const { return Size; } + +private: + const char *Src; + TargetAddress Dst; + uint64_t Size; +}; + +inline Error serialize(RPCChannel &C, const DirectBufferWriter &DBW) { + if (auto EC = serialize(C, DBW.getDst())) + return EC; + if (auto EC = serialize(C, DBW.getSize())) + return EC; + return C.appendBytes(DBW.getSrc(), DBW.getSize()); +} + +inline Error deserialize(RPCChannel &C, DirectBufferWriter &DBW) { + TargetAddress Dst; + if (auto EC = deserialize(C, Dst)) + return EC; + uint64_t Size; + if (auto EC = deserialize(C, Size)) + return EC; + char *Addr = reinterpret_cast<char *>(static_cast<uintptr_t>(Dst)); + + DBW = DirectBufferWriter(0, Dst, Size); + + return C.readBytes(Addr, Size); +} + class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> { protected: class ResourceIdMgr { public: typedef uint64_t ResourceId; - ResourceIdMgr() : NextId(0) {} + static const ResourceId InvalidId = ~0U; + ResourceId getNext() { if (!FreeIds.empty()) { ResourceId I = FreeIds.back(); @@ -41,140 +80,122 @@ protected: void release(ResourceId I) { FreeIds.push_back(I); } private: - ResourceId NextId; + ResourceId NextId = 0; std::vector<ResourceId> FreeIds; }; public: - enum JITProcId : uint32_t { - InvalidId = 0, - CallIntVoidId, - CallIntVoidResponseId, + // FIXME: Remove constructors once MSVC supports synthesizing move-ops. + OrcRemoteTargetRPCAPI() = default; + OrcRemoteTargetRPCAPI(const OrcRemoteTargetRPCAPI &) = delete; + OrcRemoteTargetRPCAPI &operator=(const OrcRemoteTargetRPCAPI &) = delete; + + OrcRemoteTargetRPCAPI(OrcRemoteTargetRPCAPI &&) {} + OrcRemoteTargetRPCAPI &operator=(OrcRemoteTargetRPCAPI &&) { return *this; } + + enum JITFuncId : uint32_t { + InvalidId = RPCFunctionIdTraits<JITFuncId>::InvalidId, + CallIntVoidId = RPCFunctionIdTraits<JITFuncId>::FirstValidId, CallMainId, - CallMainResponseId, CallVoidVoidId, - CallVoidVoidResponseId, CreateRemoteAllocatorId, CreateIndirectStubsOwnerId, + DeregisterEHFramesId, DestroyRemoteAllocatorId, DestroyIndirectStubsOwnerId, EmitIndirectStubsId, - EmitIndirectStubsResponseId, EmitResolverBlockId, EmitTrampolineBlockId, - EmitTrampolineBlockResponseId, GetSymbolAddressId, - GetSymbolAddressResponseId, GetRemoteInfoId, - GetRemoteInfoResponseId, ReadMemId, - ReadMemResponseId, + RegisterEHFramesId, ReserveMemId, - ReserveMemResponseId, RequestCompileId, - RequestCompileResponseId, SetProtectionsId, TerminateSessionId, WriteMemId, WritePtrId }; - static const char *getJITProcIdName(JITProcId Id); + static const char *getJITFuncIdName(JITFuncId Id); - typedef Procedure<CallIntVoidId, TargetAddress /* FnAddr */> CallIntVoid; + typedef Function<CallIntVoidId, int32_t(TargetAddress Addr)> CallIntVoid; - typedef Procedure<CallIntVoidResponseId, int /* Result */> - CallIntVoidResponse; - - typedef Procedure<CallMainId, TargetAddress /* FnAddr */, - std::vector<std::string> /* Args */> + typedef Function<CallMainId, + int32_t(TargetAddress Addr, std::vector<std::string> Args)> CallMain; - typedef Procedure<CallMainResponseId, int /* Result */> CallMainResponse; - - typedef Procedure<CallVoidVoidId, TargetAddress /* FnAddr */> CallVoidVoid; - - typedef Procedure<CallVoidVoidResponseId> CallVoidVoidResponse; + typedef Function<CallVoidVoidId, void(TargetAddress FnAddr)> CallVoidVoid; - typedef Procedure<CreateRemoteAllocatorId, - ResourceIdMgr::ResourceId /* Allocator ID */> + typedef Function<CreateRemoteAllocatorId, + void(ResourceIdMgr::ResourceId AllocatorID)> CreateRemoteAllocator; - typedef Procedure<CreateIndirectStubsOwnerId, - ResourceIdMgr::ResourceId /* StubsOwner ID */> + typedef Function<CreateIndirectStubsOwnerId, + void(ResourceIdMgr::ResourceId StubOwnerID)> CreateIndirectStubsOwner; - typedef Procedure<DestroyRemoteAllocatorId, - ResourceIdMgr::ResourceId /* Allocator ID */> + typedef Function<DeregisterEHFramesId, + void(TargetAddress Addr, uint32_t Size)> + DeregisterEHFrames; + + typedef Function<DestroyRemoteAllocatorId, + void(ResourceIdMgr::ResourceId AllocatorID)> DestroyRemoteAllocator; - typedef Procedure<DestroyIndirectStubsOwnerId, - ResourceIdMgr::ResourceId /* StubsOwner ID */> + typedef Function<DestroyIndirectStubsOwnerId, + void(ResourceIdMgr::ResourceId StubsOwnerID)> DestroyIndirectStubsOwner; - typedef Procedure<EmitIndirectStubsId, - ResourceIdMgr::ResourceId /* StubsOwner ID */, - uint32_t /* NumStubsRequired */> + /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted). + typedef Function<EmitIndirectStubsId, + std::tuple<TargetAddress, TargetAddress, uint32_t>( + ResourceIdMgr::ResourceId StubsOwnerID, + uint32_t NumStubsRequired)> EmitIndirectStubs; - typedef Procedure< - EmitIndirectStubsResponseId, TargetAddress /* StubsBaseAddr */, - TargetAddress /* PtrsBaseAddr */, uint32_t /* NumStubsEmitted */> - EmitIndirectStubsResponse; - - typedef Procedure<EmitResolverBlockId> EmitResolverBlock; + typedef Function<EmitResolverBlockId, void()> EmitResolverBlock; - typedef Procedure<EmitTrampolineBlockId> EmitTrampolineBlock; + /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines). + typedef Function<EmitTrampolineBlockId, std::tuple<TargetAddress, uint32_t>()> + EmitTrampolineBlock; - typedef Procedure<EmitTrampolineBlockResponseId, - TargetAddress /* BlockAddr */, - uint32_t /* NumTrampolines */> - EmitTrampolineBlockResponse; - - typedef Procedure<GetSymbolAddressId, std::string /*SymbolName*/> + typedef Function<GetSymbolAddressId, TargetAddress(std::string SymbolName)> GetSymbolAddress; - typedef Procedure<GetSymbolAddressResponseId, uint64_t /* SymbolAddr */> - GetSymbolAddressResponse; - - typedef Procedure<GetRemoteInfoId> GetRemoteInfo; - - typedef Procedure<GetRemoteInfoResponseId, std::string /* Triple */, - uint32_t /* PointerSize */, uint32_t /* PageSize */, - uint32_t /* TrampolineSize */, - uint32_t /* IndirectStubSize */> - GetRemoteInfoResponse; + /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize, + /// IndirectStubsSize). + typedef Function<GetRemoteInfoId, std::tuple<std::string, uint32_t, uint32_t, + uint32_t, uint32_t>()> + GetRemoteInfo; - typedef Procedure<ReadMemId, TargetAddress /* Src */, uint64_t /* Size */> + typedef Function<ReadMemId, + std::vector<char>(TargetAddress Src, uint64_t Size)> ReadMem; - typedef Procedure<ReadMemResponseId> ReadMemResponse; + typedef Function<RegisterEHFramesId, void(TargetAddress Addr, uint32_t Size)> + RegisterEHFrames; - typedef Procedure<ReserveMemId, ResourceIdMgr::ResourceId /* Id */, - uint64_t /* Size */, uint32_t /* Align */> + typedef Function<ReserveMemId, + TargetAddress(ResourceIdMgr::ResourceId AllocID, + uint64_t Size, uint32_t Align)> ReserveMem; - typedef Procedure<ReserveMemResponseId, TargetAddress /* Addr */> - ReserveMemResponse; - - typedef Procedure<RequestCompileId, TargetAddress /* TrampolineAddr */> + typedef Function<RequestCompileId, + TargetAddress(TargetAddress TrampolineAddr)> RequestCompile; - typedef Procedure<RequestCompileResponseId, TargetAddress /* ImplAddr */> - RequestCompileResponse; - - typedef Procedure<SetProtectionsId, ResourceIdMgr::ResourceId /* Id */, - TargetAddress /* Dst */, uint32_t /* ProtFlags */> + typedef Function<SetProtectionsId, + void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst, + uint32_t ProtFlags)> SetProtections; - typedef Procedure<TerminateSessionId> TerminateSession; + typedef Function<TerminateSessionId, void()> TerminateSession; - typedef Procedure<WriteMemId, TargetAddress /* Dst */, uint64_t /* Size */ - /* Data should follow */> - WriteMem; + typedef Function<WriteMemId, void(DirectBufferWriter DB)> WriteMem; - typedef Procedure<WritePtrId, TargetAddress /* Dst */, - TargetAddress /* Val */> + typedef Function<WritePtrId, void(TargetAddress Dst, TargetAddress Val)> WritePtr; }; diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index 5247661e49ce..bf4299c69b24 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -35,17 +35,31 @@ public: typedef std::function<TargetAddress(const std::string &Name)> SymbolLookupFtor; - OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup) - : Channel(Channel), SymbolLookup(std::move(SymbolLookup)) {} + typedef std::function<void(uint8_t *Addr, uint32_t Size)> + EHFrameRegistrationFtor; - std::error_code getNextProcId(JITProcId &Id) { - return deserialize(Channel, Id); - } + OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup, + EHFrameRegistrationFtor EHFramesRegister, + EHFrameRegistrationFtor EHFramesDeregister) + : Channel(Channel), SymbolLookup(std::move(SymbolLookup)), + EHFramesRegister(std::move(EHFramesRegister)), + EHFramesDeregister(std::move(EHFramesDeregister)) {} + + // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. + OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete; + OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete; + + OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) + : Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)), + EHFramesRegister(std::move(Other.EHFramesRegister)), + EHFramesDeregister(std::move(Other.EHFramesDeregister)) {} + + OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete; - std::error_code handleKnownProcedure(JITProcId Id) { + Error handleKnownFunction(JITFuncId Id) { typedef OrcRemoteTargetServer ThisT; - DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n"); + DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n"); switch (Id) { case CallIntVoidId: @@ -60,6 +74,9 @@ public: case CreateIndirectStubsOwnerId: return handle<CreateIndirectStubsOwner>( Channel, *this, &ThisT::handleCreateIndirectStubsOwner); + case DeregisterEHFramesId: + return handle<DeregisterEHFrames>(Channel, *this, + &ThisT::handleDeregisterEHFrames); case DestroyRemoteAllocatorId: return handle<DestroyRemoteAllocator>( Channel, *this, &ThisT::handleDestroyRemoteAllocator); @@ -82,6 +99,9 @@ public: return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo); case ReadMemId: return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem); + case RegisterEHFramesId: + return handle<RegisterEHFrames>(Channel, *this, + &ThisT::handleRegisterEHFrames); case ReserveMemId: return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem); case SetProtectionsId: @@ -98,27 +118,16 @@ public: llvm_unreachable("Unhandled JIT RPC procedure Id."); } - std::error_code requestCompile(TargetAddress &CompiledFnAddr, - TargetAddress TrampolineAddr) { - if (auto EC = call<RequestCompile>(Channel, TrampolineAddr)) - return EC; - - while (1) { - JITProcId Id = InvalidId; - if (auto EC = getNextProcId(Id)) - return EC; - - switch (Id) { - case RequestCompileResponseId: - return handle<RequestCompileResponse>(Channel, - readArgs(CompiledFnAddr)); - default: - if (auto EC = handleKnownProcedure(Id)) - return EC; - } - } + Expected<TargetAddress> requestCompile(TargetAddress TrampolineAddr) { + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return handleKnownFunction(static_cast<JITFuncId>(Id)); + }; + + return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr); + } - llvm_unreachable("Fell through request-compile command loop."); + Error handleTerminateSession() { + return handle<TerminateSession>(Channel, []() { return Error::success(); }); } private: @@ -135,60 +144,56 @@ private: sys::Memory::releaseMappedMemory(Alloc.second); } - std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) { + Error allocate(void *&Addr, size_t Size, uint32_t Align) { std::error_code EC; sys::MemoryBlock MB = sys::Memory::allocateMappedMemory( Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) - return EC; + return errorCodeToError(EC); Addr = MB.base(); assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc"); Allocs[MB.base()] = std::move(MB); - return std::error_code(); + return Error::success(); } - std::error_code setProtections(void *block, unsigned Flags) { + Error setProtections(void *block, unsigned Flags) { auto I = Allocs.find(block); if (I == Allocs.end()) return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized); - return sys::Memory::protectMappedMemory(I->second, Flags); + return errorCodeToError( + sys::Memory::protectMappedMemory(I->second, Flags)); } private: std::map<void *, sys::MemoryBlock> Allocs; }; - static std::error_code doNothing() { return std::error_code(); } + static Error doNothing() { return Error::success(); } static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) { - TargetAddress CompiledFnAddr = 0; - auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr); - auto EC = T->requestCompile( - CompiledFnAddr, static_cast<TargetAddress>( - reinterpret_cast<uintptr_t>(TrampolineAddr))); - assert(!EC && "Compile request failed"); - (void)EC; - return CompiledFnAddr; + auto AddrOrErr = T->requestCompile(static_cast<TargetAddress>( + reinterpret_cast<uintptr_t>(TrampolineAddr))); + // FIXME: Allow customizable failure substitution functions. + assert(AddrOrErr && "Compile request failed"); + return *AddrOrErr; } - std::error_code handleCallIntVoid(TargetAddress Addr) { + Expected<int32_t> handleCallIntVoid(TargetAddress Addr) { typedef int (*IntVoidFnTy)(); IntVoidFnTy Fn = reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr)); - DEBUG(dbgs() << " Calling " - << reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Fn)) - << "\n"); + DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n"); int Result = Fn(); DEBUG(dbgs() << " Result = " << Result << "\n"); - return call<CallIntVoidResponse>(Channel, Result); + return Result; } - std::error_code handleCallMain(TargetAddress Addr, - std::vector<std::string> Args) { + Expected<int32_t> handleCallMain(TargetAddress Addr, + std::vector<std::string> Args) { typedef int (*MainFnTy)(int, const char *[]); MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr)); @@ -199,63 +204,71 @@ private: for (auto &Arg : Args) ArgV[Idx++] = Arg.c_str(); - DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n"); + DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n"); int Result = Fn(ArgC, ArgV.get()); DEBUG(dbgs() << " Result = " << Result << "\n"); - return call<CallMainResponse>(Channel, Result); + return Result; } - std::error_code handleCallVoidVoid(TargetAddress Addr) { + Error handleCallVoidVoid(TargetAddress Addr) { typedef void (*VoidVoidFnTy)(); VoidVoidFnTy Fn = reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr)); - DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n"); + DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n"); Fn(); DEBUG(dbgs() << " Complete.\n"); - return call<CallVoidVoidResponse>(Channel); + return Error::success(); } - std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) { + Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I != Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse); DEBUG(dbgs() << " Created allocator " << Id << "\n"); Allocators[Id] = Allocator(); - return std::error_code(); + return Error::success(); } - std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { + Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I != IndirectStubsOwners.end()) return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse); DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n"); IndirectStubsOwners[Id] = ISBlockOwnerList(); - return std::error_code(); + return Error::success(); + } + + Error handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) { + uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr)); + DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr) + << ", Size = " << Size << " bytes\n"); + EHFramesDeregister(Addr, Size); + return Error::success(); } - std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { + Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); Allocators.erase(I); DEBUG(dbgs() << " Destroyed allocator " << Id << "\n"); - return std::error_code(); + return Error::success(); } - std::error_code - handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { + Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I == IndirectStubsOwners.end()) return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); IndirectStubsOwners.erase(I); - return std::error_code(); + return Error::success(); } - std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id, - uint32_t NumStubsRequired) { + Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>> + handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id, + uint32_t NumStubsRequired) { DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired << " stubs.\n"); @@ -264,9 +277,9 @@ private: return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); typename TargetT::IndirectStubsInfo IS; - if (auto EC = + if (auto Err = TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr)) - return EC; + return std::move(Err); TargetAddress StubsBase = static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0))); @@ -277,36 +290,35 @@ private: auto &BlockList = StubOwnerItr->second; BlockList.push_back(std::move(IS)); - return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase, - NumStubsEmitted); + return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted); } - std::error_code handleEmitResolverBlock() { + Error handleEmitResolverBlock() { std::error_code EC; ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( TargetT::ResolverCodeSize, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) - return EC; + return errorCodeToError(EC); TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), &reenter, this); - return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), - sys::Memory::MF_READ | - sys::Memory::MF_EXEC); + return errorCodeToError(sys::Memory::protectMappedMemory( + ResolverBlock.getMemoryBlock(), + sys::Memory::MF_READ | sys::Memory::MF_EXEC)); } - std::error_code handleEmitTrampolineBlock() { + Expected<std::tuple<TargetAddress, uint32_t>> handleEmitTrampolineBlock() { std::error_code EC; auto TrampolineBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( sys::Process::getPageSize(), nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) - return EC; + return errorCodeToError(EC); - unsigned NumTrampolines = + uint32_t NumTrampolines = (sys::Process::getPageSize() - TargetT::PointerSize) / TargetT::TrampolineSize; @@ -320,20 +332,21 @@ private: TrampolineBlocks.push_back(std::move(TrampolineBlock)); - return call<EmitTrampolineBlockResponse>( - Channel, - static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)), - NumTrampolines); + auto TrampolineBaseAddr = + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)); + + return std::make_tuple(TrampolineBaseAddr, NumTrampolines); } - std::error_code handleGetSymbolAddress(const std::string &Name) { + Expected<TargetAddress> handleGetSymbolAddress(const std::string &Name) { TargetAddress Addr = SymbolLookup(Name); DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr) << "\n"); - return call<GetSymbolAddressResponse>(Channel, Addr); + return Addr; } - std::error_code handleGetRemoteInfo() { + Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>> + handleGetRemoteInfo() { std::string ProcessTriple = sys::getProcessTriple(); uint32_t PointerSize = TargetT::PointerSize; uint32_t PageSize = sys::Process::getPageSize(); @@ -345,35 +358,41 @@ private: << " page size = " << PageSize << "\n" << " trampoline size = " << TrampolineSize << "\n" << " indirect stub size = " << IndirectStubSize << "\n"); - return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize, - PageSize, TrampolineSize, - IndirectStubSize); + return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize, + IndirectStubSize); } - std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) { + Expected<std::vector<char>> handleReadMem(TargetAddress RSrc, uint64_t Size) { char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc)); DEBUG(dbgs() << " Reading " << Size << " bytes from " - << static_cast<void *>(Src) << "\n"); + << format("0x%016x", RSrc) << "\n"); - if (auto EC = call<ReadMemResponse>(Channel)) - return EC; + std::vector<char> Buffer; + Buffer.resize(Size); + for (char *P = Src; Size != 0; --Size) + Buffer.push_back(*P++); - if (auto EC = Channel.appendBytes(Src, Size)) - return EC; + return Buffer; + } - return Channel.send(); + Error handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) { + uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr)); + DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr) + << ", Size = " << Size << " bytes\n"); + EHFramesRegister(Addr, Size); + return Error::success(); } - std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size, - uint32_t Align) { + Expected<TargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id, + uint64_t Size, uint32_t Align) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); auto &Allocator = I->second; void *LocalAllocAddr = nullptr; - if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align)) - return EC; + if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align)) + return std::move(Err); DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr << " (" << Size << " bytes, alignment " << Align << ")\n"); @@ -381,11 +400,11 @@ private: TargetAddress AllocAddr = static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr)); - return call<ReserveMemResponse>(Channel, AllocAddr); + return AllocAddr; } - std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id, - TargetAddress Addr, uint32_t Flags) { + Error handleSetProtections(ResourceIdMgr::ResourceId Id, TargetAddress Addr, + uint32_t Flags) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); @@ -398,24 +417,24 @@ private: return Allocator.setProtections(LocalAddr, Flags); } - std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) { - char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst)); - DEBUG(dbgs() << " Writing " << Size << " bytes to " - << format("0x%016x", RDst) << "\n"); - return Channel.readBytes(Dst, Size); + Error handleWriteMem(DirectBufferWriter DBW) { + DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to " + << format("0x%016x", DBW.getDst()) << "\n"); + return Error::success(); } - std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) { + Error handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) { DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = " << format("0x%016x", PtrVal) << "\n"); uintptr_t *Ptr = reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr)); *Ptr = static_cast<uintptr_t>(PtrVal); - return std::error_code(); + return Error::success(); } ChannelT &Channel; SymbolLookupFtor SymbolLookup; + EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister; std::map<ResourceIdMgr::ResourceId, Allocator> Allocators; typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList; std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners; diff --git a/include/llvm/ExecutionEngine/Orc/RPCChannel.h b/include/llvm/ExecutionEngine/Orc/RPCChannel.h index b97b6daf5864..c569e3cf05b4 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCChannel.h +++ b/include/llvm/ExecutionEngine/Orc/RPCChannel.h @@ -1,13 +1,27 @@ -// -*- c++ -*- +//===- llvm/ExecutionEngine/Orc/RPCChannel.h --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #include "OrcError.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" - -#include <system_error> +#include "llvm/Support/Error.h" +#include <cstddef> +#include <cstdint> +#include <mutex> +#include <string> +#include <tuple> +#include <vector> namespace llvm { namespace orc { @@ -19,40 +33,73 @@ public: virtual ~RPCChannel() {} /// Read Size bytes from the stream into *Dst. - virtual std::error_code readBytes(char *Dst, unsigned Size) = 0; + virtual Error readBytes(char *Dst, unsigned Size) = 0; /// Read size bytes from *Src and append them to the stream. - virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0; + virtual Error appendBytes(const char *Src, unsigned Size) = 0; /// Flush the stream if possible. - virtual std::error_code send() = 0; + virtual Error send() = 0; + + /// Get the lock for stream reading. + std::mutex &getReadLock() { return readLock; } + + /// Get the lock for stream writing. + std::mutex &getWriteLock() { return writeLock; } + +private: + std::mutex readLock, writeLock; }; +/// Notify the channel that we're starting a message send. +/// Locks the channel for writing. +inline Error startSendMessage(RPCChannel &C) { + C.getWriteLock().lock(); + return Error::success(); +} + +/// Notify the channel that we're ending a message send. +/// Unlocks the channel for writing. +inline Error endSendMessage(RPCChannel &C) { + C.getWriteLock().unlock(); + return Error::success(); +} + +/// Notify the channel that we're starting a message receive. +/// Locks the channel for reading. +inline Error startReceiveMessage(RPCChannel &C) { + C.getReadLock().lock(); + return Error::success(); +} + +/// Notify the channel that we're ending a message receive. +/// Unlocks the channel for reading. +inline Error endReceiveMessage(RPCChannel &C) { + C.getReadLock().unlock(); + return Error::success(); +} + /// RPC channel serialization for a variadic list of arguments. template <typename T, typename... Ts> -std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) { - if (auto EC = serialize(C, Arg)) - return EC; - return serialize_seq(C, Args...); +Error serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) { + if (auto Err = serialize(C, Arg)) + return Err; + return serializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. -inline std::error_code serialize_seq(RPCChannel &C) { - return std::error_code(); -} +inline Error serializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel deserialization for a variadic list of arguments. template <typename T, typename... Ts> -std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) { - if (auto EC = deserialize(C, Arg)) - return EC; - return deserialize_seq(C, Args...); +Error deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) { + if (auto Err = deserialize(C, Arg)) + return Err; + return deserializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. -inline std::error_code deserialize_seq(RPCChannel &C) { - return std::error_code(); -} +inline Error deserializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel serialization for integer primitives. template <typename T> @@ -61,7 +108,7 @@ typename std::enable_if< std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value || std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value || std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, - std::error_code>::type + Error>::type serialize(RPCChannel &C, T V) { support::endian::byte_swap<T, support::big>(V); return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T)); @@ -74,106 +121,129 @@ typename std::enable_if< std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value || std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value || std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, - std::error_code>::type + Error>::type deserialize(RPCChannel &C, T &V) { - if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T))) - return EC; + if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T))) + return Err; support::endian::byte_swap<T, support::big>(V); - return std::error_code(); + return Error::success(); } /// RPC channel serialization for enums. template <typename T> -typename std::enable_if<std::is_enum<T>::value, std::error_code>::type +typename std::enable_if<std::is_enum<T>::value, Error>::type serialize(RPCChannel &C, T V) { return serialize(C, static_cast<typename std::underlying_type<T>::type>(V)); } /// RPC channel deserialization for enums. template <typename T> -typename std::enable_if<std::is_enum<T>::value, std::error_code>::type +typename std::enable_if<std::is_enum<T>::value, Error>::type deserialize(RPCChannel &C, T &V) { typename std::underlying_type<T>::type Tmp; - std::error_code EC = deserialize(C, Tmp); + Error Err = deserialize(C, Tmp); V = static_cast<T>(Tmp); - return EC; + return Err; } /// RPC channel serialization for bools. -inline std::error_code serialize(RPCChannel &C, bool V) { +inline Error serialize(RPCChannel &C, bool V) { uint8_t VN = V ? 1 : 0; return C.appendBytes(reinterpret_cast<const char *>(&VN), 1); } /// RPC channel deserialization for bools. -inline std::error_code deserialize(RPCChannel &C, bool &V) { +inline Error deserialize(RPCChannel &C, bool &V) { uint8_t VN = 0; - if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1)) - return EC; + if (auto Err = C.readBytes(reinterpret_cast<char *>(&VN), 1)) + return Err; - V = (VN != 0) ? true : false; - return std::error_code(); + V = (VN != 0); + return Error::success(); } /// RPC channel serialization for StringRefs. /// Note: There is no corresponding deseralization for this, as StringRef /// doesn't own its memory and so can't hold the deserialized data. -inline std::error_code serialize(RPCChannel &C, StringRef S) { - if (auto EC = serialize(C, static_cast<uint64_t>(S.size()))) - return EC; +inline Error serialize(RPCChannel &C, StringRef S) { + if (auto Err = serialize(C, static_cast<uint64_t>(S.size()))) + return Err; return C.appendBytes((const char *)S.bytes_begin(), S.size()); } /// RPC channel serialization for std::strings. -inline std::error_code serialize(RPCChannel &C, const std::string &S) { +inline Error serialize(RPCChannel &C, const std::string &S) { return serialize(C, StringRef(S)); } /// RPC channel deserialization for std::strings. -inline std::error_code deserialize(RPCChannel &C, std::string &S) { +inline Error deserialize(RPCChannel &C, std::string &S) { uint64_t Count; - if (auto EC = deserialize(C, Count)) - return EC; + if (auto Err = deserialize(C, Count)) + return Err; S.resize(Count); return C.readBytes(&S[0], Count); } +// Serialization helper for std::tuple. +template <typename TupleT, size_t... Is> +inline Error serializeTupleHelper(RPCChannel &C, const TupleT &V, + llvm::index_sequence<Is...> _) { + return serializeSeq(C, std::get<Is>(V)...); +} + +/// RPC channel serialization for std::tuple. +template <typename... ArgTs> +inline Error serialize(RPCChannel &C, const std::tuple<ArgTs...> &V) { + return serializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>()); +} + +// Serialization helper for std::tuple. +template <typename TupleT, size_t... Is> +inline Error deserializeTupleHelper(RPCChannel &C, TupleT &V, + llvm::index_sequence<Is...> _) { + return deserializeSeq(C, std::get<Is>(V)...); +} + +/// RPC channel deserialization for std::tuple. +template <typename... ArgTs> +inline Error deserialize(RPCChannel &C, std::tuple<ArgTs...> &V) { + return deserializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>()); +} + /// RPC channel serialization for ArrayRef<T>. -template <typename T> -std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) { - if (auto EC = serialize(C, static_cast<uint64_t>(A.size()))) - return EC; +template <typename T> Error serialize(RPCChannel &C, const ArrayRef<T> &A) { + if (auto Err = serialize(C, static_cast<uint64_t>(A.size()))) + return Err; for (const auto &E : A) - if (auto EC = serialize(C, E)) - return EC; + if (auto Err = serialize(C, E)) + return Err; - return std::error_code(); + return Error::success(); } /// RPC channel serialization for std::array<T>. -template <typename T> -std::error_code serialize(RPCChannel &C, const std::vector<T> &V) { +template <typename T> Error serialize(RPCChannel &C, const std::vector<T> &V) { return serialize(C, ArrayRef<T>(V)); } /// RPC channel deserialization for std::array<T>. -template <typename T> -std::error_code deserialize(RPCChannel &C, std::vector<T> &V) { +template <typename T> Error deserialize(RPCChannel &C, std::vector<T> &V) { uint64_t Count = 0; - if (auto EC = deserialize(C, Count)) - return EC; + if (auto Err = deserialize(C, Count)) + return Err; V.resize(Count); for (auto &E : V) - if (auto EC = deserialize(C, E)) - return EC; + if (auto Err = deserialize(C, E)) + return Err; - return std::error_code(); + return Error::success(); } } // end namespace remote } // end namespace orc } // end namespace llvm -#endif +#endif // LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h index 0bd5cbc0cdde..966a49684348 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCUtils.h +++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h @@ -14,78 +14,256 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H +#include <map> +#include <vector> + +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/Orc/OrcError.h" + +#ifdef _MSC_VER +// concrt.h depends on eh.h for __uncaught_exception declaration +// even if we disable exceptions. +#include <eh.h> + +// Disable warnings from ppltasks.h transitively included by <future>. +#pragma warning(push) +#pragma warning(disable : 4530) +#pragma warning(disable : 4062) +#endif + +#include <future> + +#ifdef _MSC_VER +#pragma warning(pop) +#endif namespace llvm { namespace orc { namespace remote { +/// Describes reserved RPC Function Ids. +/// +/// The default implementation will serve for integer and enum function id +/// types. If you want to use a custom type as your FunctionId you can +/// specialize this class and provide unique values for InvalidId, +/// ResponseId and FirstValidId. + +template <typename T> class RPCFunctionIdTraits { +public: + static const T InvalidId = static_cast<T>(0); + static const T ResponseId = static_cast<T>(1); + static const T FirstValidId = static_cast<T>(2); +}; + // Base class containing utilities that require partial specialization. // These cannot be included in RPC, as template class members cannot be // partially specialized. class RPCBase { protected: - template <typename ProcedureIdT, ProcedureIdT ProcId, typename... Ts> - class ProcedureHelper { + // RPC Function description type. + // + // This class provides the information and operations needed to support the + // RPC primitive operations (call, expect, etc) for a given function. It + // is specialized for void and non-void functions to deal with the differences + // betwen the two. Both specializations have the same interface: + // + // Id - The function's unique identifier. + // OptionalReturn - The return type for asyncronous calls. + // ErrorReturn - The return type for synchronous calls. + // optionalToErrorReturn - Conversion from a valid OptionalReturn to an + // ErrorReturn. + // readResult - Deserialize a result from a channel. + // abandon - Abandon a promised (asynchronous) result. + // respond - Retun a result on the channel. + template <typename FunctionIdT, FunctionIdT FuncId, typename FnT> + class FunctionHelper {}; + + // RPC Function description specialization for non-void functions. + template <typename FunctionIdT, FunctionIdT FuncId, typename RetT, + typename... ArgTs> + class FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> { public: - static const ProcedureIdT Id = ProcId; + static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId && + FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId, + "Cannot define custom function with InvalidId or ResponseId. " + "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId."); + + static const FunctionIdT Id = FuncId; + + typedef Optional<RetT> OptionalReturn; + + typedef Expected<RetT> ErrorReturn; + + static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { + assert(V && "Return value not available"); + return std::move(*V); + } + + template <typename ChannelT> + static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) { + RetT Val; + auto Err = deserialize(C, Val); + auto Err2 = endReceiveMessage(C); + Err = joinErrors(std::move(Err), std::move(Err2)); + + if (Err) { + P.set_value(OptionalReturn()); + return Err; + } + P.set_value(std::move(Val)); + return Error::success(); + } + + static void abandon(std::promise<OptionalReturn> &P) { + P.set_value(OptionalReturn()); + } + + template <typename ChannelT, typename SequenceNumberT> + static Error respond(ChannelT &C, SequenceNumberT SeqNo, + ErrorReturn &Result) { + FunctionIdT ResponseId = RPCFunctionIdTraits<FunctionIdT>::ResponseId; + + // If the handler returned an error then bail out with that. + if (!Result) + return Result.takeError(); + + // Otherwise open a new message on the channel and send the result. + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result)) + return Err; + return endSendMessage(C); + } }; - template <typename ChannelT, typename Proc> class CallHelper; + // RPC Function description specialization for void functions. + template <typename FunctionIdT, FunctionIdT FuncId, typename... ArgTs> + class FunctionHelper<FunctionIdT, FuncId, void(ArgTs...)> { + public: + static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId && + FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId, + "Cannot define custom function with InvalidId or ResponseId. " + "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId."); - template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId, - typename... ArgTs> - class CallHelper<ChannelT, ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> { + static const FunctionIdT Id = FuncId; + + typedef bool OptionalReturn; + typedef Error ErrorReturn; + + static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { + assert(V && "Return value not available"); + return Error::success(); + } + + template <typename ChannelT> + static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) { + // Void functions don't have anything to deserialize, so we're good. + P.set_value(true); + return endReceiveMessage(C); + } + + static void abandon(std::promise<OptionalReturn> &P) { P.set_value(false); } + + template <typename ChannelT, typename SequenceNumberT> + static Error respond(ChannelT &C, SequenceNumberT SeqNo, + ErrorReturn &Result) { + const FunctionIdT ResponseId = + RPCFunctionIdTraits<FunctionIdT>::ResponseId; + + // If the handler returned an error then bail out with that. + if (Result) + return std::move(Result); + + // Otherwise open a new message on the channel and send the result. + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, ResponseId, SeqNo)) + return Err; + return endSendMessage(C); + } + }; + + // Helper for the call primitive. + template <typename ChannelT, typename SequenceNumberT, typename Func> + class CallHelper; + + template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT, + FunctionIdT FuncId, typename RetT, typename... ArgTs> + class CallHelper<ChannelT, SequenceNumberT, + FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> { public: - static std::error_code call(ChannelT &C, const ArgTs &... Args) { - if (auto EC = serialize(C, ProcId)) - return EC; - // If you see a compile-error on this line you're probably calling a - // function with the wrong signature. - return serialize_seq(C, Args...); + static Error call(ChannelT &C, SequenceNumberT SeqNo, + const ArgTs &... Args) { + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...)) + return Err; + return endSendMessage(C); } }; - template <typename ChannelT, typename Proc> class HandlerHelper; + // Helper for handle primitive. + template <typename ChannelT, typename SequenceNumberT, typename Func> + class HandlerHelper; - template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId, - typename... ArgTs> - class HandlerHelper<ChannelT, - ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> { + template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT, + FunctionIdT FuncId, typename RetT, typename... ArgTs> + class HandlerHelper<ChannelT, SequenceNumberT, + FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> { public: template <typename HandlerT> - static std::error_code handle(ChannelT &C, HandlerT Handler) { + static Error handle(ChannelT &C, HandlerT Handler) { return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>()); } private: + typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func; + template <typename HandlerT, size_t... Is> - static std::error_code readAndHandle(ChannelT &C, HandlerT Handler, - llvm::index_sequence<Is...> _) { + static Error readAndHandle(ChannelT &C, HandlerT Handler, + llvm::index_sequence<Is...> _) { std::tuple<ArgTs...> RPCArgs; - if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...)) - return EC; - return Handler(std::get<Is>(RPCArgs)...); + SequenceNumberT SeqNo; + // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning + // for RPCArgs. Void cast RPCArgs to work around this for now. + // FIXME: Remove this workaround once we can assume a working GCC version. + (void)RPCArgs; + if (auto Err = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...)) + return Err; + + // We've deserialized the arguments, so unlock the channel for reading + // before we call the handler. This allows recursive RPC calls. + if (auto Err = endReceiveMessage(C)) + return Err; + + // Run the handler and get the result. + auto Result = Handler(std::get<Is>(RPCArgs)...); + + // Return the result to the client. + return Func::template respond<ChannelT, SequenceNumberT>(C, SeqNo, + Result); } }; - template <typename ClassT, typename... ArgTs> class MemberFnWrapper { + // Helper for wrapping member functions up as functors. + template <typename ClassT, typename RetT, typename... ArgTs> + class MemberFnWrapper { public: - typedef std::error_code (ClassT::*MethodT)(ArgTs...); + typedef RetT (ClassT::*MethodT)(ArgTs...); MemberFnWrapper(ClassT &Instance, MethodT Method) : Instance(Instance), Method(Method) {} - std::error_code operator()(ArgTs &... Args) { - return (Instance.*Method)(Args...); - } + RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); } private: ClassT &Instance; MethodT Method; }; + // Helper that provides a Functor for deserializing arguments. template <typename... ArgTs> class ReadArgs { public: - std::error_code operator()() { return std::error_code(); } + Error operator()() { return Error::success(); } }; template <typename ArgT, typename... ArgTs> @@ -94,7 +272,7 @@ protected: ReadArgs(ArgT &Arg, ArgTs &... Args) : ReadArgs<ArgTs...>(Args...), Arg(Arg) {} - std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) { + Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) { this->Arg = std::move(ArgVal); return ReadArgs<ArgTs...>::operator()(ArgVals...); } @@ -106,7 +284,7 @@ protected: /// Contains primitive utilities for defining, calling and handling calls to /// remote procedures. ChannelT is a bidirectional stream conforming to the -/// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure +/// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure /// identifier type that must be serializable on ChannelT. /// /// These utilities support the construction of very primitive RPC utilities. @@ -123,120 +301,223 @@ protected: /// /// Overview (see comments individual types/methods for details): /// -/// Procedure<Id, Args...> : +/// Function<Id, Args...> : /// /// associates a unique serializable id with an argument list. /// /// -/// call<Proc>(Channel, Args...) : +/// call<Func>(Channel, Args...) : /// -/// Calls the remote procedure 'Proc' by serializing Proc's id followed by its +/// Calls the remote procedure 'Func' by serializing Func's id followed by its /// arguments and sending the resulting bytes to 'Channel'. /// /// -/// handle<Proc>(Channel, <functor matching std::error_code(Args...)> : +/// handle<Func>(Channel, <functor matching Error(Args...)> : /// -/// Handles a call to 'Proc' by deserializing its arguments and calling the -/// given functor. This assumes that the id for 'Proc' has already been +/// Handles a call to 'Func' by deserializing its arguments and calling the +/// given functor. This assumes that the id for 'Func' has already been /// deserialized. /// -/// expect<Proc>(Channel, <functor matching std::error_code(Args...)> : +/// expect<Func>(Channel, <functor matching Error(Args...)> : /// /// The same as 'handle', except that the procedure id should not have been -/// read yet. Expect will deserialize the id and assert that it matches Proc's +/// read yet. Expect will deserialize the id and assert that it matches Func's /// id. If it does not, and unexpected RPC call error is returned. - -template <typename ChannelT, typename ProcedureIdT = uint32_t> +template <typename ChannelT, typename FunctionIdT = uint32_t, + typename SequenceNumberT = uint16_t> class RPC : public RPCBase { public: + /// RPC default constructor. + RPC() = default; + + /// RPC instances cannot be copied. + RPC(const RPC &) = delete; + + /// RPC instances cannot be copied. + RPC &operator=(const RPC &) = delete; + + /// RPC move constructor. + // FIXME: Remove once MSVC can synthesize move ops. + RPC(RPC &&Other) + : SequenceNumberMgr(std::move(Other.SequenceNumberMgr)), + OutstandingResults(std::move(Other.OutstandingResults)) {} + + /// RPC move assignment. + // FIXME: Remove once MSVC can synthesize move ops. + RPC &operator=(RPC &&Other) { + SequenceNumberMgr = std::move(Other.SequenceNumberMgr); + OutstandingResults = std::move(Other.OutstandingResults); + return *this; + } + /// Utility class for defining/referring to RPC procedures. /// /// Typedefs of this utility are used when calling/handling remote procedures. /// - /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any - /// other Procedure typedef in the RPC API being defined. + /// FuncId should be a unique value of FunctionIdT (i.e. not used with any + /// other Function typedef in the RPC API being defined. /// /// the template argument Ts... gives the argument list for the remote /// procedure. /// /// E.g. /// - /// typedef Procedure<0, bool> Proc1; - /// typedef Procedure<1, std::string, std::vector<int>> Proc2; + /// typedef Function<0, bool> Func1; + /// typedef Function<1, std::string, std::vector<int>> Func2; /// - /// if (auto EC = call<Proc1>(Channel, true)) - /// /* handle EC */; + /// if (auto Err = call<Func1>(Channel, true)) + /// /* handle Err */; /// - /// if (auto EC = expect<Proc2>(Channel, + /// if (auto Err = expect<Func2>(Channel, /// [](std::string &S, std::vector<int> &V) { /// // Stuff. - /// return std::error_code(); + /// return Error::success(); /// }) - /// /* handle EC */; + /// /* handle Err */; /// - template <ProcedureIdT ProcId, typename... Ts> - using Procedure = ProcedureHelper<ProcedureIdT, ProcId, Ts...>; + template <FunctionIdT FuncId, typename FnT> + using Function = FunctionHelper<FunctionIdT, FuncId, FnT>; + + /// Return type for asynchronous call primitives. + template <typename Func> + using AsyncCallResult = std::future<typename Func::OptionalReturn>; + + /// Return type for asynchronous call-with-seq primitives. + template <typename Func> + using AsyncCallWithSeqResult = + std::pair<std::future<typename Func::OptionalReturn>, SequenceNumberT>; /// Serialize Args... to channel C, but do not call C.send(). /// - /// For buffered channels, this can be used to queue up several calls before - /// flushing the channel. - template <typename Proc, typename... ArgTs> - static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) { - return CallHelper<ChannelT, Proc>::call(C, Args...); + /// Returns an error (on serialization failure) or a pair of: + /// (1) A future Optional<T> (or future<bool> for void functions), and + /// (2) A sequence number. + /// + /// This utility function is primarily used for single-threaded mode support, + /// where the sequence number can be used to wait for the corresponding + /// result. In multi-threaded mode the appendCallAsync method, which does not + /// return the sequence numeber, should be preferred. + template <typename Func, typename... ArgTs> + Expected<AsyncCallWithSeqResult<Func>> + appendCallAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { + auto SeqNo = SequenceNumberMgr.getSequenceNumber(); + std::promise<typename Func::OptionalReturn> Promise; + auto Result = Promise.get_future(); + OutstandingResults[SeqNo] = + createOutstandingResult<Func>(std::move(Promise)); + + if (auto Err = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo, + Args...)) { + abandonOutstandingResults(); + return std::move(Err); + } else + return AsyncCallWithSeqResult<Func>(std::move(Result), SeqNo); } - /// Serialize Args... to channel C and call C.send(). - template <typename Proc, typename... ArgTs> - static std::error_code call(ChannelT &C, const ArgTs &... Args) { - if (auto EC = appendCall<Proc>(C, Args...)) - return EC; - return C.send(); + /// The same as appendCallAsyncWithSeq, except that it calls C.send() to + /// flush the channel after serializing the call. + template <typename Func, typename... ArgTs> + Expected<AsyncCallWithSeqResult<Func>> + callAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { + auto Result = appendCallAsyncWithSeq<Func>(C, Args...); + if (!Result) + return Result; + if (auto Err = C.send()) { + abandonOutstandingResults(); + return std::move(Err); + } + return Result; + } + + /// Serialize Args... to channel C, but do not call send. + /// Returns an error if serialization fails, otherwise returns a + /// std::future<Optional<T>> (or a future<bool> for void functions). + template <typename Func, typename... ArgTs> + Expected<AsyncCallResult<Func>> appendCallAsync(ChannelT &C, + const ArgTs &... Args) { + auto ResAndSeqOrErr = appendCallAsyncWithSeq<Func>(C, Args...); + if (ResAndSeqOrErr) + return std::move(ResAndSeqOrErr->first); + return ResAndSeqOrErr.getError(); + } + + /// The same as appendCallAsync, except that it calls C.send to flush the + /// channel after serializing the call. + template <typename Func, typename... ArgTs> + Expected<AsyncCallResult<Func>> callAsync(ChannelT &C, + const ArgTs &... Args) { + auto ResAndSeqOrErr = callAsyncWithSeq<Func>(C, Args...); + if (ResAndSeqOrErr) + return std::move(ResAndSeqOrErr->first); + return ResAndSeqOrErr.getError(); + } + + /// This can be used in single-threaded mode. + template <typename Func, typename HandleFtor, typename... ArgTs> + typename Func::ErrorReturn + callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) { + if (auto ResultAndSeqNoOrErr = callAsyncWithSeq<Func>(C, Args...)) { + auto &ResultAndSeqNo = *ResultAndSeqNoOrErr; + if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther)) + return std::move(Err); + return Func::optionalToErrorReturn(ResultAndSeqNo.first.get()); + } else + return ResultAndSeqNoOrErr.takeError(); } - /// Deserialize and return an enum whose underlying type is ProcedureIdT. - static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) { + // This can be used in single-threaded mode. + template <typename Func, typename... ArgTs> + typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) { + return callSTHandling<Func>(C, handleNone, Args...); + } + + /// Start receiving a new function call. + /// + /// Calls startReceiveMessage on the channel, then deserializes a FunctionId + /// into Id. + Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) { + if (auto Err = startReceiveMessage(C)) + return Err; + return deserialize(C, Id); } - /// Deserialize args for Proc from C and call Handler. The signature of - /// handler must conform to 'std::error_code(Args...)' where Args... matches - /// the arguments used in the Proc typedef. - template <typename Proc, typename HandlerT> - static std::error_code handle(ChannelT &C, HandlerT Handler) { - return HandlerHelper<ChannelT, Proc>::handle(C, Handler); + /// Deserialize args for Func from C and call Handler. The signature of + /// handler must conform to 'Error(Args...)' where Args... matches + /// the arguments used in the Func typedef. + template <typename Func, typename HandlerT> + static Error handle(ChannelT &C, HandlerT Handler) { + return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C, Handler); } /// Helper version of 'handle' for calling member functions. - template <typename Proc, typename ClassT, typename... ArgTs> - static std::error_code - handle(ChannelT &C, ClassT &Instance, - std::error_code (ClassT::*HandlerMethod)(ArgTs...)) { - return handle<Proc>( - C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod)); + template <typename Func, typename ClassT, typename RetT, typename... ArgTs> + static Error handle(ChannelT &C, ClassT &Instance, + RetT (ClassT::*HandlerMethod)(ArgTs...)) { + return handle<Func>( + C, MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance, HandlerMethod)); } - /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc. + /// Deserialize a FunctionIdT from C and verify it matches the id for Func. /// If the id does match, deserialize the arguments and call the handler /// (similarly to handle). /// If the id does not match, return an unexpect RPC call error and do not /// deserialize any further bytes. - template <typename Proc, typename HandlerT> - static std::error_code expect(ChannelT &C, HandlerT Handler) { - ProcedureIdT ProcId; - if (auto EC = getNextProcId(C, ProcId)) - return EC; - if (ProcId != Proc::Id) + template <typename Func, typename HandlerT> + Error expect(ChannelT &C, HandlerT Handler) { + FunctionIdT FuncId; + if (auto Err = startReceivingFunction(C, FuncId)) + return std::move(Err); + if (FuncId != Func::Id) return orcError(OrcErrorCode::UnexpectedRPCCall); - return handle<Proc>(C, Handler); + return handle<Func>(C, Handler); } /// Helper version of expect for calling member functions. - template <typename Proc, typename ClassT, typename... ArgTs> - static std::error_code - expect(ChannelT &C, ClassT &Instance, - std::error_code (ClassT::*HandlerMethod)(ArgTs...)) { - return expect<Proc>( + template <typename Func, typename ClassT, typename... ArgTs> + static Error expect(ChannelT &C, ClassT &Instance, + Error (ClassT::*HandlerMethod)(ArgTs...)) { + return expect<Func>( C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod)); } @@ -245,18 +526,165 @@ public: /// channel. /// E.g. /// - /// typedef Procedure<0, bool, int> Proc1; + /// typedef Function<0, bool, int> Func1; /// /// ... /// bool B; /// int I; - /// if (auto EC = expect<Proc1>(Channel, readArgs(B, I))) + /// if (auto Err = expect<Func1>(Channel, readArgs(B, I))) /// /* Handle Args */ ; /// template <typename... ArgTs> static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) { return ReadArgs<ArgTs...>(Args...); } + + /// Read a response from Channel. + /// This should be called from the receive loop to retrieve results. + Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) { + SequenceNumberT SeqNo; + if (auto Err = deserialize(C, SeqNo)) { + abandonOutstandingResults(); + return Err; + } + + if (SeqNoRet) + *SeqNoRet = SeqNo; + + auto I = OutstandingResults.find(SeqNo); + if (I == OutstandingResults.end()) { + abandonOutstandingResults(); + return orcError(OrcErrorCode::UnexpectedRPCResponse); + } + + if (auto Err = I->second->readResult(C)) { + abandonOutstandingResults(); + // FIXME: Release sequence numbers? + return Err; + } + + OutstandingResults.erase(I); + SequenceNumberMgr.releaseSequenceNumber(SeqNo); + + return Error::success(); + } + + // Loop waiting for a result with the given sequence number. + // This can be used as a receive loop if the user doesn't have a default. + template <typename HandleOtherFtor> + Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo, + HandleOtherFtor &HandleOther = handleNone) { + bool GotTgtResult = false; + + while (!GotTgtResult) { + FunctionIdT Id = RPCFunctionIdTraits<FunctionIdT>::InvalidId; + if (auto Err = startReceivingFunction(C, Id)) + return Err; + if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) { + SequenceNumberT SeqNo; + if (auto Err = handleResponse(C, &SeqNo)) + return Err; + GotTgtResult = (SeqNo == TgtSeqNo); + } else if (auto Err = HandleOther(C, Id)) + return Err; + } + + return Error::success(); + } + + // Default handler for 'other' (non-response) functions when waiting for a + // result from the channel. + static Error handleNone(ChannelT &, FunctionIdT) { + return orcError(OrcErrorCode::UnexpectedRPCCall); + }; + +private: + // Manage sequence numbers. + class SequenceNumberManager { + public: + SequenceNumberManager() = default; + + SequenceNumberManager(const SequenceNumberManager &) = delete; + SequenceNumberManager &operator=(const SequenceNumberManager &) = delete; + + SequenceNumberManager(SequenceNumberManager &&Other) + : NextSequenceNumber(std::move(Other.NextSequenceNumber)), + FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {} + + SequenceNumberManager &operator=(SequenceNumberManager &&Other) { + NextSequenceNumber = std::move(Other.NextSequenceNumber); + FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers); + } + + void reset() { + std::lock_guard<std::mutex> Lock(SeqNoLock); + NextSequenceNumber = 0; + FreeSequenceNumbers.clear(); + } + + SequenceNumberT getSequenceNumber() { + std::lock_guard<std::mutex> Lock(SeqNoLock); + if (FreeSequenceNumbers.empty()) + return NextSequenceNumber++; + auto SequenceNumber = FreeSequenceNumbers.back(); + FreeSequenceNumbers.pop_back(); + return SequenceNumber; + } + + void releaseSequenceNumber(SequenceNumberT SequenceNumber) { + std::lock_guard<std::mutex> Lock(SeqNoLock); + FreeSequenceNumbers.push_back(SequenceNumber); + } + + private: + std::mutex SeqNoLock; + SequenceNumberT NextSequenceNumber = 0; + std::vector<SequenceNumberT> FreeSequenceNumbers; + }; + + // Base class for results that haven't been returned from the other end of the + // RPC connection yet. + class OutstandingResult { + public: + virtual ~OutstandingResult() {} + virtual Error readResult(ChannelT &C) = 0; + virtual void abandon() = 0; + }; + + // Outstanding results for a specific function. + template <typename Func> + class OutstandingResultImpl : public OutstandingResult { + private: + public: + OutstandingResultImpl(std::promise<typename Func::OptionalReturn> &&P) + : P(std::move(P)) {} + + Error readResult(ChannelT &C) override { return Func::readResult(C, P); } + + void abandon() override { Func::abandon(P); } + + private: + std::promise<typename Func::OptionalReturn> P; + }; + + // Create an outstanding result for the given function. + template <typename Func> + std::unique_ptr<OutstandingResult> + createOutstandingResult(std::promise<typename Func::OptionalReturn> &&P) { + return llvm::make_unique<OutstandingResultImpl<Func>>(std::move(P)); + } + + // Abandon all outstanding results. + void abandonOutstandingResults() { + for (auto &KV : OutstandingResults) + KV.second->abandon(); + OutstandingResults.clear(); + SequenceNumberMgr.reset(); + } + + SequenceNumberManager SequenceNumberMgr; + std::map<SequenceNumberT, std::unique_ptr<OutstandingResult>> + OutstandingResults; }; } // end namespace remote diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h index c5006962550e..adcb063f4544 100644 --- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h +++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h @@ -16,7 +16,6 @@ #include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Memory.h" @@ -62,8 +61,19 @@ public: RTDyldMemoryManager() {} ~RTDyldMemoryManager() override; - void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override; - void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override; + /// Register EH frames in the current process. + static void registerEHFramesInProcess(uint8_t *Addr, size_t Size); + + /// Deregister EH frames in the current proces. + static void deregisterEHFramesInProcess(uint8_t *Addr, size_t Size); + + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override { + registerEHFramesInProcess(Addr, Size); + } + + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override { + registerEHFramesInProcess(Addr, Size); + } /// This method returns the address of the specified function or variable in /// the current process. diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index 100e97b8b3d9..bd485de91bd4 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -16,20 +16,35 @@ #include "JITSymbolFlags.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Memory.h" -#include "llvm/DebugInfo/DIContext.h" #include <map> #include <memory> +#include <utility> namespace llvm { +class StringRef; + namespace object { class ObjectFile; template <typename T> class OwningBinary; } +/// Base class for errors originating in RuntimeDyld, e.g. missing relocation +/// support. +class RuntimeDyldError : public ErrorInfo<RuntimeDyldError> { +public: + static char ID; + RuntimeDyldError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {} + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const { return ErrMsg; } + std::error_code convertToErrorCode() const override; +private: + std::string ErrMsg; +}; + class RuntimeDyldImpl; class RuntimeDyldCheckerImpl; @@ -64,7 +79,7 @@ public: typedef std::map<object::SectionRef, unsigned> ObjSectionToIDMap; LoadedObjectInfo(RuntimeDyldImpl &RTDyld, ObjSectionToIDMap ObjSecToIDMap) - : RTDyld(RTDyld), ObjSecToIDMap(ObjSecToIDMap) { } + : RTDyld(RTDyld), ObjSecToIDMap(std::move(ObjSecToIDMap)) {} virtual object::OwningBinary<object::ObjectFile> getObjectForDebug(const object::ObjectFile &Obj) const = 0; @@ -179,17 +194,9 @@ public: public: virtual ~SymbolResolver() {} - /// This method returns the address of the specified function or variable. - /// It is used to resolve symbols during module linking. - /// - /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will - /// skip all relocations for that symbol, and the client will be responsible - /// for handling them manually. - virtual SymbolInfo findSymbol(const std::string &Name) = 0; - /// This method returns the address of the specified symbol if it exists /// within the logical dynamic library represented by this - /// RTDyldMemoryManager. Unlike getSymbolAddress, queries through this + /// RTDyldMemoryManager. Unlike findSymbol, queries through this /// interface should return addresses for hidden symbols. /// /// This is of particular importance for the Orc JIT APIs, which support lazy @@ -198,13 +205,17 @@ public: /// writing memory managers for MCJIT can usually ignore this method. /// /// This method will be queried by RuntimeDyld when checking for previous - /// definitions of common symbols. It will *not* be queried by default when - /// resolving external symbols (this minimises the link-time overhead for - /// MCJIT clients who don't care about Orc features). If you are writing a - /// RTDyldMemoryManager for Orc and want "external" symbol resolution to - /// search the logical dylib, you should override your getSymbolAddress - /// method call this method directly. + /// definitions of common symbols. virtual SymbolInfo findSymbolInLogicalDylib(const std::string &Name) = 0; + + /// This method returns the address of the specified function or variable. + /// It is used to resolve symbols during module linking. + /// + /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will + /// skip all relocations for that symbol, and the client will be responsible + /// for handling them manually. + virtual SymbolInfo findSymbol(const std::string &Name) = 0; + private: virtual void anchor(); }; diff --git a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h index 31ce151c56a3..f5f52b5d2f92 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -10,10 +10,14 @@ #ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H #define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H -#include "llvm/ADT/StringRef.h" +#include <cstdint> +#include <memory> +#include <string> +#include <utility> namespace llvm { +class StringRef; class MCDisassembler; class MemoryBuffer; class MCInstPrinter; diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h index 0092f49e49ad..d8b280a66f18 100644 --- a/include/llvm/IR/Argument.h +++ b/include/llvm/IR/Argument.h @@ -73,6 +73,12 @@ public: /// containing function. bool hasByValAttr() const; + /// \brief Return true if this argument has the swiftself attribute. + bool hasSwiftSelfAttr() const; + + /// \brief 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. @@ -120,9 +126,20 @@ public: /// \brief Add a Attribute to an argument. void addAttr(AttributeSet AS); + void addAttr(Attribute::AttrKind Kind) { + addAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + } + /// \brief Remove a Attribute from an argument. void removeAttr(AttributeSet AS); + void removeAttr(Attribute::AttrKind Kind) { + removeAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + } + + /// \brief Checks 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. static inline bool classof(const Value *V) { diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 0e3373165407..af1bf0a354ec 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -18,8 +18,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm-c/Types.h" #include <bitset> #include <cassert> #include <map> @@ -94,6 +96,9 @@ public: uint64_t Bytes); static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context, uint64_t Bytes); + static Attribute getWithAllocSizeArgs(LLVMContext &Context, + unsigned ElemSizeArg, + const Optional<unsigned> &NumElemsArg); //===--------------------------------------------------------------------===// // Attribute Accessors @@ -116,11 +121,11 @@ public: bool hasAttribute(StringRef Val) const; /// \brief Return the attribute's kind as an enum (Attribute::AttrKind). This - /// requires the attribute to be an enum or alignment attribute. + /// requires the attribute to be an enum or integer attribute. Attribute::AttrKind getKindAsEnum() const; /// \brief Return the attribute's value as an integer. This requires that the - /// attribute be an alignment attribute. + /// attribute be an integer attribute. uint64_t getValueAsInt() const; /// \brief Return the attribute's kind as a string. This requires the @@ -147,6 +152,10 @@ public: /// dereferenceable_or_null attribute. uint64_t getDereferenceableOrNullBytes() const; + /// Returns the argument numbers for the allocsize attribute (or pair(0, 0) + /// if not known). + std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; + /// \brief The Attribute is converted to a string of equivalent mnemonic. This /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString(bool InAttrGrp = false) const; @@ -161,8 +170,28 @@ public: void Profile(FoldingSetNodeID &ID) const { ID.AddPointer(pImpl); } + + /// \brief Return a raw pointer that uniquely identifies this attribute. + void *getRawPointer() const { + return pImpl; + } + + /// \brief Get an attribute from a raw pointer created by getRawPointer. + static Attribute fromRawPointer(void *RawPtr) { + return Attribute(reinterpret_cast<AttributeImpl*>(RawPtr)); + } }; +// Specialized opaque value conversions. +inline LLVMAttributeRef wrap(Attribute Attr) { + return reinterpret_cast<LLVMAttributeRef>(Attr.getRawPointer()); +} + +// Specialized opaque value conversions. +inline Attribute unwrap(LLVMAttributeRef Attr) { + return Attribute::fromRawPointer(Attr); +} + //===----------------------------------------------------------------------===// /// \class /// \brief This class holds the attributes for a function, its return value, and @@ -213,20 +242,20 @@ public: /// \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> Kind); + 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 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 Attr) const; + 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) const; - AttributeSet addAttribute(LLVMContext &C, unsigned Index, - StringRef Kind, StringRef Value) const; + AttributeSet 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. @@ -242,7 +271,13 @@ public: /// attribute list. Because attribute lists are immutable, this returns the /// new list. AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Attr) const; + 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; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the @@ -267,6 +302,12 @@ public: AttributeSet 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); + //===--------------------------------------------------------------------===// // AttributeSet Accessors //===--------------------------------------------------------------------===// @@ -292,9 +333,15 @@ public: /// \brief Return true if attribute exists at the given index. bool hasAttributes(unsigned Index) const; + /// \brief Equivalent to hasAttribute(AttributeSet::FunctionIndex, Kind) but + /// may be faster. + bool hasFnAttribute(Attribute::AttrKind Kind) const; + /// \brief Return true if the specified attribute is set for at least one - /// parameter or for the return value. - bool hasAttrSomewhere(Attribute::AttrKind Attr) const; + /// parameter or for the return value. If Index is not nullptr, the index + /// of a parameter with the specified attribute is provided. + bool hasAttrSomewhere(Attribute::AttrKind Kind, + unsigned *Index = nullptr) const; /// \brief Return the attribute object that exists at the given index. Attribute getAttribute(unsigned Index, Attribute::AttrKind Kind) const; @@ -315,6 +362,10 @@ public: /// unknown). uint64_t getDereferenceableOrNullBytes(unsigned Index) const; + /// Get the allocsize argument numbers (or pair(0, 0) if unknown). + std::pair<unsigned, Optional<unsigned>> + getAllocSizeArgs(unsigned Index) const; + /// \brief Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; @@ -396,19 +447,20 @@ class AttrBuilder { uint64_t StackAlignment; uint64_t DerefBytes; uint64_t DerefOrNullBytes; + uint64_t AllocSizeArgs; public: AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) {} + DerefOrNullBytes(0), AllocSizeArgs(0) {} explicit AttrBuilder(uint64_t Val) : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) { + DerefOrNullBytes(0), AllocSizeArgs(0) { addRawValue(Val); } AttrBuilder(const Attribute &A) : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) { + DerefOrNullBytes(0), AllocSizeArgs(0) { addAttribute(A); } AttrBuilder(AttributeSet AS, unsigned Idx); @@ -477,6 +529,10 @@ public: /// dereferenceable_or_null attribute exists (zero is returned otherwise). uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; } + /// Retrieve the allocsize args, if the allocsize attribute exists. If it + /// doesn't exist, pair(0, 0) is returned. + std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; + /// \brief This turns an int alignment (which must be a power of 2) into the /// form used internally in Attribute. AttrBuilder &addAlignmentAttr(unsigned Align); @@ -493,6 +549,14 @@ public: /// form used internally in Attribute. AttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes); + /// This turns one (or two) ints into the form used internally in Attribute. + AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg, + const Optional<unsigned> &NumElemsArg); + + /// Add an allocsize attribute, using the representation returned by + /// Attribute.getIntValue(). + AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr); + /// \brief Return true if the builder contains no target-independent /// attributes. bool empty() const { return Attrs.none(); } diff --git a/include/llvm/IR/Attributes.td b/include/llvm/IR/Attributes.td index 30249bbd8fab..7b63638a3f6a 100644 --- a/include/llvm/IR/Attributes.td +++ b/include/llvm/IR/Attributes.td @@ -16,6 +16,10 @@ class StrBoolAttr<string S> : Attr<S>; /// 0 means unaligned (different from align(1)). def Alignment : EnumAttr<"align">; +/// The result of the function is guaranteed to point to a number of bytes that +/// we can determine if we know the value of the function's arguments. +def AllocSize : EnumAttr<"allocsize">; + /// inline=always. def AlwaysInline : EnumAttr<"alwaysinline">; @@ -154,9 +158,18 @@ def SanitizeThread : EnumAttr<"sanitize_thread">; /// MemorySanitizer is on. def SanitizeMemory : EnumAttr<"sanitize_memory">; +/// Argument is swift error. +def SwiftError : EnumAttr<"swifterror">; + +/// Argument is swift self/context. +def SwiftSelf : EnumAttr<"swiftself">; + /// Function must be in a unwind table. def UWTable : EnumAttr<"uwtable">; +/// Function only writes to memory. +def WriteOnly : EnumAttr<"writeonly">; + /// Zero extended before/after call. def ZExt : EnumAttr<"zeroext">; @@ -165,6 +178,7 @@ def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; def NoNansFPMath : StrBoolAttr<"no-nans-fp-math">; def UnsafeFPMath : StrBoolAttr<"unsafe-fp-math">; +def NoJumpTables : StrBoolAttr<"no-jump-tables">; class CompatRule<string F> { // The name of the function called to check the attribute of the caller and @@ -179,6 +193,7 @@ class CompatRule<string F> { def : CompatRule<"isEqual<SanitizeAddressAttr>">; def : CompatRule<"isEqual<SanitizeThreadAttr>">; def : CompatRule<"isEqual<SanitizeMemoryAttr>">; +def : CompatRule<"isEqual<SafeStackAttr>">; class MergeRule<string F> { // The name of the function called to merge the attributes of the caller and @@ -194,4 +209,5 @@ def : MergeRule<"setAND<NoInfsFPMathAttr>">; def : MergeRule<"setAND<NoNansFPMathAttr>">; def : MergeRule<"setAND<UnsafeFPMathAttr>">; def : MergeRule<"setOR<NoImplicitFloatAttr>">; +def : MergeRule<"setOR<NoJumpTablesAttr>">; def : MergeRule<"adjustCallerSSPLevel">; diff --git a/include/llvm/IR/AutoUpgrade.h b/include/llvm/IR/AutoUpgrade.h index a4b3c410c4f6..9eb358682c65 100644 --- a/include/llvm/IR/AutoUpgrade.h +++ b/include/llvm/IR/AutoUpgrade.h @@ -14,13 +14,14 @@ #ifndef LLVM_IR_AUTOUPGRADE_H #define LLVM_IR_AUTOUPGRADE_H -#include <string> +#include "llvm/ADT/StringRef.h" namespace llvm { class CallInst; class Constant; class Function; class Instruction; + class MDNode; class Module; class GlobalVariable; class Type; @@ -46,6 +47,10 @@ namespace llvm { /// if it requires upgrading. bool UpgradeGlobalVariable(GlobalVariable *GV); + /// This checks for module flags which should be upgraded. It returns true if + /// module is modified. + bool UpgradeModuleFlags(Module &M); + /// If the TBAA tag for the given instruction uses the scalar TBAA format, /// we upgrade it to the struct-path aware TBAA format. void UpgradeInstWithTBAATag(Instruction *I); @@ -64,8 +69,14 @@ namespace llvm { /// info. Return true if module is modified. bool UpgradeDebugInfo(Module &M); - /// Upgrade a metadata string constant in place. - void UpgradeMDStringConstant(std::string &String); + /// Check whether a string looks like an old loop attachment tag. + inline bool mayBeOldLoopAttachmentTag(StringRef Name) { + return Name.startswith("llvm.vectorizer."); + } + + /// Upgrade the loop attachment metadata node. + MDNode *upgradeInstructionLoopAttachment(MDNode &N); + } // End llvm namespace #endif diff --git a/include/llvm/IR/BasicBlock.h b/include/llvm/IR/BasicBlock.h index c6b54d308ce6..e7daf6ee238e 100644 --- a/include/llvm/IR/BasicBlock.h +++ b/include/llvm/IR/BasicBlock.h @@ -111,6 +111,14 @@ public: TerminatorInst *getTerminator(); const TerminatorInst *getTerminator() const; + /// \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(); + } + /// \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. diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index f7bfb47a5b44..9c977aef941a 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -273,6 +273,10 @@ public: CALLSITE_DELEGATE_GETTER(getArgOperand(i)); } + ValTy *getReturnedArgOperand() const { + CALLSITE_DELEGATE_GETTER(getReturnedArgOperand()); + } + bool isInlineAsm() const { if (isCall()) return cast<CallInst>(getInstruction())->isInlineAsm(); @@ -305,19 +309,51 @@ public: CALLSITE_DELEGATE_SETTER(setAttributes(PAL)); } + void addAttribute(unsigned i, Attribute::AttrKind Kind) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Kind)); + } + + void addAttribute(unsigned i, StringRef Kind, StringRef Value) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Kind, Value)); + } + + void addAttribute(unsigned i, Attribute Attr) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Attr)); + } + + void removeAttribute(unsigned i, Attribute::AttrKind Kind) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); + } + + void removeAttribute(unsigned i, StringRef Kind) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); + } + + void removeAttribute(unsigned i, Attribute Attr) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Attr)); + } + /// \brief Return true if this function has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(A)); + bool hasFnAttr(Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } /// \brief Return true if this function has the given attribute. - bool hasFnAttr(StringRef A) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(A)); + 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 A) const { - CALLSITE_DELEGATE_GETTER(paramHasAttr(i, A)); + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(paramHasAttr(i, Kind)); + } + + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); + } + + Attribute getAttribute(unsigned i, StringRef Kind) const { + CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); } /// \brief Return true if the data operand at index \p i directly or @@ -327,8 +363,8 @@ public: /// in the attribute set attached to this instruction, while operand bundle /// operands may have some attributes implied by the type of its containing /// operand bundle. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const { - CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, A)); + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, Kind)); } /// @brief Extract the alignment for a call or parameter (0=unknown). @@ -385,6 +421,14 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory()); } + /// @brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + CALLSITE_DELEGATE_GETTER(doesNotReadMemory()); + } + void setDoesNotReadMemory() { + CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory()); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { @@ -410,6 +454,25 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotThrow()); } + /// @brief Determine if the call can be duplicated. + bool cannotDuplicate() const { + CALLSITE_DELEGATE_GETTER(cannotDuplicate()); + } + void setCannotDuplicate() { + CALLSITE_DELEGATE_GETTER(setCannotDuplicate()); + } + + /// @brief Determine if the call is convergent. + bool isConvergent() const { + CALLSITE_DELEGATE_GETTER(isConvergent()); + } + void setConvergent() { + CALLSITE_DELEGATE_SETTER(setConvergent()); + } + void setNotConvergent() { + CALLSITE_DELEGATE_SETTER(setNotConvergent()); + } + unsigned getNumOperandBundles() const { CALLSITE_DELEGATE_GETTER(getNumOperandBundles()); } @@ -442,6 +505,10 @@ public: CALLSITE_DELEGATE_GETTER(getOperandBundle(ID)); } + unsigned countOperandBundlesOfType(uint32_t ID) const { + CALLSITE_DELEGATE_GETTER(countOperandBundlesOfType(ID)); + } + IterTy arg_begin() const { CALLSITE_DELEGATE_GETTER(arg_begin()); } diff --git a/include/llvm/IR/CallingConv.h b/include/llvm/IR/CallingConv.h index bc050928266e..4987b7e943f2 100644 --- a/include/llvm/IR/CallingConv.h +++ b/include/llvm/IR/CallingConv.h @@ -168,6 +168,31 @@ namespace CallingConv { /// subtargets. X86_INTR = 83, + /// Used for AVR interrupt routines. + AVR_INTR = 84, + + /// Calling convention used for AVR signal routines. + AVR_SIGNAL = 85, + + /// Calling convention used for special AVR rtlib functions + /// which have an "optimized" convention to preserve registers. + AVR_BUILTIN = 86, + + /// Calling convention used for Mesa vertex shaders. + AMDGPU_VS = 87, + + /// Calling convention used for Mesa geometry shaders. + AMDGPU_GS = 88, + + /// Calling convention used for Mesa pixel shaders. + AMDGPU_PS = 89, + + /// Calling convention used for Mesa compute shaders. + AMDGPU_CS = 90, + + /// Calling convention for AMDGPU code object kernels. + AMDGPU_KERNEL = 91, + /// The highest possible calling convention ID. Must be some 2^k - 1. MaxID = 1023 }; diff --git a/include/llvm/IR/Comdat.h b/include/llvm/IR/Comdat.h index fb79e13af3a5..577247f27e20 100644 --- a/include/llvm/IR/Comdat.h +++ b/include/llvm/IR/Comdat.h @@ -16,12 +16,10 @@ #ifndef LLVM_IR_COMDAT_H #define LLVM_IR_COMDAT_H -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" - namespace llvm { class raw_ostream; +class StringRef; template <typename ValueTy> class StringMapEntry; // This is a Name X SelectionKind pair. The reason for having this be an @@ -48,7 +46,6 @@ public: private: friend class Module; Comdat(); - Comdat(SelectionKind SK, StringMapEntry<Comdat> *Name); Comdat(const Comdat &) = delete; // Points to the map in Module. diff --git a/include/llvm/IR/Constant.h b/include/llvm/IR/Constant.h index bb88905aa57a..3c5fe556d50f 100644 --- a/include/llvm/IR/Constant.h +++ b/include/llvm/IR/Constant.h @@ -48,42 +48,41 @@ protected: : User(ty, vty, Ops, NumOps) {} public: - /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. + /// Return true if this is the value that would be returned by getNullValue. bool isNullValue() const; - /// \brief Returns true if the value is one. + /// Returns true if the value is one. bool isOneValue() const; - /// isAllOnesValue - Return true if this is the value that would be returned by + /// Return true if this is the value that would be returned by /// getAllOnesValue. bool isAllOnesValue() const; - /// isNegativeZeroValue - Return true if the value is what would be returned - /// by getZeroValueForNegation. + /// Return true if the value is what would be returned by + /// getZeroValueForNegation. bool isNegativeZeroValue() const; /// Return true if the value is negative zero or null value. bool isZeroValue() const; - /// \brief Return true if the value is not the smallest signed value. + /// Return true if the value is not the smallest signed value. bool isNotMinSignedValue() const; - /// \brief Return true if the value is the smallest signed value. + /// Return true if the value is the smallest signed value. bool isMinSignedValue() const; - /// canTrap - Return true if evaluation of this constant could trap. This is - /// true for things like constant expressions that could divide by zero. + /// Return true if evaluation of this constant could trap. This is true for + /// things like constant expressions that could divide by zero. bool canTrap() const; - /// isThreadDependent - Return true if the value can vary between threads. + /// Return true if the value can vary between threads. bool isThreadDependent() const; /// Return true if the value is dependent on a dllimport variable. bool isDLLImportDependent() const; - /// isConstantUsed - Return true if the constant has users other than constant - /// exprs and other dangling things. + /// Return true if the constant has users other than constant expressions and + /// other dangling things. bool isConstantUsed() const; /// This method classifies the entry according to whether or not it may @@ -93,15 +92,14 @@ public: /// FIXME: This really should not be in IR. bool needsRelocation() const; - /// getAggregateElement - For aggregates (struct/array/vector) return the - /// constant that corresponds to the specified element if possible, or null if - /// not. This can return null if the element index is a ConstantExpr, or if - /// 'this' is a constant expr. + /// For aggregates (struct/array/vector) return the constant that corresponds + /// to the specified element if possible, or null if not. This can return null + /// if the element index is a ConstantExpr, or if 'this' is a constant expr. Constant *getAggregateElement(unsigned Elt) const; Constant *getAggregateElement(Constant *Elt) const; - /// getSplatValue - If this is a splat vector constant, meaning that all of - /// the elements have the same value, return that value. Otherwise return 0. + /// If this is a splat vector constant, meaning that all of the elements have + /// the same value, return that value. Otherwise return 0. Constant *getSplatValue() const; /// If C is a constant integer then return its value, otherwise C must be a @@ -133,7 +131,7 @@ public: /// use Value::replaceAllUsesWith, which automatically dispatches to this /// method as needed. /// - void handleOperandChange(Value *, Value *, Use *); + void handleOperandChange(Value *, Value *); static Constant *getNullValue(Type* Ty); @@ -142,14 +140,14 @@ public: /// @brief Get the all ones value static Constant *getAllOnesValue(Type* Ty); - /// getIntegerValue - Return the value for an integer or pointer constant, - /// or a vector thereof, with the given scalar value. + /// Return the value for an integer or pointer constant, or a vector thereof, + /// with the given scalar value. static Constant *getIntegerValue(Type *Ty, const APInt &V); - /// removeDeadConstantUsers - If there are any dead constant users dangling - /// off of this constant, remove them. This method is useful for clients - /// that want to check to see if a global is unused, but don't want to deal - /// with potentially dead constants hanging off of the globals. + /// If there are any dead constant users dangling off of this constant, remove + /// them. This method is useful for clients that want to check to see if a + /// global is unused, but don't want to deal with potentially dead constants + /// hanging off of the globals. void removeDeadConstantUsers() const; Constant *stripPointerCasts() { diff --git a/include/llvm/IR/ConstantRange.h b/include/llvm/IR/ConstantRange.h index fb596a3bf16e..9458fa9f5c86 100644 --- a/include/llvm/IR/ConstantRange.h +++ b/include/llvm/IR/ConstantRange.h @@ -82,16 +82,42 @@ public: static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other); - /// Return the largest range containing all X such that "X BinOpC C" does not - /// wrap (overflow). + /// Produce the exact range such that all values in the returned range satisfy + /// the given predicate with any value contained within Other. Formally, this + /// returns the exact answer when the superset of 'union over all y in Other + /// is exactly same as the subset of intersection over all y in Other. + /// { x : icmp op x y is true}'. /// - /// Example: + /// Example: Pred = ult and Other = i8 3 returns [0, 3) + static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, + const APInt &Other); + + /// Return the largest range containing all X such that "X BinOpC Y" is + /// guaranteed not to wrap (overflow) for all Y in Other. + /// + /// NB! The returned set does *not* contain **all** possible values of X for + /// which "X BinOpC Y" does not wrap -- some viable values of X may be + /// missing, so you cannot use this to contrain X's range. E.g. in the last + /// example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2), but (-2) + /// is not in the set returned. + /// + /// Examples: /// typedef OverflowingBinaryOperator OBO; - /// makeNoWrapRegion(Add, i8 1, OBO::NoSignedWrap) == [-128, 127) - /// makeNoWrapRegion(Add, i8 1, OBO::NoUnsignedWrap) == [0, -1) - /// makeNoWrapRegion(Add, i8 0, OBO::NoUnsignedWrap) == Full Set - static ConstantRange makeNoWrapRegion(Instruction::BinaryOps BinOp, - const APInt &C, unsigned NoWrapKind); + /// #define MGNR makeGuaranteedNoWrapRegion + /// MGNR(Add, [i8 1, 2), OBO::NoSignedWrap) == [-128, 127) + /// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap) == [0, -1) + /// MGNR(Add, [i8 0, 1), OBO::NoUnsignedWrap) == Full Set + /// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap) + /// == [0,INT_MAX) + /// MGNR(Add, [i8 -1, 6), OBO::NoSignedWrap) == [INT_MIN+1, INT_MAX-4) + static ConstantRange makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, + const ConstantRange &Other, + unsigned NoWrapKind); + + /// Set up \p Pred and \p RHS such that + /// ConstantRange::makeExactICmpRegion(Pred, RHS) == *this. Return true if + /// successful. + bool getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const; /// Return the lower value for this range. /// @@ -245,6 +271,14 @@ public: ConstantRange umax(const ConstantRange &Other) const; /// Return a new range representing the possible values resulting + /// from a signed minimum of a value in this range and a value in \p Other. + ConstantRange smin(const ConstantRange &Other) const; + + /// Return a new range representing the possible values resulting + /// from an unsigned minimum of a value in this range and a value in \p Other. + ConstantRange umin(const ConstantRange &Other) const; + + /// Return a new range representing the possible values resulting /// from an unsigned division of a value in this range and a value in /// \p Other. ConstantRange udiv(const ConstantRange &Other) const; diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index a5a20c9c5701..2a5d14d94646 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -40,26 +40,47 @@ class SequentialType; struct ConstantExprKeyType; template <class ConstantClass> struct ConstantAggrKeyType; +/// Base class for constants with no operands. +/// +/// These constants have no operands; they represent their data directly. +/// Since they can be in use by unrelated modules (and are never based on +/// GlobalValues), it never makes sense to RAUW them. +class ConstantData : public Constant { + void anchor() override; + void *operator new(size_t, unsigned) = delete; + ConstantData() = delete; + ConstantData(const ConstantData &) = delete; + + friend class Constant; + Value *handleOperandChangeImpl(Value *From, Value *To) { + llvm_unreachable("Constant data does not have operands!"); + } + +protected: + explicit ConstantData(Type *Ty, ValueTy VT) : Constant(Ty, VT, nullptr, 0) {} + void *operator new(size_t s) { return User::operator new(s, 0); } + +public: + /// Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return V->getValueID() >= ConstantDataFirstVal && + V->getValueID() <= ConstantDataLastVal; + } +}; + //===----------------------------------------------------------------------===// /// This is the shared class of boolean and integer constants. This class /// represents both boolean and integral constants. /// @brief Class for constant integers. -class ConstantInt : public Constant { +class ConstantInt final : public ConstantData { void anchor() override; - void *operator new(size_t, unsigned) = delete; ConstantInt(const ConstantInt &) = delete; ConstantInt(IntegerType *Ty, const APInt& V); APInt Val; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s, 0); - } public: static ConstantInt *getTrue(LLVMContext &Context); static ConstantInt *getFalse(LLVMContext &Context); @@ -230,34 +251,26 @@ public: //===----------------------------------------------------------------------===// /// ConstantFP - Floating Point Values [float, double] /// -class ConstantFP : public Constant { +class ConstantFP final : public ConstantData { APFloat Val; void anchor() override; - void *operator new(size_t, unsigned) = delete; ConstantFP(const ConstantFP &) = delete; - friend class LLVMContextImpl; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: ConstantFP(Type *Ty, const APFloat& V); -protected: - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s, 0); - } + public: /// Floating point negation must be implemented with f(x) = -0.0 - x. This /// method returns the negative zero constant for floating point or vector /// floating point types; for all other types, it returns the null value. static Constant *getZeroValueForNegation(Type *Ty); - /// get() - This returns a ConstantFP, or a vector containing a splat of a - /// ConstantFP, for the specified value in the specified type. This should - /// only be used for simple constant values like 2.0/1.0 etc, that are - /// known-valid both as host double and as the target format. + /// This returns a ConstantFP, or a vector containing a splat of a ConstantFP, + /// for the specified value in the specified type. This should only be used + /// for simple constant values like 2.0/1.0 etc, that are known-valid both as + /// host double and as the target format. static Constant *get(Type* Ty, double V); static Constant *get(Type* Ty, StringRef Str); static ConstantFP *get(LLVMContext &Context, const APFloat &V); @@ -265,24 +278,24 @@ public: static Constant *getNegativeZero(Type *Ty); static Constant *getInfinity(Type *Ty, bool Negative = false); - /// isValueValidForType - return true if Ty is big enough to represent V. + /// Return true if Ty is big enough to represent V. static bool isValueValidForType(Type *Ty, const APFloat &V); inline const APFloat &getValueAPF() const { return Val; } - /// isZero - Return true if the value is positive or negative zero. + /// Return true if the value is positive or negative zero. bool isZero() const { return Val.isZero(); } - /// isNegative - Return true if the sign bit is set. + /// Return true if the sign bit is set. bool isNegative() const { return Val.isNegative(); } - /// isInfinity - Return true if the value is infinity + /// Return true if the value is infinity bool isInfinity() const { return Val.isInfinity(); } - /// isNaN - Return true if the value is a NaN. + /// Return true if the value is a NaN. bool isNaN() const { return Val.isNaN(); } - /// isExactlyValue - We don't rely on operator== working on double values, as - /// it returns true for things that are clearly not equal, like -0.0 and 0.0. + /// We don't rely on operator== working on double values, as it returns true + /// for things that are clearly not equal, like -0.0 and 0.0. /// As such, this method can be used to do an exact bit-for-bit comparison of /// two floating point values. The version with a double operand is retained /// because it's so convenient to write isExactlyValue(2.0), but please use @@ -302,44 +315,36 @@ public: }; //===----------------------------------------------------------------------===// -/// ConstantAggregateZero - All zero aggregate value +/// All zero aggregate value /// -class ConstantAggregateZero : public Constant { - void *operator new(size_t, unsigned) = delete; +class ConstantAggregateZero final : public ConstantData { ConstantAggregateZero(const ConstantAggregateZero &) = delete; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: - explicit ConstantAggregateZero(Type *ty) - : Constant(ty, ConstantAggregateZeroVal, nullptr, 0) {} -protected: - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s, 0); - } + explicit ConstantAggregateZero(Type *Ty) + : ConstantData(Ty, ConstantAggregateZeroVal) {} + public: static ConstantAggregateZero *get(Type *Ty); - /// getSequentialElement - If this CAZ has array or vector type, return a zero - /// with the right element type. + /// If this CAZ has array or vector type, return a zero with the right element + /// type. Constant *getSequentialElement() const; - /// getStructElement - If this CAZ has struct type, return a zero with the - /// right element type for the specified element. + /// If this CAZ has struct type, return a zero with the right element type for + /// the specified element. Constant *getStructElement(unsigned Elt) const; - /// getElementValue - Return a zero of the right value for the specified GEP - /// index. + /// Return a zero of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). Constant *getElementValue(Constant *C) const; - /// getElementValue - Return a zero of the right value for the specified GEP - /// index. + /// Return a zero of the right value for the specified GEP index. Constant *getElementValue(unsigned Idx) const; - /// \brief Return the number of elements in the array, vector, or struct. + /// Return the number of elements in the array, vector, or struct. unsigned getNumElements() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -349,20 +354,49 @@ public: } }; +/// Base class for aggregate constants (with operands). +/// +/// These constants are aggregates of other constants, which are stored as +/// operands. +/// +/// Subclasses are \a ConstantStruct, \a ConstantArray, and \a +/// ConstantVector. +/// +/// \note Some subclasses of \a ConstantData are semantically aggregates -- +/// such as \a ConstantDataArray -- but are not subclasses of this because they +/// use operands. +class ConstantAggregate : public Constant { +protected: + ConstantAggregate(CompositeType *T, ValueTy VT, ArrayRef<Constant *> V); + +public: + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const Value *V) { + return V->getValueID() >= ConstantAggregateFirstVal && + V->getValueID() <= ConstantAggregateLastVal; + } +}; + +template <> +struct OperandTraits<ConstantAggregate> + : public VariadicOperandTraits<ConstantAggregate> {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantAggregate, Constant) //===----------------------------------------------------------------------===// /// ConstantArray - Constant Array Declarations /// -class ConstantArray : public Constant { +class ConstantArray final : public ConstantAggregate { friend struct ConstantAggrKeyType<ConstantArray>; - ConstantArray(const ConstantArray &) = delete; - friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantArray(ArrayType *T, ArrayRef<Constant *> Val); + public: // ConstantArray accessors static Constant *get(ArrayType *T, ArrayRef<Constant*> V); @@ -371,12 +405,8 @@ private: static Constant *getImpl(ArrayType *T, ArrayRef<Constant *> V); public: - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - - /// getType - Specialize the getType() method to always return an ArrayType, + /// Specialize the getType() method to always return an ArrayType, /// which reduces the amount of casting needed in parts of the compiler. - /// inline ArrayType *getType() const { return cast<ArrayType>(Value::getType()); } @@ -387,34 +417,24 @@ public: } }; -template <> -struct OperandTraits<ConstantArray> : - public VariadicOperandTraits<ConstantArray> { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantArray, Constant) - //===----------------------------------------------------------------------===// -// ConstantStruct - Constant Struct Declarations +// Constant Struct Declarations // -class ConstantStruct : public Constant { +class ConstantStruct final : public ConstantAggregate { friend struct ConstantAggrKeyType<ConstantStruct>; - ConstantStruct(const ConstantStruct &) = delete; - friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantStruct(StructType *T, ArrayRef<Constant *> Val); + public: // ConstantStruct accessors static Constant *get(StructType *T, ArrayRef<Constant*> V); static Constant *get(StructType *T, ...) LLVM_END_WITH_NULL; - /// getAnon - Return an anonymous struct that has the specified - /// elements. If the struct is possibly empty, then you must specify a - /// context. + /// Return an anonymous struct that has the specified elements. + /// If the struct is possibly empty, then you must specify a context. static Constant *getAnon(ArrayRef<Constant*> V, bool Packed = false) { return get(getTypeForElements(V, Packed), V); } @@ -423,20 +443,16 @@ public: return get(getTypeForElements(Ctx, V, Packed), V); } - /// getTypeForElements - Return an anonymous struct type to use for a constant - /// with the specified set of elements. The list must not be empty. + /// Return an anonymous struct type to use for a constant with the specified + /// set of elements. The list must not be empty. static StructType *getTypeForElements(ArrayRef<Constant*> V, bool Packed = false); - /// getTypeForElements - This version of the method allows an empty list. + /// This version of the method allows an empty list. static StructType *getTypeForElements(LLVMContext &Ctx, ArrayRef<Constant*> V, bool Packed = false); - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - - /// getType() specialization - Reduce amount of casting... - /// + /// Specialization - reduce amount of casting. inline StructType *getType() const { return cast<StructType>(Value::getType()); } @@ -447,27 +463,18 @@ public: } }; -template <> -struct OperandTraits<ConstantStruct> : - public VariadicOperandTraits<ConstantStruct> { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantStruct, Constant) - //===----------------------------------------------------------------------===// -/// ConstantVector - Constant Vector Declarations +/// Constant Vector Declarations /// -class ConstantVector : public Constant { +class ConstantVector final : public ConstantAggregate { friend struct ConstantAggrKeyType<ConstantVector>; - ConstantVector(const ConstantVector &) = delete; - friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantVector(VectorType *T, ArrayRef<Constant *> Val); + public: // ConstantVector accessors static Constant *get(ArrayRef<Constant*> V); @@ -476,22 +483,17 @@ private: static Constant *getImpl(ArrayRef<Constant *> V); public: - /// getSplat - Return a ConstantVector with the specified constant in each - /// element. + /// Return a ConstantVector with the specified constant in each element. static Constant *getSplat(unsigned NumElts, Constant *Elt); - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - - /// getType - Specialize the getType() method to always return a VectorType, + /// Specialize the getType() method to always return a VectorType, /// which reduces the amount of casting needed in parts of the compiler. - /// inline VectorType *getType() const { return cast<VectorType>(Value::getType()); } - /// getSplatValue - If this is a splat constant, meaning that all of the - /// elements have the same value, return that value. Otherwise return NULL. + /// If this is a splat constant, meaning that all of the elements have the + /// same value, return that value. Otherwise return NULL. Constant *getSplatValue() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -500,41 +502,24 @@ public: } }; -template <> -struct OperandTraits<ConstantVector> : - public VariadicOperandTraits<ConstantVector> { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantVector, Constant) - //===----------------------------------------------------------------------===// -/// ConstantPointerNull - a constant pointer value that points to null +/// A constant pointer value that points to null /// -class ConstantPointerNull : public Constant { - void *operator new(size_t, unsigned) = delete; +class ConstantPointerNull final : public ConstantData { ConstantPointerNull(const ConstantPointerNull &) = delete; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: explicit ConstantPointerNull(PointerType *T) - : Constant(T, - Value::ConstantPointerNullVal, nullptr, 0) {} + : ConstantData(T, Value::ConstantPointerNullVal) {} -protected: - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s, 0); - } public: - /// get() - Static factory methods - Return objects of the specified value + /// Static factory methods - Return objects of the specified value static ConstantPointerNull *get(PointerType *T); - /// getType - Specialize the getType() method to always return an PointerType, + /// Specialize the getType() method to always return an PointerType, /// which reduces the amount of casting needed in parts of the compiler. - /// inline PointerType *getType() const { return cast<PointerType>(Value::getType()); } @@ -554,116 +539,101 @@ public: /// /// This is the common base class of ConstantDataArray and ConstantDataVector. /// -class ConstantDataSequential : public Constant { +class ConstantDataSequential : public ConstantData { friend class LLVMContextImpl; - /// DataElements - A pointer to the bytes underlying this constant (which is - /// owned by the uniquing StringMap). + /// A pointer to the bytes underlying this constant (which is owned by the + /// uniquing StringMap). const char *DataElements; - /// Next - This forms a link list of ConstantDataSequential nodes that have + /// This forms a link list of ConstantDataSequential nodes that have /// the same value but different type. For example, 0,0,0,1 could be a 4 /// element array of i8, or a 1-element array of i32. They'll both end up in /// the same StringMap bucket, linked up. ConstantDataSequential *Next; - void *operator new(size_t, unsigned) = delete; ConstantDataSequential(const ConstantDataSequential &) = delete; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); protected: explicit ConstantDataSequential(Type *ty, ValueTy VT, const char *Data) - : Constant(ty, VT, nullptr, 0), DataElements(Data), Next(nullptr) {} + : ConstantData(ty, VT), DataElements(Data), Next(nullptr) {} ~ConstantDataSequential() override { delete Next; } static Constant *getImpl(StringRef Bytes, Type *Ty); -protected: - // allocate space for exactly zero operands. - void *operator new(size_t s) { - return User::operator new(s, 0); - } public: - - /// isElementTypeCompatible - Return true if a ConstantDataSequential can be - /// formed with a vector or array of the specified element type. + /// Return true if a ConstantDataSequential can be formed with a vector or + /// array of the specified element type. /// ConstantDataArray only works with normal float and int types that are /// stored densely in memory, not with things like i42 or x86_f80. static bool isElementTypeCompatible(Type *Ty); - /// getElementAsInteger - If this is a sequential container of integers (of - /// any size), return the specified element in the low bits of a uint64_t. + /// If this is a sequential container of integers (of any size), return the + /// specified element in the low bits of a uint64_t. uint64_t getElementAsInteger(unsigned i) const; - /// getElementAsAPFloat - If this is a sequential container of floating point - /// type, return the specified element as an APFloat. + /// If this is a sequential container of floating point type, return the + /// specified element as an APFloat. APFloat getElementAsAPFloat(unsigned i) const; - /// getElementAsFloat - If this is an sequential container of floats, return - /// the specified element as a float. + /// If this is an sequential container of floats, return the specified element + /// as a float. float getElementAsFloat(unsigned i) const; - /// getElementAsDouble - If this is an sequential container of doubles, return - /// the specified element as a double. + /// If this is an sequential container of doubles, return the specified + /// element as a double. double getElementAsDouble(unsigned i) const; - /// getElementAsConstant - Return a Constant for a specified index's element. + /// Return a Constant for a specified index's element. /// Note that this has to compute a new constant to return, so it isn't as /// efficient as getElementAsInteger/Float/Double. Constant *getElementAsConstant(unsigned i) const; - /// getType - Specialize the getType() method to always return a - /// SequentialType, which reduces the amount of casting needed in parts of the - /// compiler. + /// Specialize the getType() method to always return a SequentialType, which + /// reduces the amount of casting needed in parts of the compiler. inline SequentialType *getType() const { return cast<SequentialType>(Value::getType()); } - /// getElementType - Return the element type of the array/vector. + /// Return the element type of the array/vector. Type *getElementType() const; - /// getNumElements - Return the number of elements in the array or vector. + /// Return the number of elements in the array or vector. unsigned getNumElements() const; - /// getElementByteSize - Return the size (in bytes) of each element in the - /// array/vector. The size of the elements is known to be a multiple of one - /// byte. + /// Return the size (in bytes) of each element in the array/vector. + /// The size of the elements is known to be a multiple of one byte. uint64_t getElementByteSize() const; - - /// isString - This method returns true if this is an array of i8. + /// This method returns true if this is an array of i8. bool isString() const; - /// isCString - This method returns true if the array "isString", ends with a - /// nul byte, and does not contains any other nul bytes. + /// This method returns true if the array "isString", ends with a null byte, + /// and does not contains any other null bytes. bool isCString() const; - /// getAsString - If this array is isString(), then this method returns the - /// array as a StringRef. Otherwise, it asserts out. - /// + /// If this array is isString(), then this method returns the array as a + /// StringRef. Otherwise, it asserts out. StringRef getAsString() const { assert(isString() && "Not a string"); return getRawDataValues(); } - /// getAsCString - If this array is isCString(), then this method returns the - /// array (without the trailing null byte) as a StringRef. Otherwise, it - /// asserts out. - /// + /// If this array is isCString(), then this method returns the array (without + /// the trailing null byte) as a StringRef. Otherwise, it asserts out. StringRef getAsCString() const { assert(isCString() && "Isn't a C string"); StringRef Str = getAsString(); return Str.substr(0, Str.size()-1); } - /// getRawDataValues - Return the raw, underlying, bytes of this data. Note - /// that this is an extremely tricky thing to work with, as it exposes the - /// host endianness of the data elements. + /// Return the raw, underlying, bytes of this data. Note that this is an + /// extremely tricky thing to work with, as it exposes the host endianness of + /// the data elements. StringRef getRawDataValues() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: - /// static bool classof(const Value *V) { return V->getValueID() == ConstantDataArrayVal || V->getValueID() == ConstantDataVectorVal; @@ -673,25 +643,24 @@ private: }; //===----------------------------------------------------------------------===// -/// ConstantDataArray - An array constant whose element type is a simple -/// 1/2/4/8-byte integer or float/double, and whose elements are just simple -/// data values (i.e. ConstantInt/ConstantFP). This Constant node has no -/// operands because it stores all of the elements of the constant as densely -/// packed data, instead of as Value*'s. -class ConstantDataArray : public ConstantDataSequential { +/// An array constant whose element type is a simple 1/2/4/8-byte integer or +/// float/double, and whose elements are just simple data values +/// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it +/// stores all of the elements of the constant as densely packed data, instead +/// of as Value*'s. +class ConstantDataArray final : public ConstantDataSequential { void *operator new(size_t, unsigned) = delete; ConstantDataArray(const ConstantDataArray &) = delete; void anchor() override; friend class ConstantDataSequential; explicit ConstantDataArray(Type *ty, const char *Data) - : ConstantDataSequential(ty, ConstantDataArrayVal, Data) {} -protected: - // allocate space for exactly zero operands. + : ConstantDataSequential(ty, ConstantDataArrayVal, Data) {} + /// Allocate space for exactly zero operands. void *operator new(size_t s) { return User::operator new(s, 0); } -public: +public: /// get() constructors - Return a constant with array type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -711,48 +680,45 @@ public: static Constant *getFP(LLVMContext &Context, ArrayRef<uint32_t> Elts); static Constant *getFP(LLVMContext &Context, ArrayRef<uint64_t> Elts); - /// getString - This method constructs a CDS and initializes it with a text - /// string. The default behavior (AddNull==true) causes a null terminator to + /// This method constructs a CDS and initializes it with a text string. + /// The default behavior (AddNull==true) causes a null terminator to /// be placed at the end of the array (increasing the length of the string by /// one more than the StringRef would normally indicate. Pass AddNull=false /// to disable this behavior. static Constant *getString(LLVMContext &Context, StringRef Initializer, bool AddNull = true); - /// getType - Specialize the getType() method to always return an ArrayType, + /// Specialize the getType() method to always return an ArrayType, /// which reduces the amount of casting needed in parts of the compiler. - /// inline ArrayType *getType() const { return cast<ArrayType>(Value::getType()); } /// Methods for support type inquiry through isa, cast, and dyn_cast: - /// static bool classof(const Value *V) { return V->getValueID() == ConstantDataArrayVal; } }; //===----------------------------------------------------------------------===// -/// ConstantDataVector - A vector constant whose element type is a simple -/// 1/2/4/8-byte integer or float/double, and whose elements are just simple -/// data values (i.e. ConstantInt/ConstantFP). This Constant node has no -/// operands because it stores all of the elements of the constant as densely -/// packed data, instead of as Value*'s. -class ConstantDataVector : public ConstantDataSequential { +/// A vector constant whose element type is a simple 1/2/4/8-byte integer or +/// float/double, and whose elements are just simple data values +/// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it +/// stores all of the elements of the constant as densely packed data, instead +/// of as Value*'s. +class ConstantDataVector final : public ConstantDataSequential { void *operator new(size_t, unsigned) = delete; ConstantDataVector(const ConstantDataVector &) = delete; void anchor() override; friend class ConstantDataSequential; explicit ConstantDataVector(Type *ty, const char *Data) - : ConstantDataSequential(ty, ConstantDataVectorVal, Data) {} -protected: + : ConstantDataSequential(ty, ConstantDataVectorVal, Data) {} // allocate space for exactly zero operands. void *operator new(size_t s) { return User::operator new(s, 0); } -public: +public: /// get() constructors - Return a constant with vector type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -772,45 +738,38 @@ public: static Constant *getFP(LLVMContext &Context, ArrayRef<uint32_t> Elts); static Constant *getFP(LLVMContext &Context, ArrayRef<uint64_t> Elts); - /// getSplat - Return a ConstantVector with the specified constant in each - /// element. The specified constant has to be a of a compatible type (i8/i16/ + /// Return a ConstantVector with the specified constant in each element. + /// The specified constant has to be a of a compatible type (i8/i16/ /// i32/i64/float/double) and must be a ConstantFP or ConstantInt. static Constant *getSplat(unsigned NumElts, Constant *Elt); - /// getSplatValue - If this is a splat constant, meaning that all of the - /// elements have the same value, return that value. Otherwise return NULL. + /// If this is a splat constant, meaning that all of the elements have the + /// same value, return that value. Otherwise return NULL. Constant *getSplatValue() const; - /// getType - Specialize the getType() method to always return a VectorType, + /// Specialize the getType() method to always return a VectorType, /// which reduces the amount of casting needed in parts of the compiler. - /// inline VectorType *getType() const { return cast<VectorType>(Value::getType()); } /// Methods for support type inquiry through isa, cast, and dyn_cast: - /// static bool classof(const Value *V) { return V->getValueID() == ConstantDataVectorVal; } }; //===----------------------------------------------------------------------===// -/// ConstantTokenNone - a constant token which is empty +/// A constant token which is empty /// -class ConstantTokenNone : public Constant { - void *operator new(size_t, unsigned) = delete; +class ConstantTokenNone final : public ConstantData { ConstantTokenNone(const ConstantTokenNone &) = delete; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: explicit ConstantTokenNone(LLVMContext &Context) - : Constant(Type::getTokenTy(Context), ConstantTokenNoneVal, nullptr, 0) {} - // allocate space for exactly zero operands - void *operator new(size_t s) { return User::operator new(s, 0); } + : ConstantData(Type::getTokenTy(Context), ConstantTokenNoneVal) {} public: /// Return the ConstantTokenNone. @@ -822,27 +781,26 @@ public: } }; -/// BlockAddress - The address of a basic block. +/// The address of a basic block. /// -class BlockAddress : public Constant { +class BlockAddress final : public Constant { void *operator new(size_t, unsigned) = delete; void *operator new(size_t s) { return User::operator new(s, 2); } BlockAddress(Function *F, BasicBlock *BB); friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); public: - /// get - Return a BlockAddress for the specified function and basic block. + /// Return a BlockAddress for the specified function and basic block. static BlockAddress *get(Function *F, BasicBlock *BB); - /// get - Return a BlockAddress for the specified basic block. The basic + /// Return a BlockAddress for the specified basic block. The basic /// block must be embedded into a function. static BlockAddress *get(BasicBlock *BB); - /// \brief Lookup an existing \c BlockAddress constant for the given - /// BasicBlock. + /// Lookup an existing \c BlockAddress constant for the given BasicBlock. /// /// \returns 0 if \c !BB->hasAddressTaken(), otherwise the \c BlockAddress. static BlockAddress *lookup(const BasicBlock *BB); @@ -868,7 +826,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BlockAddress, Value) //===----------------------------------------------------------------------===// -/// ConstantExpr - a constant value that is initialized with an expression using +/// A constant value that is initialized with an expression using /// other constant values. /// /// This class uses the standard Instruction opcodes to define the various @@ -879,11 +837,11 @@ class ConstantExpr : public Constant { friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); protected: ConstantExpr(Type *ty, unsigned Opcode, Use *Ops, unsigned NumOps) - : Constant(ty, ConstantExprVal, Ops, NumOps) { + : Constant(ty, ConstantExprVal, Ops, NumOps) { // Operation type (an Instruction opcode) is stored as the SubclassData. setValueSubclassData(Opcode); } @@ -998,12 +956,12 @@ public: return getLShr(C1, C2, true); } - /// getBinOpIdentity - Return the identity for the given binary operation, + /// Return the identity for the given binary operation, /// i.e. a constant C such that X op C = X and C op X = X for every X. It /// returns null if the operator doesn't have an identity. static Constant *getBinOpIdentity(unsigned Opcode, Type *Ty); - /// getBinOpAbsorber - Return the absorbing element for the given binary + /// Return the absorbing element for the given binary /// operation, i.e. a constant C such that X op C = C and C op X = C for /// every X. For example, this returns zero for integer multiplication. /// It returns null if the operator doesn't have an absorbing element. @@ -1165,32 +1123,32 @@ public: ArrayRef<unsigned> Idxs, Type *OnlyIfReducedTy = nullptr); - /// getOpcode - Return the opcode at the root of this constant expression + /// Return the opcode at the root of this constant expression unsigned getOpcode() const { return getSubclassDataFromValue(); } - /// getPredicate - Return the ICMP or FCMP predicate value. Assert if this is - /// not an ICMP or FCMP constant expression. + /// Return the ICMP or FCMP predicate value. Assert if this is not an ICMP or + /// FCMP constant expression. unsigned getPredicate() const; - /// getIndices - Assert that this is an insertvalue or exactvalue + /// Assert that this is an insertvalue or exactvalue /// expression and return the list of indices. ArrayRef<unsigned> getIndices() const; - /// getOpcodeName - Return a string representation for an opcode. + /// Return a string representation for an opcode. const char *getOpcodeName() const; - /// getWithOperandReplaced - Return a constant expression identical to this - /// one, but with the specified operand set to the specified value. + /// Return a constant expression identical to this one, but with the specified + /// operand set to the specified value. Constant *getWithOperandReplaced(unsigned OpNo, Constant *Op) const; - /// getWithOperands - This returns the current constant expression with the - /// operands replaced with the specified values. The specified array must - /// have the same number of operands as our current one. + /// This returns the current constant expression with the operands replaced + /// with the specified values. The specified array must have the same number + /// of operands as our current one. Constant *getWithOperands(ArrayRef<Constant*> Ops) const { return getWithOperands(Ops, getType()); } - /// \brief Get the current expression with the operands replaced. + /// Get the current expression with the operands replaced. /// /// Return the current constant expression with the operands replaced with \c /// Ops and the type with \c Ty. The new operands must have the same number @@ -1203,9 +1161,8 @@ public: bool OnlyIfReduced = false, Type *SrcTy = nullptr) const; - /// getAsInstruction - Returns an Instruction which implements the same - /// operation as this ConstantExpr. The instruction is not linked to any basic - /// block. + /// Returns an Instruction which implements the same operation as this + /// ConstantExpr. The instruction is not linked to any basic block. /// /// A better approach to this could be to have a constructor for Instruction /// which would take a ConstantExpr parameter, but that would have spread @@ -1234,7 +1191,7 @@ struct OperandTraits<ConstantExpr> : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantExpr, Constant) //===----------------------------------------------------------------------===// -/// UndefValue - 'undef' values are things that do not have specified contents. +/// 'undef' values are things that do not have specified contents. /// These are used for a variety of purposes, including global variable /// initializers and operands to instructions. 'undef' values can occur with /// any first-class type. @@ -1243,44 +1200,34 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantExpr, Constant) /// can appear to have different bit patterns at each use. See /// LangRef.html#undefvalues for details. /// -class UndefValue : public Constant { - void *operator new(size_t, unsigned) = delete; +class UndefValue final : public ConstantData { UndefValue(const UndefValue &) = delete; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); -protected: - explicit UndefValue(Type *T) : Constant(T, UndefValueVal, nullptr, 0) {} -protected: - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s, 0); - } + explicit UndefValue(Type *T) : ConstantData(T, UndefValueVal) {} + public: - /// get() - Static factory methods - Return an 'undef' object of the specified - /// type. - /// + /// Static factory methods - Return an 'undef' object of the specified type. static UndefValue *get(Type *T); - /// getSequentialElement - If this Undef has array or vector type, return a - /// undef with the right element type. + /// If this Undef has array or vector type, return a undef with the right + /// element type. UndefValue *getSequentialElement() const; - /// getStructElement - If this undef has struct type, return a undef with the - /// right element type for the specified element. + /// If this undef has struct type, return a undef with the right element type + /// for the specified element. UndefValue *getStructElement(unsigned Elt) const; - /// getElementValue - Return an undef of the right value for the specified GEP - /// index. + /// Return an undef of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). UndefValue *getElementValue(Constant *C) const; - /// getElementValue - Return an undef of the right value for the specified GEP - /// index. + /// Return an undef of the right value for the specified GEP index. UndefValue *getElementValue(unsigned Idx) const; - /// \brief Return the number of elements in the array, vector, or struct. + /// Return the number of elements in the array, vector, or struct. unsigned getNumElements() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h index aeec39541154..0f2f67f5feaf 100644 --- a/include/llvm/IR/DIBuilder.h +++ b/include/llvm/IR/DIBuilder.h @@ -15,8 +15,6 @@ #ifndef LLVM_IR_DIBUILDER_H #define LLVM_IR_DIBUILDER_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/ValueHandle.h" @@ -31,6 +29,7 @@ namespace llvm { class Constant; class LLVMContext; class StringRef; + template <typename T> class ArrayRef; class DIBuilder { Module &M; @@ -52,7 +51,11 @@ namespace llvm { bool AllowUnresolvedNodes; /// Each subprogram's preserved local variables. - DenseMap<MDNode *, std::vector<TrackingMDNodeRef>> PreservedVariables; + /// + /// Do not use a std::vector. Some versions of libc++ apparently copy + /// instead of move on grow operations, and TrackingMDRef is expensive to + /// copy. + DenseMap<MDNode *, SmallVector<TrackingMDNodeRef, 1>> PreservedVariables; DIBuilder(const DIBuilder &) = delete; void operator=(const DIBuilder &) = delete; @@ -68,7 +71,6 @@ namespace llvm { /// If \c AllowUnresolved, collect unresolved nodes attached to the module /// in order to resolve cycles during \a finalize(). explicit DIBuilder(Module &M, bool AllowUnresolved = true); - enum DebugEmissionKind { FullDebug=1, LineTablesOnly }; /// Construct any deferred debug info descriptors. void finalize(); @@ -93,22 +95,13 @@ 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 EmitDebugInfo A boolean flag which indicates whether - /// debug information should be written to - /// the final output or not. When this is - /// false, debug information annotations will - /// be present in the IL but they are not - /// written to the final assembly or object - /// file. This supports tracking source - /// location information in the back end - /// without actually changing the output - /// (e.g., when using optimization remarks). DICompileUnit * createCompileUnit(unsigned Lang, StringRef File, StringRef Dir, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), - DebugEmissionKind Kind = FullDebug, uint64_t DWOId = 0, - bool EmitDebugInfo = true); + DICompileUnit::DebugEmissionKind Kind = + DICompileUnit::DebugEmissionKind::FullDebug, + uint64_t DWOId = 0); /// Create a file descriptor to hold debugging information /// for a file. @@ -154,7 +147,8 @@ namespace llvm { /// \param Class Type for which this pointer points to members of. DIDerivedType *createMemberPointerType(DIType *PointeeTy, DIType *Class, uint64_t SizeInBits, - uint64_t AlignInBits = 0); + uint64_t AlignInBits = 0, + unsigned Flags = 0); /// Create debugging information entry for a c++ /// style reference or rvalue reference type. @@ -200,6 +194,22 @@ namespace llvm { uint64_t OffsetInBits, unsigned Flags, DIType *Ty); + /// Create debugging information entry for a bit field member. + /// \param Scope Member scope. + /// \param Name Member name. + /// \param File File where this member is defined. + /// \param LineNo Line number. + /// \param SizeInBits Member size. + /// \param AlignInBits Member alignment. + /// \param OffsetInBits Member offset. + /// \param StorageOffsetInBits Member storage offset. + /// \param Flags Flags to encode member attribute. + /// \param Ty Parent type. + DIDerivedType *createBitFieldMemberType( + DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, + uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, + uint64_t StorageOffsetInBits, unsigned Flags, DIType *Ty); + /// Create debugging information entry for a /// C++ static data member. /// \param Scope Member scope. @@ -381,8 +391,9 @@ namespace llvm { /// includes return type at 0th index. /// \param Flags E.g.: LValueReference. /// These flags are used to emit dwarf attributes. + /// \param CC Calling convention, e.g. dwarf::DW_CC_normal DISubroutineType *createSubroutineType(DITypeRefArray ParameterTypes, - unsigned Flags = 0); + unsigned Flags = 0, unsigned CC = 0); /// Create an external type reference. /// \param Tag Dwarf TAG. @@ -413,9 +424,9 @@ namespace llvm { uint64_t AlignInBits = 0, unsigned Flags = DINode::FlagFwdDecl, StringRef UniqueIdentifier = ""); - /// Retain DIType* in a module even if it is not referenced + /// Retain DIScope* in a module even if it is not referenced /// through debug info anchors. - void retainType(DIType *T); + void retainType(DIScope *T); /// Create unspecified parameter type /// for a subroutine type. @@ -535,17 +546,6 @@ namespace llvm { bool isOptimized = false, DITemplateParameterArray TParams = nullptr, DISubprogram *Decl = nullptr); - /// FIXME: this is added for dragonegg. Once we update dragonegg - /// to call resolve function, this will be removed. - DISubprogram *createFunction(DIScopeRef Scope, StringRef Name, - StringRef LinkageName, DIFile *File, - unsigned LineNo, DISubroutineType *Ty, - bool isLocalToUnit, bool isDefinition, - unsigned ScopeLine, unsigned Flags = 0, - bool isOptimized = false, - DITemplateParameterArray TParams = nullptr, - DISubprogram *Decl = nullptr); - /// Create a new descriptor for the specified C++ method. /// See comments in \a DISubprogram* for descriptions of these fields. /// \param Scope Function scope. @@ -558,7 +558,11 @@ namespace llvm { /// \param isDefinition True if this is a function definition. /// \param Virtuality Attributes describing virtualness. e.g. pure /// virtual function. - /// \param VTableIndex Index no of this method in virtual table. + /// \param VTableIndex Index no of this method in virtual table, or -1u if + /// unrepresentable. + /// \param ThisAdjustment + /// MS ABI-specific adjustment of 'this' that occurs + /// in the prologue. /// \param VTableHolder Type that holds vtable. /// \param Flags e.g. is this function prototyped or not. /// This flags are used to emit dwarf attributes. @@ -568,8 +572,9 @@ namespace llvm { createMethod(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit, bool isDefinition, unsigned Virtuality = 0, - unsigned VTableIndex = 0, DIType *VTableHolder = nullptr, - unsigned Flags = 0, bool isOptimized = false, + unsigned VTableIndex = 0, int ThisAdjustment = 0, + DIType *VTableHolder = nullptr, unsigned Flags = 0, + bool isOptimized = false, DITemplateParameterArray TParams = nullptr); /// This creates new descriptor for a namespace with the specified diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index 19a3a6661feb..173121b72ffd 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -20,7 +20,6 @@ #ifndef LLVM_IR_DATALAYOUT_H #define LLVM_IR_DATALAYOUT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" @@ -34,8 +33,6 @@ typedef struct LLVMOpaqueTargetData *LLVMTargetDataRef; namespace llvm { class Value; -class Type; -class IntegerType; class StructType; class StructLayout; class Triple; @@ -236,14 +233,14 @@ public: /// on any known one. This returns false if the integer width is not legal. /// /// The width is specified in bits. - bool isLegalInteger(unsigned Width) const { + bool isLegalInteger(uint64_t Width) const { for (unsigned LegalIntWidth : LegalIntWidths) if (LegalIntWidth == Width) return true; return false; } - bool isIllegalInteger(unsigned Width) const { return !isLegalInteger(Width); } + bool isIllegalInteger(uint64_t Width) const { return !isLegalInteger(Width); } /// Returns true if the given alignment exceeds the natural stack alignment. bool exceedsNaturalStackAlignment(unsigned Align) const { @@ -387,7 +384,7 @@ public: /// returns 12 or 16 for x86_fp80, depending on alignment. uint64_t getTypeAllocSize(Type *Ty) const { // Round up to the next alignment boundary. - return RoundUpToAlignment(getTypeStoreSize(Ty), getABITypeAlignment(Ty)); + return alignTo(getTypeStoreSize(Ty), getABITypeAlignment(Ty)); } /// \brief Returns the offset in bits between successive objects of the @@ -430,19 +427,20 @@ public: /// \brief Returns the largest legal integer type, or null if none are set. Type *getLargestLegalIntType(LLVMContext &C) const { - unsigned LargestSize = getLargestLegalIntTypeSize(); + unsigned LargestSize = getLargestLegalIntTypeSizeInBits(); return (LargestSize == 0) ? nullptr : Type::getIntNTy(C, LargestSize); } /// \brief Returns the size of largest legal integer type size, or 0 if none /// are set. - unsigned getLargestLegalIntTypeSize() const; + unsigned getLargestLegalIntTypeSizeInBits() const; /// \brief Returns the offset from the beginning of the type for the specified /// indices. /// + /// Note that this takes the element type, not the pointer type. /// This is used to implement getelementptr. - uint64_t getIndexedOffset(Type *Ty, ArrayRef<Value *> Indices) const; + int64_t getIndexedOffsetInType(Type *ElemTy, ArrayRef<Value *> Indices) const; /// \brief Returns a StructLayout object, indicating the alignment of the /// struct, its size, and the offsets of its fields. @@ -475,7 +473,7 @@ inline LLVMTargetDataRef wrap(const DataLayout *P) { class StructLayout { uint64_t StructSize; unsigned StructAlignment; - bool IsPadded : 1; + unsigned IsPadded : 1; unsigned NumElements : 31; uint64_t MemberOffsets[1]; // variable sized array! public: diff --git a/include/llvm/IR/DebugInfo.h b/include/llvm/IR/DebugInfo.h index 4caceacbb58e..972042432b7b 100644 --- a/include/llvm/IR/DebugInfo.h +++ b/include/llvm/IR/DebugInfo.h @@ -17,10 +17,8 @@ #ifndef LLVM_IR_DEBUGINFO_H #define LLVM_IR_DEBUGINFO_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Casting.h" @@ -32,21 +30,12 @@ namespace llvm { class Module; class DbgDeclareInst; class DbgValueInst; - -/// \brief Maps from type identifier to the actual MDNode. -typedef DenseMap<const MDString *, DIType *> DITypeIdentifierMap; +template <typename K, typename V, typename KeyInfoT, typename BucketT> +class DenseMap; /// \brief Find subprogram that is enclosing this scope. DISubprogram *getDISubprogram(const MDNode *Scope); -/// \brief Find debug info for a given function. -/// -/// \returns a valid subprogram, if found. Otherwise, return \c nullptr. -DISubprogram *getDISubprogram(const Function *F); - -/// \brief Generate map by visiting all retained types. -DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes); - /// \brief Strip debug info in the module if it exists. /// /// To do this, we remove all calls to the debugger intrinsics and any named @@ -68,8 +57,6 @@ unsigned getDebugMetadataVersionFromModule(const Module &M); /// used by the CUs. class DebugInfoFinder { public: - DebugInfoFinder() : TypeMapInitialized(false) {} - /// \brief Process entire module and collect debug info anchors. void processModule(const Module &M); @@ -136,11 +123,7 @@ private: SmallVector<DIGlobalVariable *, 8> GVs; SmallVector<DIType *, 8> TYs; SmallVector<DIScope *, 8> Scopes; - SmallPtrSet<const MDNode *, 64> NodesSeen; - DITypeIdentifierMap TypeIdentifierMap; - - /// \brief Specify if TypeIdentifierMap is initialized. - bool TypeMapInitialized; + SmallPtrSet<const MDNode *, 32> NodesSeen; }; } // end namespace llvm diff --git a/include/llvm/IR/DebugInfoFlags.def b/include/llvm/IR/DebugInfoFlags.def index 9756c12264b4..26238c349e7e 100644 --- a/include/llvm/IR/DebugInfoFlags.def +++ b/include/llvm/IR/DebugInfoFlags.def @@ -33,5 +33,10 @@ HANDLE_DI_FLAG((1 << 12), StaticMember) HANDLE_DI_FLAG((1 << 13), LValueReference) HANDLE_DI_FLAG((1 << 14), RValueReference) HANDLE_DI_FLAG((1 << 15), ExternalTypeRef) +HANDLE_DI_FLAG((1 << 16), SingleInheritance) +HANDLE_DI_FLAG((2 << 16), MultipleInheritance) +HANDLE_DI_FLAG((3 << 16), VirtualInheritance) +HANDLE_DI_FLAG((1 << 18), IntroducedVirtual) +HANDLE_DI_FLAG((1 << 19), BitField) #undef HANDLE_DI_FLAG diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 456313a70e83..853a94afd9d9 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -43,21 +43,25 @@ namespace llvm { -/// \brief Pointer union between a subclass of DINode and MDString. +template <typename T> class Optional; + +/// Holds a subclass of DINode. /// -/// \a DICompositeType can be referenced via an \a MDString unique identifier. -/// This class allows some type safety in the face of that, requiring either a -/// node of a particular type or an \a MDString. +/// FIXME: This class doesn't currently make much sense. Previously it was a +/// union beteen MDString (for ODR-uniqued types) and things like DIType. To +/// support CodeView work, it wasn't deleted outright when MDString-based type +/// references were deleted; we'll soon need a similar concept for CodeView +/// DITypeIndex. template <class T> class TypedDINodeRef { const Metadata *MD = nullptr; public: TypedDINodeRef() = default; TypedDINodeRef(std::nullptr_t) {} + TypedDINodeRef(const T *MD) : MD(MD) {} - /// \brief Construct from a raw pointer. explicit TypedDINodeRef(const Metadata *MD) : MD(MD) { - assert((!MD || isa<MDString>(MD) || isa<T>(MD)) && "Expected valid ref"); + assert((!MD || isa<T>(MD)) && "Expected valid type ref"); } template <class U> @@ -69,26 +73,10 @@ public: operator Metadata *() const { return const_cast<Metadata *>(MD); } + T *resolve() const { return const_cast<T *>(cast_or_null<T>(MD)); } + bool operator==(const TypedDINodeRef<T> &X) const { return MD == X.MD; } bool operator!=(const TypedDINodeRef<T> &X) const { return MD != X.MD; } - - /// \brief Create a reference. - /// - /// Get a reference to \c N, using an \a MDString reference if available. - static TypedDINodeRef get(const T *N); - - template <class MapTy> T *resolve(const MapTy &Map) const { - if (!MD) - return nullptr; - - if (auto *Typed = dyn_cast<T>(MD)) - return const_cast<T *>(Typed); - - auto *S = cast<MDString>(MD); - auto I = Map.find(S); - assert(I != Map.end() && "Missing identifier in type map"); - return cast<T>(I->second); - } }; typedef TypedDINodeRef<DINode> DINodeRef; @@ -173,6 +161,9 @@ protected: return MDString::get(Context, S); } + /// Allow subclasses to mutate the tag. + void setTag(unsigned Tag) { SubclassData16 = Tag; } + public: unsigned getTag() const { return SubclassData16; } @@ -183,7 +174,9 @@ public: enum DIFlags { #define HANDLE_DI_FLAG(ID, NAME) Flag##NAME = ID, #include "llvm/IR/DebugInfoFlags.def" - FlagAccessibility = FlagPrivate | FlagProtected | FlagPublic + FlagAccessibility = FlagPrivate | FlagProtected | FlagPublic, + FlagPtrToMemberRep = FlagSingleInheritance | FlagMultipleInheritance | + FlagVirtualInheritance, }; static unsigned getFlag(StringRef Flag); @@ -196,8 +189,6 @@ public: static unsigned splitFlags(unsigned Flags, SmallVectorImpl<unsigned> &SplitFlags); - DINodeRef getRef() const { return DINodeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -291,6 +282,7 @@ public: unsigned getTag() const { return SubclassData16; } StringRef getHeader() const { return getStringOperand(0); } + MDString *getRawHeader() const { return getOperandAs<MDString>(0); } op_iterator dwarf_op_begin() const { return op_begin() + 1; } op_iterator dwarf_op_end() const { return op_end(); } @@ -431,8 +423,6 @@ public: : static_cast<Metadata *>(getOperand(0)); } - DIScopeRef getRef() const { return DIScopeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -527,11 +517,28 @@ protected: DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, ArrayRef<Metadata *> Ops) - : DIScope(C, ID, Storage, Tag, Ops), Line(Line), Flags(Flags), - SizeInBits(SizeInBits), AlignInBits(AlignInBits), - OffsetInBits(OffsetInBits) {} + : DIScope(C, ID, Storage, Tag, Ops) { + init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } ~DIType() = default; + void init(unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags) { + this->Line = Line; + this->Flags = Flags; + this->SizeInBits = SizeInBits; + this->AlignInBits = AlignInBits; + this->OffsetInBits = OffsetInBits; + } + + /// Change fields in place. + void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits, + uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags) { + assert(isDistinct() && "Only distinct nodes can mutate"); + setTag(Tag); + init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } + public: TempDIType clone() const { return TempDIType(cast<DIType>(MDNode::clone().release())); @@ -574,13 +581,12 @@ public: return getFlags() & FlagObjcClassComplete; } bool isVector() const { return getFlags() & FlagVector; } + bool isBitField() const { return getFlags() & FlagBitField; } bool isStaticMember() const { return getFlags() & FlagStaticMember; } bool isLValueReference() const { return getFlags() & FlagLValueReference; } bool isRValueReference() const { return getFlags() & FlagRValueReference; } bool isExternalTypeRef() const { return getFlags() & FlagExternalTypeRef; } - DITypeRef getRef() const { return DITypeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -735,6 +741,12 @@ public: DIObjCProperty *getObjCProperty() const { return dyn_cast_or_null<DIObjCProperty>(getExtraData()); } + Constant *getStorageOffsetInBits() const { + assert(getTag() == dwarf::DW_TAG_member && isBitField()); + if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData())) + return C->getValue(); + return nullptr; + } Constant *getConstant() const { assert(getTag() == dwarf::DW_TAG_member && isStaticMember()); if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData())) @@ -767,6 +779,16 @@ class DICompositeType : public DIType { RuntimeLang(RuntimeLang) {} ~DICompositeType() = default; + /// Change fields in place. + void mutate(unsigned Tag, unsigned Line, unsigned RuntimeLang, + uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, + unsigned Flags) { + assert(isDistinct() && "Only distinct nodes can mutate"); + assert(getRawIdentifier() && "Only ODR-uniqued nodes should mutate"); + this->RuntimeLang = RuntimeLang; + DIType::mutate(Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } + static DICompositeType * getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, @@ -822,6 +844,40 @@ public: TempDICompositeType clone() const { return cloneImpl(); } + /// Get a DICompositeType with the given ODR identifier. + /// + /// If \a LLVMContext::isODRUniquingDebugTypes(), gets the mapped + /// DICompositeType for the given ODR \c Identifier. If none exists, creates + /// a new node. + /// + /// Else, returns \c nullptr. + static DICompositeType * + getODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, + MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, Metadata *Elements, + unsigned RuntimeLang, Metadata *VTableHolder, + Metadata *TemplateParams); + static DICompositeType *getODRTypeIfExists(LLVMContext &Context, + MDString &Identifier); + + /// Build a DICompositeType with the given ODR identifier. + /// + /// Looks up the mapped DICompositeType for the given ODR \c Identifier. If + /// it doesn't exist, creates a new one. If it does exist and \a + /// isForwardDecl(), and the new arguments would be a definition, mutates the + /// the type in place. In either case, returns the type. + /// + /// If not \a LLVMContext::isODRUniquingDebugTypes(), this function returns + /// nullptr. + static DICompositeType * + buildODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, + MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, Metadata *Elements, + unsigned RuntimeLang, Metadata *VTableHolder, + Metadata *TemplateParams); + DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } DINodeArray getElements() const { return cast_or_null<MDTuple>(getRawElements()); @@ -866,14 +922,6 @@ public: } }; -template <class T> TypedDINodeRef<T> TypedDINodeRef<T>::get(const T *N) { - if (N) - if (auto *Composite = dyn_cast<DICompositeType>(N)) - if (auto *S = Composite->getRawIdentifier()) - return TypedDINodeRef<T>(S); - return TypedDINodeRef<T>(N); -} - /// \brief Type array for a subprogram. /// /// TODO: Fold the array of types in directly as operands. @@ -881,35 +929,44 @@ class DISubroutineType : public DIType { friend class LLVMContextImpl; friend class MDNode; + /// The calling convention used with DW_AT_calling_convention. Actually of + /// type dwarf::CallingConvention. + uint8_t CC; + DISubroutineType(LLVMContext &C, StorageType Storage, unsigned Flags, - ArrayRef<Metadata *> Ops) + uint8_t CC, ArrayRef<Metadata *> Ops) : DIType(C, DISubroutineTypeKind, Storage, dwarf::DW_TAG_subroutine_type, - 0, 0, 0, 0, Flags, Ops) {} + 0, 0, 0, 0, Flags, Ops), + CC(CC) {} ~DISubroutineType() = default; static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags, - DITypeRefArray TypeArray, + uint8_t CC, DITypeRefArray TypeArray, StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, Flags, TypeArray.get(), Storage, ShouldCreate); + return getImpl(Context, Flags, CC, TypeArray.get(), Storage, ShouldCreate); } static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags, - Metadata *TypeArray, StorageType Storage, + uint8_t CC, Metadata *TypeArray, + StorageType Storage, bool ShouldCreate = true); TempDISubroutineType cloneImpl() const { - return getTemporary(getContext(), getFlags(), getTypeArray()); + return getTemporary(getContext(), getFlags(), getCC(), getTypeArray()); } public: DEFINE_MDNODE_GET(DISubroutineType, - (unsigned Flags, DITypeRefArray TypeArray), - (Flags, TypeArray)) - DEFINE_MDNODE_GET(DISubroutineType, (unsigned Flags, Metadata *TypeArray), - (Flags, TypeArray)) + (unsigned Flags, uint8_t CC, DITypeRefArray TypeArray), + (Flags, CC, TypeArray)) + DEFINE_MDNODE_GET(DISubroutineType, + (unsigned Flags, uint8_t CC, Metadata *TypeArray), + (Flags, CC, TypeArray)) TempDISubroutineType clone() const { return cloneImpl(); } + uint8_t getCC() const { return CC; } + DITypeRefArray getTypeArray() const { return cast_or_null<MDTuple>(getRawTypeArray()); } @@ -924,7 +981,17 @@ public: class DICompileUnit : public DIScope { friend class LLVMContextImpl; friend class MDNode; +public: + enum DebugEmissionKind : unsigned { + NoDebug = 0, + FullDebug, + LineTablesOnly, + LastEmissionKind = LineTablesOnly + }; + static Optional<DebugEmissionKind> getEmissionKind(StringRef Str); + static const char *EmissionKindString(DebugEmissionKind EK); +private: unsigned SourceLanguage; bool IsOptimized; unsigned RuntimeVersion; @@ -947,33 +1014,30 @@ class DICompileUnit : public DIScope { StringRef Producer, bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, StringRef SplitDebugFilename, unsigned EmissionKind, DICompositeTypeArray EnumTypes, - DITypeArray RetainedTypes, DISubprogramArray Subprograms, - DIGlobalVariableArray GlobalVariables, + DIScopeArray RetainedTypes, DIGlobalVariableArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, 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(), - Subprograms.get(), GlobalVariables.get(), - ImportedEntities.get(), Macros.get(), DWOId, Storage, - ShouldCreate); + 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, Storage, ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, - Metadata *Subprograms, Metadata *GlobalVariables, - Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, - StorageType Storage, bool ShouldCreate = true); + Metadata *GlobalVariables, Metadata *ImportedEntities, + Metadata *Macros, uint64_t DWOId, StorageType Storage, + bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary( getContext(), getSourceLanguage(), getFile(), getProducer(), isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(), - getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(), + getEmissionKind(), getEnumTypes(), getRetainedTypes(), getGlobalVariables(), getImportedEntities(), getMacros(), DWOId); } @@ -985,24 +1049,23 @@ public: DICompileUnit, (unsigned SourceLanguage, DIFile *File, StringRef Producer, bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, - StringRef SplitDebugFilename, unsigned EmissionKind, - DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes, - DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables, + StringRef SplitDebugFilename, DebugEmissionKind EmissionKind, + DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, + DIGlobalVariableArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, - SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, + SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, - Metadata *RetainedTypes, Metadata *Subprograms, - Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, - uint64_t DWOId), + Metadata *RetainedTypes, Metadata *GlobalVariables, + Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, - SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, + SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1010,19 +1073,18 @@ public: unsigned getSourceLanguage() const { return SourceLanguage; } bool isOptimized() const { return IsOptimized; } unsigned getRuntimeVersion() const { return RuntimeVersion; } - unsigned getEmissionKind() const { return EmissionKind; } + DebugEmissionKind getEmissionKind() const { + return (DebugEmissionKind)EmissionKind; + } StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } StringRef getSplitDebugFilename() const { return getStringOperand(3); } DICompositeTypeArray getEnumTypes() const { return cast_or_null<MDTuple>(getRawEnumTypes()); } - DITypeArray getRetainedTypes() const { + DIScopeArray getRetainedTypes() const { return cast_or_null<MDTuple>(getRawRetainedTypes()); } - DISubprogramArray getSubprograms() const { - return cast_or_null<MDTuple>(getRawSubprograms()); - } DIGlobalVariableArray getGlobalVariables() const { return cast_or_null<MDTuple>(getRawGlobalVariables()); } @@ -1042,10 +1104,9 @@ public: } Metadata *getRawEnumTypes() const { return getOperand(4); } Metadata *getRawRetainedTypes() const { return getOperand(5); } - Metadata *getRawSubprograms() const { return getOperand(6); } - Metadata *getRawGlobalVariables() const { return getOperand(7); } - Metadata *getRawImportedEntities() const { return getOperand(8); } - Metadata *getRawMacros() const { return getOperand(9); } + Metadata *getRawGlobalVariables() const { return getOperand(6); } + Metadata *getRawImportedEntities() const { return getOperand(7); } + Metadata *getRawMacros() const { return getOperand(8); } /// \brief Replace arrays. /// @@ -1059,16 +1120,13 @@ public: void replaceRetainedTypes(DITypeArray N) { replaceOperandWith(5, N.get()); } - void replaceSubprograms(DISubprogramArray N) { - replaceOperandWith(6, N.get()); - } void replaceGlobalVariables(DIGlobalVariableArray N) { - replaceOperandWith(7, N.get()); + replaceOperandWith(6, N.get()); } void replaceImportedEntities(DIImportedEntityArray N) { - replaceOperandWith(8, N.get()); + replaceOperandWith(7, N.get()); } - void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(9, N.get()); } + void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(8, N.get()); } /// @} static bool classof(const Metadata *MD) { @@ -1095,6 +1153,12 @@ public: /// chain. DISubprogram *getSubprogram() const; + /// Get the first non DILexicalBlockFile scope of this scope. + /// + /// Return this if it's not a \a DILexicalBlockFIle; otherwise, look up the + /// scope chain. + DILocalScope *getNonLexicalBlockFileScope() const; + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubprogramKind || MD->getMetadataID() == DILexicalBlockKind || @@ -1192,15 +1256,6 @@ public: /// instructions that are on different basic blocks. inline unsigned getDiscriminator() const; - /// \brief Compute new discriminator in the given context. - /// - /// This modifies the \a LLVMContext that \c this is in to increment the next - /// discriminator for \c this's line/filename combination. - /// - /// FIXME: Delete this. See comments in implementation and at the only call - /// site in \a AddDiscriminators::runOnFunction(). - unsigned computeNewDiscriminator() const; - Metadata *getRawScope() const { return getOperand(0); } Metadata *getRawInlinedAt() const { if (getNumOperands() == 2) @@ -1223,22 +1278,41 @@ class DISubprogram : public DILocalScope { unsigned Line; unsigned ScopeLine; - unsigned Virtuality; unsigned VirtualIndex; - unsigned Flags; - bool IsLocalToUnit; - bool IsDefinition; - bool IsOptimized; + + /// In the MS ABI, the implicit 'this' parameter is adjusted in the prologue + /// of method overrides from secondary bases by this amount. It may be + /// negative. + int ThisAdjustment; + + // Virtuality can only assume three values, so we can pack + // in 2 bits (none/pure/pure_virtual). + unsigned Virtuality : 2; + + unsigned Flags : 27; + + // These are boolean flags so one bit is enough. + // MSVC starts a new container field every time the base + // type changes so we can't use 'bool' to ensure these bits + // are packed. + unsigned IsLocalToUnit : 1; + unsigned IsDefinition : 1; + unsigned IsOptimized : 1; DISubprogram(LLVMContext &C, StorageType Storage, unsigned Line, unsigned ScopeLine, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsLocalToUnit, bool IsDefinition, - bool IsOptimized, ArrayRef<Metadata *> Ops) + int ThisAdjustment, unsigned Flags, bool IsLocalToUnit, + bool IsDefinition, bool IsOptimized, ArrayRef<Metadata *> Ops) : DILocalScope(C, DISubprogramKind, Storage, dwarf::DW_TAG_subprogram, Ops), - Line(Line), ScopeLine(ScopeLine), Virtuality(Virtuality), - VirtualIndex(VirtualIndex), Flags(Flags), IsLocalToUnit(IsLocalToUnit), - IsDefinition(IsDefinition), IsOptimized(IsOptimized) {} + Line(Line), ScopeLine(ScopeLine), VirtualIndex(VirtualIndex), + ThisAdjustment(ThisAdjustment), Virtuality(Virtuality), Flags(Flags), + IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), + IsOptimized(IsOptimized) { + static_assert(dwarf::DW_VIRTUALITY_max < 4, "Virtuality out of range"); + assert(Virtuality < 4 && "Virtuality out of range"); + assert((Flags < (1 << 27)) && "Flags out of range"); + } ~DISubprogram() = default; static DISubprogram * @@ -1246,32 +1320,34 @@ class DISubprogram : public DILocalScope { StringRef LinkageName, DIFile *File, unsigned Line, DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, DICompileUnit *Unit, DITemplateParameterArray TemplateParams, DISubprogram *Declaration, DILocalVariableArray Variables, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, - Virtuality, VirtualIndex, Flags, IsOptimized, - TemplateParams.get(), Declaration, Variables.get(), Storage, - ShouldCreate); + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams.get(), Declaration, Variables.get(), + Storage, ShouldCreate); } static DISubprogram * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsOptimized, Metadata *TemplateParams, - Metadata *Declaration, Metadata *Variables, StorageType Storage, - bool ShouldCreate = true); + int ThisAdjustment, unsigned Flags, bool IsOptimized, Metadata *Unit, + Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables, + StorageType Storage, bool ShouldCreate = true); TempDISubprogram cloneImpl() const { return getTemporary( getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), isDefinition(), getScopeLine(), - getContainingType(), getVirtuality(), getVirtualIndex(), getFlags(), - isOptimized(), getTemplateParams(), getDeclaration(), getVariables()); + getContainingType(), getVirtuality(), getVirtualIndex(), + getThisAdjustment(), getFlags(), isOptimized(), getUnit(), + getTemplateParams(), getDeclaration(), getVariables()); } public: @@ -1280,25 +1356,26 @@ public: DIFile *File, unsigned Line, DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, DICompileUnit *Unit, DITemplateParameterArray TemplateParams = nullptr, DISubprogram *Declaration = nullptr, DILocalVariableArray Variables = nullptr), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, TemplateParams, - Declaration, Variables)) + VirtualIndex, ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)) DEFINE_MDNODE_GET( DISubprogram, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, - Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr, - Metadata *Variables = nullptr), + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, Metadata *Unit, Metadata *TemplateParams = nullptr, + Metadata *Declaration = nullptr, Metadata *Variables = nullptr), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, - TemplateParams, Declaration, Variables)) + ScopeLine, ContainingType, Virtuality, VirtualIndex, ThisAdjustment, + Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables)) TempDISubprogram clone() const { return cloneImpl(); } @@ -1306,6 +1383,7 @@ public: unsigned getLine() const { return Line; } unsigned getVirtuality() const { return Virtuality; } unsigned getVirtualIndex() const { return VirtualIndex; } + int getThisAdjustment() const { return ThisAdjustment; } unsigned getScopeLine() const { return ScopeLine; } unsigned getFlags() const { return Flags; } bool isLocalToUnit() const { return IsLocalToUnit; } @@ -1357,6 +1435,12 @@ public: return DITypeRef(getRawContainingType()); } + DICompileUnit *getUnit() const { + return cast_or_null<DICompileUnit>(getRawUnit()); + } + void replaceUnit(DICompileUnit *CU) { + replaceOperandWith(7, CU); + } DITemplateParameterArray getTemplateParams() const { return cast_or_null<MDTuple>(getRawTemplateParams()); } @@ -1370,9 +1454,10 @@ public: Metadata *getRawScope() const { return getOperand(1); } Metadata *getRawType() const { return getOperand(5); } Metadata *getRawContainingType() const { return getOperand(6); } - Metadata *getRawTemplateParams() const { return getOperand(7); } - Metadata *getRawDeclaration() const { return getOperand(8); } - Metadata *getRawVariables() const { return getOperand(9); } + Metadata *getRawUnit() const { return getOperand(7); } + Metadata *getRawTemplateParams() const { return getOperand(8); } + Metadata *getRawDeclaration() const { return getOperand(9); } + Metadata *getRawVariables() const { return getOperand(10); } /// \brief Check if this subprogram describes the given function. /// @@ -1852,13 +1937,16 @@ class DILocalVariable : public DIVariable { friend class LLVMContextImpl; friend class MDNode; - unsigned Arg; - unsigned Flags; + unsigned Arg : 16; + unsigned Flags : 16; DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Arg, unsigned Flags, ArrayRef<Metadata *> Ops) : DIVariable(C, DILocalVariableKind, Storage, Line, Ops), Arg(Arg), - Flags(Flags) {} + Flags(Flags) { + assert(Flags < (1 << 16) && "DILocalVariable: Flags out of range"); + assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range"); + } ~DILocalVariable() = default; static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope, diff --git a/include/llvm/IR/DerivedTypes.h b/include/llvm/IR/DerivedTypes.h index 071e69b1e808..efd0d07366ee 100644 --- a/include/llvm/IR/DerivedTypes.h +++ b/include/llvm/IR/DerivedTypes.h @@ -61,15 +61,14 @@ public: /// @brief Get the number of bits in this IntegerType unsigned getBitWidth() const { return getSubclassData(); } - /// getBitMask - Return a bitmask with ones set for all of the bits - /// that can be set by an unsigned version of this type. This is 0xFF for - /// i8, 0xFFFF for i16, etc. + /// Return a bitmask with ones set for all of the bits that can be set by an + /// unsigned version of this type. This is 0xFF for i8, 0xFFFF for i16, etc. uint64_t getBitMask() const { return ~uint64_t(0UL) >> (64-getBitWidth()); } - /// getSignBit - Return a uint64_t with just the most significant bit set (the - /// sign bit, if the value is treated as a signed number). + /// Return a uint64_t with just the most significant bit set (the sign bit, if + /// the value is treated as a signed number). uint64_t getSignBit() const { return 1ULL << (getBitWidth()-1); } @@ -95,7 +94,7 @@ unsigned Type::getIntegerBitWidth() const { return cast<IntegerType>(this)->getBitWidth(); } -/// FunctionType - Class to represent function types +/// Class to represent function types /// class FunctionType : public Type { FunctionType(const FunctionType &) = delete; @@ -103,22 +102,17 @@ class FunctionType : public Type { FunctionType(Type *Result, ArrayRef<Type*> Params, bool IsVarArgs); public: - /// FunctionType::get - This static method is the primary way of constructing - /// a FunctionType. - /// + /// This static method is the primary way of constructing a FunctionType. static FunctionType *get(Type *Result, ArrayRef<Type*> Params, bool isVarArg); - /// FunctionType::get - Create a FunctionType taking no parameters. - /// + /// Create a FunctionType taking no parameters. static FunctionType *get(Type *Result, bool isVarArg); - /// isValidReturnType - Return true if the specified type is valid as a return - /// type. + /// Return true if the specified type is valid as a return type. static bool isValidReturnType(Type *RetTy); - /// isValidArgumentType - Return true if the specified type is valid as an - /// argument type. + /// Return true if the specified type is valid as an argument type. static bool isValidArgumentType(Type *ArgTy); bool isVarArg() const { return getSubclassData()!=0; } @@ -134,9 +128,8 @@ public: /// Parameter type accessors. Type *getParamType(unsigned i) const { return ContainedTys[i+1]; } - /// getNumParams - Return the number of fixed parameters this function type - /// requires. This does not consider varargs. - /// + /// Return the number of fixed parameters this function type requires. + /// This does not consider varargs. unsigned getNumParams() const { return NumContainedTys - 1; } /// Methods for support type inquiry through isa, cast, and dyn_cast. @@ -159,16 +152,13 @@ unsigned Type::getFunctionNumParams() const { return cast<FunctionType>(this)->getNumParams(); } -/// CompositeType - Common super class of ArrayType, StructType, PointerType -/// and VectorType. +/// Common super class of ArrayType, StructType, PointerType and VectorType. class CompositeType : public Type { protected: explicit CompositeType(LLVMContext &C, TypeID tid) : Type(C, tid) {} public: - /// getTypeAtIndex - Given an index value into the type, return the type of - /// the element. - /// + /// Given an index value into the type, return the type of the element. Type *getTypeAtIndex(const Value *V) const; Type *getTypeAtIndex(unsigned Idx) const; bool indexValid(const Value *V) const; @@ -183,8 +173,8 @@ public: } }; -/// StructType - Class to represent struct types. There are two different kinds -/// of struct types: Literal structs and Identified structs. +/// Class to represent struct types. There are two different kinds of struct +/// types: Literal structs and Identified structs. /// /// Literal struct types (e.g. { i32, i32 }) are uniqued structurally, and must /// always have a body when created. You can get one of these by using one of @@ -216,15 +206,14 @@ class StructType : public CompositeType { SCDB_IsSized = 8 }; - /// SymbolTableEntry - For a named struct that actually has a name, this is a - /// pointer to the symbol table entry (maintained by LLVMContext) for the - /// struct. This is null if the type is an literal struct or if it is - /// a identified type that has an empty name. - /// + /// For a named struct that actually has a name, this is a pointer to the + /// symbol table entry (maintained by LLVMContext) for the struct. + /// This is null if the type is an literal struct or if it is a identified + /// type that has an empty name. void *SymbolTableEntry; public: - /// StructType::create - This creates an identified struct. + /// This creates an identified struct. static StructType *create(LLVMContext &Context, StringRef Name); static StructType *create(LLVMContext &Context); @@ -236,53 +225,48 @@ public: static StructType *create(LLVMContext &Context, ArrayRef<Type *> Elements); static StructType *create(StringRef Name, Type *elt1, ...) LLVM_END_WITH_NULL; - /// StructType::get - This static method is the primary way to create a - /// literal StructType. + /// This static method is the primary way to create a literal StructType. static StructType *get(LLVMContext &Context, ArrayRef<Type*> Elements, bool isPacked = false); - /// StructType::get - Create an empty structure type. - /// + /// Create an empty structure type. static StructType *get(LLVMContext &Context, bool isPacked = false); - /// StructType::get - This static method is a convenience method for creating - /// structure types by specifying the elements as arguments. Note that this - /// method always returns a non-packed struct, and requires at least one - /// element type. + /// This static method is a convenience method for creating structure types by + /// specifying the elements as arguments. Note that this method always returns + /// a non-packed struct, and requires at least one element type. static StructType *get(Type *elt1, ...) LLVM_END_WITH_NULL; bool isPacked() const { return (getSubclassData() & SCDB_Packed) != 0; } - /// isLiteral - Return true if this type is uniqued by structural - /// equivalence, false if it is a struct definition. + /// Return true if this type is uniqued by structural equivalence, false if it + /// is a struct definition. bool isLiteral() const { return (getSubclassData() & SCDB_IsLiteral) != 0; } - /// isOpaque - Return true if this is a type with an identity that has no body - /// specified yet. These prints as 'opaque' in .ll files. + /// Return true if this is a type with an identity that has no body specified + /// yet. These prints as 'opaque' in .ll files. bool isOpaque() const { return (getSubclassData() & SCDB_HasBody) == 0; } /// isSized - Return true if this is a sized type. bool isSized(SmallPtrSetImpl<Type *> *Visited = nullptr) const; - /// hasName - Return true if this is a named struct that has a non-empty name. + /// Return true if this is a named struct that has a non-empty name. bool hasName() const { return SymbolTableEntry != nullptr; } - /// getName - Return the name for this struct type if it has an identity. + /// Return the name for this struct type if it has an identity. /// This may return an empty string for an unnamed struct type. Do not call /// this on an literal type. StringRef getName() const; - /// setName - Change the name of this type to the specified name, or to a name - /// with a suffix if there is a collision. Do not call this on an literal - /// type. + /// Change the name of this type to the specified name, or to a name with a + /// suffix if there is a collision. Do not call this on an literal type. void setName(StringRef Name); - /// setBody - Specify a body for an opaque identified type. + /// Specify a body for an opaque identified type. void setBody(ArrayRef<Type*> Elements, bool isPacked = false); void setBody(Type *elt1, ...) LLVM_END_WITH_NULL; - /// isValidElementType - Return true if the specified type is valid as a - /// element type. + /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); // Iterator access to the elements. @@ -293,8 +277,7 @@ public: return makeArrayRef(element_begin(), element_end()); } - /// isLayoutIdentical - Return true if this is layout identical to the - /// specified struct. + /// Return true if this is layout identical to the specified struct. bool isLayoutIdentical(StructType *Other) const; /// Random access to the elements @@ -322,14 +305,12 @@ Type *Type::getStructElementType(unsigned N) const { return cast<StructType>(this)->getElementType(N); } -/// SequentialType - This is the superclass of the array, pointer and vector -/// type classes. All of these represent "arrays" in memory. The array type -/// represents a specifically sized array, pointer types are unsized/unknown -/// size arrays, vector types represent specifically sized arrays that -/// allow for use of SIMD instructions. SequentialType holds the common -/// features of all, which stem from the fact that all three lay their -/// components out in memory identically. -/// +/// This is the superclass of the array, pointer and vector type classes. +/// All of these represent "arrays" in memory. The array type represents a +/// specifically sized array, pointer types are unsized/unknown size arrays, +/// vector types represent specifically sized arrays that allow for use of SIMD +/// instructions. SequentialType holds the common features of all, which stem +/// from the fact that all three lay their components out in memory identically. class SequentialType : public CompositeType { Type *ContainedType; ///< Storage for the single contained type. SequentialType(const SequentialType &) = delete; @@ -343,7 +324,7 @@ protected: } public: - Type *getElementType() const { return ContainedTys[0]; } + Type *getElementType() const { return getSequentialElementType(); } /// Methods for support type inquiry through isa, cast, and dyn_cast. static inline bool classof(const Type *T) { @@ -353,12 +334,7 @@ public: } }; -Type *Type::getSequentialElementType() const { - return cast<SequentialType>(this)->getElementType(); -} - -/// ArrayType - Class to represent array types. -/// +/// Class to represent array types. class ArrayType : public SequentialType { uint64_t NumElements; @@ -367,13 +343,10 @@ class ArrayType : public SequentialType { ArrayType(Type *ElType, uint64_t NumEl); public: - /// ArrayType::get - This static method is the primary way to construct an - /// ArrayType - /// + /// This static method is the primary way to construct an ArrayType static ArrayType *get(Type *ElementType, uint64_t NumElements); - /// isValidElementType - Return true if the specified type is valid as a - /// element type. + /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); uint64_t getNumElements() const { return NumElements; } @@ -388,8 +361,7 @@ uint64_t Type::getArrayNumElements() const { return cast<ArrayType>(this)->getNumElements(); } -/// VectorType - Class to represent vector types. -/// +/// Class to represent vector types. class VectorType : public SequentialType { unsigned NumElements; @@ -398,15 +370,12 @@ class VectorType : public SequentialType { VectorType(Type *ElType, unsigned NumEl); public: - /// VectorType::get - This static method is the primary way to construct an - /// VectorType. - /// + /// This static method is the primary way to construct an VectorType. static VectorType *get(Type *ElementType, unsigned NumElements); - /// VectorType::getInteger - This static method gets a VectorType with the - /// same number of elements as the input type, and the element type is an - /// integer type of the same width as the input element type. - /// + /// This static method gets a VectorType with the same number of elements as + /// the input type, and the element type is an integer type of the same width + /// as the input element type. static VectorType *getInteger(VectorType *VTy) { unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); assert(EltBits && "Element size must be of a non-zero size"); @@ -414,20 +383,16 @@ public: return VectorType::get(EltTy, VTy->getNumElements()); } - /// VectorType::getExtendedElementVectorType - This static method is like - /// getInteger except that the element types are twice as wide as the - /// elements in the input type. - /// + /// This static method is like getInteger except that the element types are + /// twice as wide as the elements in the input type. static VectorType *getExtendedElementVectorType(VectorType *VTy) { unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); Type *EltTy = IntegerType::get(VTy->getContext(), EltBits * 2); return VectorType::get(EltTy, VTy->getNumElements()); } - /// VectorType::getTruncatedElementVectorType - This static method is like - /// getInteger except that the element types are half as wide as the - /// elements in the input type. - /// + /// This static method is like getInteger except that the element types are + /// half as wide as the elements in the input type. static VectorType *getTruncatedElementVectorType(VectorType *VTy) { unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); assert((EltBits & 1) == 0 && @@ -436,10 +401,8 @@ public: return VectorType::get(EltTy, VTy->getNumElements()); } - /// VectorType::getHalfElementsVectorType - This static method returns - /// a VectorType with half as many elements as the input type and the - /// same element type. - /// + /// This static method returns a VectorType with half as many elements as the + /// input type and the same element type. static VectorType *getHalfElementsVectorType(VectorType *VTy) { unsigned NumElts = VTy->getNumElements(); assert ((NumElts & 1) == 0 && @@ -447,23 +410,20 @@ public: return VectorType::get(VTy->getElementType(), NumElts/2); } - /// VectorType::getDoubleElementsVectorType - This static method returns - /// a VectorType with twice as many elements as the input type and the - /// same element type. - /// + /// This static method returns a VectorType with twice as many elements as the + /// input type and the same element type. static VectorType *getDoubleElementsVectorType(VectorType *VTy) { unsigned NumElts = VTy->getNumElements(); return VectorType::get(VTy->getElementType(), NumElts*2); } - /// isValidElementType - Return true if the specified type is valid as a - /// element type. + /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); - /// @brief Return the number of elements in the Vector type. + /// Return the number of elements in the Vector type. unsigned getNumElements() const { return NumElements; } - /// @brief Return the number of bits in the Vector type. + /// Return the number of bits in the Vector type. /// Returns zero when the vector is a vector of pointers. unsigned getBitWidth() const { return NumElements * getElementType()->getPrimitiveSizeInBits(); @@ -479,32 +439,30 @@ unsigned Type::getVectorNumElements() const { return cast<VectorType>(this)->getNumElements(); } -/// PointerType - Class to represent pointers. -/// +/// Class to represent pointers. class PointerType : public SequentialType { PointerType(const PointerType &) = delete; const PointerType &operator=(const PointerType &) = delete; explicit PointerType(Type *ElType, unsigned AddrSpace); public: - /// PointerType::get - This constructs a pointer to an object of the specified - /// type in a numbered address space. + /// This constructs a pointer to an object of the specified type in a numbered + /// address space. static PointerType *get(Type *ElementType, unsigned AddressSpace); - /// PointerType::getUnqual - This constructs a pointer to an object of the - /// specified type in the generic address space (address space zero). + /// This constructs a pointer to an object of the specified type in the + /// generic address space (address space zero). static PointerType *getUnqual(Type *ElementType) { return PointerType::get(ElementType, 0); } - /// isValidElementType - Return true if the specified type is valid as a - /// element type. + /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); /// Return true if we can load or store from a pointer to this type. static bool isLoadableOrStorableType(Type *ElemTy); - /// @brief Return the address space of the Pointer type. + /// Return the address space of the Pointer type. inline unsigned getAddressSpace() const { return getSubclassData(); } /// Implement support type inquiry through isa, cast, and dyn_cast. diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index f69955e5ed48..1c78684da64d 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -1,4 +1,4 @@ -//===- llvm/Support/DiagnosticInfo.h - Diagnostic Declaration ---*- C++ -*-===// +//===- llvm/IR/DiagnosticInfo.h - Diagnostic Declaration --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,11 +15,14 @@ #ifndef LLVM_IR_DIAGNOSTICINFO_H #define LLVM_IR_DIAGNOSTICINFO_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/IR/DebugLoc.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Casting.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm-c/Types.h" #include <functional> +#include <string> namespace llvm { @@ -27,14 +30,12 @@ namespace llvm { class DiagnosticPrinter; class Function; class Instruction; -class LLVMContextImpl; -class Twine; -class Value; -class DebugLoc; +class LLVMContext; +class Module; class SMDiagnostic; /// \brief Defines the different supported severity of a diagnostic. -enum DiagnosticSeverity { +enum DiagnosticSeverity : char { DS_Error, DS_Warning, DS_Remark, @@ -48,9 +49,11 @@ enum DiagnosticSeverity { enum DiagnosticKind { DK_Bitcode, DK_InlineAsm, + DK_ResourceLimit, DK_StackSize, DK_Linker, DK_DebugMetadataVersion, + DK_DebugMetadataInvalid, DK_SampleProfile, DK_OptimizationRemark, DK_OptimizationRemarkMissed, @@ -58,8 +61,11 @@ enum DiagnosticKind { DK_OptimizationRemarkAnalysisFPCommute, DK_OptimizationRemarkAnalysisAliasing, DK_OptimizationFailure, + DK_FirstRemark = DK_OptimizationRemark, + DK_LastRemark = DK_OptimizationFailure, DK_MIRParser, DK_PGOProfile, + DK_Unsupported, DK_FirstPluginKind }; @@ -101,8 +107,6 @@ public: /// The printed message must not end with '.' nor start with a severity /// keyword. virtual void print(DiagnosticPrinter &DP) const = 0; - - static const char *AlwaysPrint; }; typedef std::function<void(const DiagnosticInfo &)> DiagnosticHandlerFunction; @@ -156,29 +160,64 @@ public: } }; -/// Diagnostic information for stack size reporting. +/// Diagnostic information for stack size etc. reporting. /// This is basically a function and a size. -class DiagnosticInfoStackSize : public DiagnosticInfo { +class DiagnosticInfoResourceLimit : public DiagnosticInfo { private: - /// The function that is concerned by this stack size diagnostic. + /// The function that is concerned by this resource limit diagnostic. const Function &Fn; - /// The computed stack size. - unsigned StackSize; + + /// Description of the resource type (e.g. stack size) + const char *ResourceName; + + /// The computed size usage + uint64_t ResourceSize; + + // Threshould passed + uint64_t ResourceLimit; public: /// \p The function that is concerned by this stack size diagnostic. /// \p The computed stack size. - DiagnosticInfoStackSize(const Function &Fn, unsigned StackSize, - DiagnosticSeverity Severity = DS_Warning) - : DiagnosticInfo(DK_StackSize, Severity), Fn(Fn), StackSize(StackSize) {} + DiagnosticInfoResourceLimit(const Function &Fn, + const char *ResourceName, + uint64_t ResourceSize, + DiagnosticSeverity Severity = DS_Warning, + DiagnosticKind Kind = DK_ResourceLimit, + uint64_t ResourceLimit = 0) + : DiagnosticInfo(Kind, Severity), + Fn(Fn), + ResourceName(ResourceName), + ResourceSize(ResourceSize), + ResourceLimit(ResourceLimit) {} const Function &getFunction() const { return Fn; } - unsigned getStackSize() const { return StackSize; } + const char *getResourceName() const { return ResourceName; } + uint64_t getResourceSize() const { return ResourceSize; } + uint64_t getResourceLimit() const { return ResourceLimit; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_ResourceLimit || + DI->getKind() == DK_StackSize; + } +}; + +class DiagnosticInfoStackSize : public DiagnosticInfoResourceLimit { +public: + DiagnosticInfoStackSize(const Function &Fn, + uint64_t StackSize, + DiagnosticSeverity Severity = DS_Warning, + uint64_t StackLimit = 0) + : DiagnosticInfoResourceLimit(Fn, "stack size", StackSize, + Severity, DK_StackSize, StackLimit) {} + + uint64_t getStackSize() const { return getResourceSize(); } + uint64_t getStackLimit() const { return getResourceLimit(); } + + static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_StackSize; } }; @@ -211,6 +250,29 @@ public: } }; +/// Diagnostic information for stripping invalid debug metadata. +class DiagnosticInfoIgnoringInvalidDebugMetadata : public DiagnosticInfo { +private: + /// The module that is concerned by this debug metadata version diagnostic. + const Module &M; + +public: + /// \p The module that is concerned by this debug metadata version diagnostic. + DiagnosticInfoIgnoringInvalidDebugMetadata( + const Module &M, DiagnosticSeverity Severity = DS_Warning) + : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M) {} + + const Module &getModule() const { return M; } + + /// \see DiagnosticInfo::print. + void print(DiagnosticPrinter &DP) const override; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_DebugMetadataInvalid; + } +}; + + /// Diagnostic information for the sample profiler. class DiagnosticInfoSampleProfile : public DiagnosticInfo { public: @@ -275,8 +337,42 @@ private: const Twine &Msg; }; +/// Common features for diagnostics with an associated DebugLoc +class DiagnosticInfoWithDebugLocBase : public DiagnosticInfo { +public: + /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + /// the location information to use in the diagnostic. + DiagnosticInfoWithDebugLocBase(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const Function &Fn, + const DebugLoc &DLoc) + : DiagnosticInfo(Kind, Severity), Fn(Fn), DLoc(DLoc) {} + + /// Return true if location information is available for this diagnostic. + bool isLocationAvailable() const; + + /// Return a string with the location information for this diagnostic + /// in the format "file:line:col". If location information is not available, + /// it returns "<unknown>:0:0". + const std::string getLocationStr() const; + + /// Return location information for this diagnostic in three parts: + /// the source file name, line number and column. + void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const; + + const Function &getFunction() const { return Fn; } + const DebugLoc &getDebugLoc() const { return DLoc; } + +private: + /// Function where this diagnostic is triggered. + const Function &Fn; + + /// Debug location where this diagnostic is triggered. + DebugLoc DLoc; +}; + /// Common features for diagnostics dealing with optimization remarks. -class DiagnosticInfoOptimizationBase : public DiagnosticInfo { +class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithDebugLocBase { public: /// \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 @@ -288,9 +384,10 @@ public: DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg) - : DiagnosticInfo(Kind, Severity), PassName(PassName), Fn(Fn), DLoc(DLoc), - Msg(Msg) {} + const DebugLoc &DLoc, const Twine &Msg, + Optional<uint64_t> Hotness = None) + : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc), + PassName(PassName), Msg(Msg), Hotness(Hotness) {} /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; @@ -302,37 +399,26 @@ public: /// in BackendConsumer::OptimizationRemarkHandler). virtual bool isEnabled() const = 0; - /// Return true if location information is available for this diagnostic. - bool isLocationAvailable() const; - - /// Return a string with the location information for this diagnostic - /// in the format "file:line:col". If location information is not available, - /// it returns "<unknown>:0:0". - const std::string getLocationStr() const; - - /// Return location information for this diagnostic in three parts: - /// the source file name, line number and column. - void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const; - const char *getPassName() const { return PassName; } - const Function &getFunction() const { return Fn; } - const DebugLoc &getDebugLoc() const { return DLoc; } const Twine &getMsg() const { return Msg; } + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() >= DK_FirstRemark && + DI->getKind() <= DK_LastRemark; + } + private: /// 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; - /// Function where this diagnostic is triggered. - const Function &Fn; - - /// Debug location where this diagnostic is triggered. - DebugLoc DLoc; - /// Message to report. const Twine &Msg; + + /// 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; }; /// Diagnostic information for applied optimization remarks. @@ -373,9 +459,10 @@ public: /// must be valid for the whole life time of the diagnostic. DiagnosticInfoOptimizationRemarkMissed(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg) + const DebugLoc &DLoc, const Twine &Msg, + Optional<uint64_t> Hotness = None) : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark, - PassName, Fn, DLoc, Msg) {} + PassName, Fn, DLoc, Msg, Hotness) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkMissed; @@ -411,6 +498,10 @@ public: /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; + static const char *AlwaysPrint; + + bool shouldAlwaysPrint() const { return getPassName() == AlwaysPrint; } + protected: DiagnosticInfoOptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, @@ -572,6 +663,34 @@ public: bool isEnabled() const override; }; +/// Diagnostic information for unsupported feature in backend. +class DiagnosticInfoUnsupported + : public DiagnosticInfoWithDebugLocBase { +private: + Twine Msg; + +public: + /// \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. + DiagnosticInfoUnsupported(const Function &Fn, const Twine &Msg, + DebugLoc DLoc = DebugLoc(), + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfoWithDebugLocBase(DK_Unsupported, Severity, Fn, DLoc), + Msg(Msg) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_Unsupported; + } + + const Twine &getMessage() const { return Msg; } + + 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. @@ -584,6 +703,6 @@ void emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, void emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, const DebugLoc &DLoc, const Twine &Msg); -} // End namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/include/llvm/IR/Dominators.h b/include/llvm/IR/Dominators.h index 37447c353b19..f445a49b67b8 100644 --- a/include/llvm/IR/Dominators.h +++ b/include/llvm/IR/Dominators.h @@ -15,26 +15,19 @@ #ifndef LLVM_IR_DOMINATORS_H #define LLVM_IR_DOMINATORS_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" -#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/GenericDomTree.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> namespace llvm { -// FIXME: Replace this brittle forward declaration with the include of the new -// PassManager.h when doing so doesn't break the PassManagerBuilder. -template <typename IRUnitT> class AnalysisManager; -class PreservedAnalyses; +class Function; +class BasicBlock; +class raw_ostream; extern template class DomTreeNodeBase<BasicBlock>; extern template class DominatorTreeBase<BasicBlock>; @@ -62,6 +55,26 @@ public: bool isSingleEdge() const; }; +template <> struct DenseMapInfo<BasicBlockEdge> { + static unsigned getHashValue(const BasicBlockEdge *V); + typedef DenseMapInfo<const BasicBlock *> BBInfo; + static inline BasicBlockEdge getEmptyKey() { + return BasicBlockEdge(BBInfo::getEmptyKey(), BBInfo::getEmptyKey()); + } + static inline BasicBlockEdge getTombstoneKey() { + return BasicBlockEdge(BBInfo::getTombstoneKey(), BBInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const BasicBlockEdge &Edge) { + 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()); + } +}; + /// \brief Concrete subclass of DominatorTreeBase that is used to compute a /// normal dominator tree. /// @@ -186,40 +199,31 @@ template <> struct GraphTraits<DominatorTree*> }; /// \brief Analysis pass which computes a \c DominatorTree. -class DominatorTreeAnalysis { +class DominatorTreeAnalysis : public AnalysisInfoMixin<DominatorTreeAnalysis> { + friend AnalysisInfoMixin<DominatorTreeAnalysis>; + static char PassID; + public: /// \brief Provide the result typedef for this analysis pass. typedef DominatorTree Result; - /// \brief Opaque, unique identifier for this analysis pass. - static void *ID() { return (void *)&PassID; } - /// \brief Run the analysis pass over a function and produce a dominator tree. - DominatorTree run(Function &F); - - /// \brief Provide access to a name for this pass for debugging purposes. - static StringRef name() { return "DominatorTreeAnalysis"; } - -private: - static char PassID; + DominatorTree run(Function &F, AnalysisManager<Function> &); }; /// \brief Printer pass for the \c DominatorTree. -class DominatorTreePrinterPass { +class DominatorTreePrinterPass + : public PassInfoMixin<DominatorTreePrinterPass> { raw_ostream &OS; public: explicit DominatorTreePrinterPass(raw_ostream &OS); - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); - - static StringRef name() { return "DominatorTreePrinterPass"; } + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Verifier pass for the \c DominatorTree. -struct DominatorTreeVerifierPass { - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); - - static StringRef name() { return "DominatorTreeVerifierPass"; } +struct DominatorTreeVerifierPass : PassInfoMixin<DominatorTreeVerifierPass> { + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Legacy analysis pass which computes a \c DominatorTree. diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 4f64caeade20..d7d27e7585c1 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -19,7 +19,6 @@ #define LLVM_IR_FUNCTION_H #include "llvm/ADT/iterator_range.h" -#include "llvm/ADT/Optional.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -30,6 +29,7 @@ namespace llvm { +template <typename T> class Optional; class FunctionType; class LLVMContext; class DISubprogram; @@ -56,7 +56,6 @@ private: mutable ArgumentListType ArgumentList; ///< The formal arguments ValueSymbolTable *SymTab; ///< Symbol table of args/instructions AttributeSet AttributeSets; ///< Parameter attributes - FunctionType *Ty; /* * Value::SubclassData @@ -73,13 +72,8 @@ private: /// Bits from GlobalObject::GlobalObjectSubclassData. enum { /// Whether this function is materializable. - IsMaterializableBit = 1 << 0, - HasMetadataHashEntryBit = 1 << 1 + IsMaterializableBit = 0, }; - void setGlobalObjectBit(unsigned Mask, bool Value) { - setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | - (Value ? Mask : 0u)); - } friend class SymbolTableListTraits<Function>; @@ -89,9 +83,12 @@ private: /// built on demand, so that the list isn't allocated until the first client /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. +public: bool hasLazyArguments() const { return getSubclassDataFromValue() & (1<<0); } + +private: void CheckLazyArguments() const { if (hasLazyArguments()) BuildLazyArguments(); @@ -166,7 +163,7 @@ public: AttributeSet getAttributes() const { return AttributeSets; } /// @brief Set the attribute list for this Function. - void setAttributes(AttributeSet attrs) { AttributeSets = attrs; } + void setAttributes(AttributeSet Attrs) { AttributeSets = Attrs; } /// @brief Add function attributes to this function. void addFnAttr(Attribute::AttrKind N) { @@ -175,9 +172,9 @@ public: } /// @brief Remove function attributes from this function. - void removeFnAttr(Attribute::AttrKind N) { + void removeFnAttr(Attribute::AttrKind Kind) { setAttributes(AttributeSets.removeAttribute( - getContext(), AttributeSet::FunctionIndex, N)); + getContext(), AttributeSet::FunctionIndex, Kind)); } /// @brief Add function attributes to this function. @@ -200,7 +197,7 @@ public: /// @brief Return true if the function has the attribute. bool hasFnAttribute(Attribute::AttrKind Kind) const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, Kind); + return AttributeSets.hasFnAttribute(Kind); } bool hasFnAttribute(StringRef Kind) const { return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, Kind); @@ -208,14 +205,16 @@ public: /// @brief Return the attribute for the given attribute kind. Attribute getFnAttribute(Attribute::AttrKind Kind) const { - return AttributeSets.getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeSet::FunctionIndex, Kind); } Attribute getFnAttribute(StringRef Kind) const { - return AttributeSets.getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeSet::FunctionIndex, Kind); } /// \brief Return the stack alignment for the function. unsigned getFnStackAlignment() const { + if (!hasFnAttribute(Attribute::StackAlignment)) + return 0; return AttributeSets.getStackAlignment(AttributeSet::FunctionIndex); } @@ -225,17 +224,39 @@ public: return getSubclassDataFromValue() & (1<<14); } const std::string &getGC() const; - void setGC(const std::string Str); + void setGC(std::string Str); void clearGC(); /// @brief adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); + + /// @brief adds the attribute to the list of attributes. + 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, AttributeSet Attrs); + + /// @brief removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute::AttrKind Kind); + + /// @brief removes the attribute from the list of attributes. + void removeAttribute(unsigned i, StringRef Kind); /// @brief removes the attributes from the list of attributes. - void removeAttributes(unsigned i, AttributeSet attr); + void removeAttributes(unsigned i, AttributeSet 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); + } + + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { + return AttributeSets.getAttribute(i, Kind); + } + + Attribute getAttribute(unsigned i, StringRef Kind) const { + return AttributeSets.getAttribute(i, Kind); + } /// @brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); @@ -263,8 +284,7 @@ public: /// @brief Determine if the function does not access memory. bool doesNotAccessMemory() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::ReadNone); + return hasFnAttribute(Attribute::ReadNone); } void setDoesNotAccessMemory() { addFnAttr(Attribute::ReadNone); @@ -272,27 +292,31 @@ public: /// @brief Determine if the function does not access or only reads memory. bool onlyReadsMemory() const { - return doesNotAccessMemory() || - AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::ReadOnly); + return doesNotAccessMemory() || hasFnAttribute(Attribute::ReadOnly); } void setOnlyReadsMemory() { addFnAttr(Attribute::ReadOnly); } + /// @brief Determine if the function does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addFnAttr(Attribute::WriteOnly); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::ArgMemOnly); + return hasFnAttribute(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } /// @brief Determine if the function may only access memory that is /// inaccessible from the IR. bool onlyAccessesInaccessibleMemory() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::InaccessibleMemOnly); + return hasFnAttribute(Attribute::InaccessibleMemOnly); } void setOnlyAccessesInaccessibleMemory() { addFnAttr(Attribute::InaccessibleMemOnly); @@ -301,8 +325,7 @@ public: /// @brief Determine if the function may only access memory that is // either inaccessible from the IR or pointed to by its arguments. bool onlyAccessesInaccessibleMemOrArgMem() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::InaccessibleMemOrArgMemOnly); + return hasFnAttribute(Attribute::InaccessibleMemOrArgMemOnly); } void setOnlyAccessesInaccessibleMemOrArgMem() { addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); @@ -310,8 +333,7 @@ public: /// @brief Determine if the function cannot return. bool doesNotReturn() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::NoReturn); + return hasFnAttribute(Attribute::NoReturn); } void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); @@ -319,8 +341,7 @@ public: /// @brief Determine if the function cannot unwind. bool doesNotThrow() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::NoUnwind); + return hasFnAttribute(Attribute::NoUnwind); } void setDoesNotThrow() { addFnAttr(Attribute::NoUnwind); @@ -328,8 +349,7 @@ public: /// @brief Determine if the call cannot be duplicated. bool cannotDuplicate() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::NoDuplicate); + return hasFnAttribute(Attribute::NoDuplicate); } void setCannotDuplicate() { addFnAttr(Attribute::NoDuplicate); @@ -337,18 +357,19 @@ public: /// @brief Determine if the call is convergent. bool isConvergent() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::Convergent); + return hasFnAttribute(Attribute::Convergent); } void setConvergent() { addFnAttr(Attribute::Convergent); } + void setNotConvergent() { + removeFnAttr(Attribute::Convergent); + } /// Determine if the function is known not to recurse, directly or /// indirectly. bool doesNotRecurse() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::NoRecurse); + return hasFnAttribute(Attribute::NoRecurse); } void setDoesNotRecurse() { addFnAttr(Attribute::NoRecurse); @@ -357,8 +378,7 @@ public: /// @brief True if the ABI mandates (or the user requested) that this /// function be in a unwind table. bool hasUWTable() const { - return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, - Attribute::UWTable); + return hasFnAttribute(Attribute::UWTable); } void setHasUWTable() { addFnAttr(Attribute::UWTable); @@ -440,6 +460,12 @@ public: /// void eraseFromParent() override; + /// Steal arguments from another function. + /// + /// Drop this function's arguments and splice in the ones from \c Src. + /// Requires that this has no function body. + void stealArgumentListFrom(Function &Src); + /// Get the underlying elements of the Function... the basic block list is /// empty for external functions. /// @@ -547,6 +573,12 @@ public: Constant *getPrologueData() const; void setPrologueData(Constant *PrologueData); + /// Print the function to an output stream with an optional + /// AssemblyAnnotationWriter. + void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW = nullptr, + bool ShouldPreserveUseListOrder = false, + bool IsForDebug = false) const; + /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the /// program, displaying the CFG of the current function with the code for each @@ -597,35 +629,6 @@ public: /// setjmp or other function that gcc recognizes as "returning twice". bool callsFunctionThatReturnsTwice() const; - /// \brief Check if this has any metadata. - bool hasMetadata() const { return hasMetadataHashEntry(); } - - /// \brief Get the current metadata attachment, if any. - /// - /// Returns \c nullptr if such an attachment is missing. - /// @{ - MDNode *getMetadata(unsigned KindID) const; - MDNode *getMetadata(StringRef Kind) const; - /// @} - - /// \brief Set a particular kind of metadata attachment. - /// - /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or - /// replacing it if it already exists. - /// @{ - void setMetadata(unsigned KindID, MDNode *MD); - void setMetadata(StringRef Kind, MDNode *MD); - /// @} - - /// \brief Get all current metadata attachments. - void - getAllMetadata(SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const; - - /// \brief Drop metadata not in the given list. - /// - /// Drop all metadata from \c this not included in \c KnownIDs. - void dropUnknownMetadata(ArrayRef<unsigned> KnownIDs); - /// \brief Set the attached subprogram. /// /// Calls \a setMetadata() with \a LLVMContext::MD_dbg. @@ -647,15 +650,6 @@ private: Value::setValueSubclassData(D); } void setValueSubclassDataBit(unsigned Bit, bool On); - - bool hasMetadataHashEntry() const { - return getGlobalObjectSubClassData() & HasMetadataHashEntryBit; - } - void setHasMetadataHashEntry(bool HasEntry) { - setGlobalObjectBit(HasMetadataHashEntryBit, HasEntry); - } - - void clearMetadata(); }; template <> diff --git a/include/llvm/IR/FunctionInfo.h b/include/llvm/IR/FunctionInfo.h deleted file mode 100644 index eba088a61bc0..000000000000 --- a/include/llvm/IR/FunctionInfo.h +++ /dev/null @@ -1,241 +0,0 @@ -//===-- llvm/FunctionInfo.h - Function Info Index ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -/// @file -/// FunctionInfo.h This file contains the declarations the classes that hold -/// the function info index and summary. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_IR_FUNCTIONINFO_H -#define LLVM_IR_FUNCTIONINFO_H - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { - -/// \brief Function summary information to aid decisions and implementation of -/// importing. -/// -/// This is a separate class from FunctionInfo to enable lazy reading of this -/// function summary information from the combined index file during imporing. -class FunctionSummary { -private: - /// \brief Path of module containing function IR, used to locate module when - /// importing this function. - /// - /// This is only used during parsing of the combined function index, or when - /// parsing the per-module index for creation of the combined function index, - /// not during writing of the per-module index which doesn't contain a - /// module path string table. - StringRef ModulePath; - - /// \brief Used to flag functions that have local linkage types and need to - /// have module identifier appended before placing into the combined - /// index, to disambiguate from other functions with the same name. - /// - /// This is only used in the per-module function index, as it is consumed - /// while creating the combined index. - bool IsLocalFunction; - - // The rest of the information is used to help decide whether importing - // is likely to be profitable. - // Other information will be added as the importing is tuned, such - // as hotness (when profile available), and other function characteristics. - - /// Number of instructions (ignoring debug instructions, e.g.) computed - /// during the initial compile step when the function index is first built. - unsigned InstCount; - -public: - /// Construct a summary object from summary data expected for all - /// summary records. - FunctionSummary(unsigned NumInsts) : InstCount(NumInsts) {} - - /// Set the path to the module containing this function, for use in - /// the combined index. - void setModulePath(StringRef ModPath) { ModulePath = ModPath; } - - /// Get the path to the module containing this function. - StringRef modulePath() const { return ModulePath; } - - /// Record whether this is a local function in the per-module index. - void setLocalFunction(bool IsLocal) { IsLocalFunction = IsLocal; } - - /// Check whether this was a local function, for use in creating - /// the combined index. - bool isLocalFunction() const { return IsLocalFunction; } - - /// Get the instruction count recorded for this function. - unsigned instCount() const { return InstCount; } -}; - -/// \brief Class to hold pointer to function summary and information required -/// for parsing it. -/// -/// For the per-module index, this holds the bitcode offset -/// of the corresponding function block. For the combined index, -/// after parsing of the \a ValueSymbolTable, this initially -/// holds the offset of the corresponding function summary bitcode -/// record. After parsing the associated summary information from the summary -/// block the \a FunctionSummary is populated and stored here. -class FunctionInfo { -private: - /// Function summary information used to help make ThinLTO importing - /// decisions. - std::unique_ptr<FunctionSummary> Summary; - - /// \brief The bitcode offset corresponding to either the associated - /// function's function body record, or its function summary record, - /// depending on whether this is a per-module or combined index. - /// - /// This bitcode offset is written to or read from the associated - /// \a ValueSymbolTable entry for the function. - /// For the per-module index this holds the bitcode offset of the - /// function's body record within bitcode module block in its module, - /// which is used during lazy function parsing or ThinLTO importing. - /// For the combined index this holds the offset of the corresponding - /// function summary record, to enable associating the combined index - /// VST records with the summary records. - uint64_t BitcodeIndex; - -public: - /// Constructor used during parsing of VST entries. - FunctionInfo(uint64_t FuncOffset) - : Summary(nullptr), BitcodeIndex(FuncOffset) {} - - /// Constructor used for per-module index bitcode writing. - FunctionInfo(uint64_t FuncOffset, - std::unique_ptr<FunctionSummary> FuncSummary) - : Summary(std::move(FuncSummary)), BitcodeIndex(FuncOffset) {} - - /// Record the function summary information parsed out of the function - /// summary block during parsing or combined index creation. - void setFunctionSummary(std::unique_ptr<FunctionSummary> FuncSummary) { - Summary = std::move(FuncSummary); - } - - /// Get the function summary recorded for this function. - FunctionSummary *functionSummary() const { return Summary.get(); } - - /// Get the bitcode index recorded for this function, depending on - /// the index type. - uint64_t bitcodeIndex() const { return BitcodeIndex; } - - /// Record the bitcode index for this function, depending on - /// the index type. - void setBitcodeIndex(uint64_t FuncOffset) { BitcodeIndex = FuncOffset; } -}; - -/// List of function info structures for a particular function name held -/// in the FunctionMap. Requires a vector in the case of multiple -/// COMDAT functions of the same name. -typedef std::vector<std::unique_ptr<FunctionInfo>> FunctionInfoList; - -/// Map from function name to corresponding function info structures. -typedef StringMap<FunctionInfoList> FunctionInfoMapTy; - -/// Type used for iterating through the function info map. -typedef FunctionInfoMapTy::const_iterator const_funcinfo_iterator; -typedef FunctionInfoMapTy::iterator funcinfo_iterator; - -/// String table to hold/own module path strings, which additionally holds the -/// module ID assigned to each module during the plugin step. The StringMap -/// makes a copy of and owns inserted strings. -typedef StringMap<uint64_t> ModulePathStringTableTy; - -/// Class to hold module path string table and function map, -/// and encapsulate methods for operating on them. -class FunctionInfoIndex { -private: - /// Map from function name to list of function information instances - /// for functions of that name (may be duplicates in the COMDAT case, e.g.). - FunctionInfoMapTy FunctionMap; - - /// Holds strings for combined index, mapping to the corresponding module ID. - ModulePathStringTableTy ModulePathStringTable; - -public: - FunctionInfoIndex() = default; - - // Disable the copy constructor and assignment operators, so - // no unexpected copying/moving occurs. - FunctionInfoIndex(const FunctionInfoIndex &) = delete; - void operator=(const FunctionInfoIndex &) = delete; - - funcinfo_iterator begin() { return FunctionMap.begin(); } - const_funcinfo_iterator begin() const { return FunctionMap.begin(); } - funcinfo_iterator end() { return FunctionMap.end(); } - const_funcinfo_iterator end() const { return FunctionMap.end(); } - - /// Get the list of function info objects for a given function. - const FunctionInfoList &getFunctionInfoList(StringRef FuncName) { - return FunctionMap[FuncName]; - } - - /// Get the list of function info objects for a given function. - const const_funcinfo_iterator findFunctionInfoList(StringRef FuncName) const { - return FunctionMap.find(FuncName); - } - - /// Add a function info for a function of the given name. - void addFunctionInfo(StringRef FuncName, std::unique_ptr<FunctionInfo> Info) { - FunctionMap[FuncName].push_back(std::move(Info)); - } - - /// Iterator to allow writer to walk through table during emission. - iterator_range<StringMap<uint64_t>::const_iterator> - modPathStringEntries() const { - return llvm::make_range(ModulePathStringTable.begin(), - ModulePathStringTable.end()); - } - - /// Get the module ID recorded for the given module path. - uint64_t getModuleId(const StringRef ModPath) const { - return ModulePathStringTable.lookup(ModPath); - } - - /// Add the given per-module index into this function index/summary, - /// assigning it the given module ID. Each module merged in should have - /// a unique ID, necessary for consistent renaming of promoted - /// static (local) variables. - void mergeFrom(std::unique_ptr<FunctionInfoIndex> Other, - uint64_t NextModuleId); - - /// Convenience method for creating a promoted global name - /// for the given value name of a local, and its original module's ID. - static std::string getGlobalNameForLocal(StringRef Name, uint64_t ModId) { - SmallString<256> NewName(Name); - NewName += ".llvm."; - raw_svector_ostream(NewName) << ModId; - return NewName.str(); - } - - /// Add a new module path, mapped to the given module Id, and return StringRef - /// owned by string table map. - StringRef addModulePath(StringRef ModPath, uint64_t ModId) { - return ModulePathStringTable.insert(std::make_pair(ModPath, ModId)) - .first->first(); - } - - /// Check if the given Module has any functions available for exporting - /// in the index. We consider any module present in the ModulePathStringTable - /// to have exported functions. - bool hasExportedFunctions(const Module &M) const { - return ModulePathStringTable.count(M.getModuleIdentifier()); - } -}; - -} // End llvm namespace - -#endif diff --git a/include/llvm/IR/GVMaterializer.h b/include/llvm/IR/GVMaterializer.h index 6cb593c7a3da..9e47722c892b 100644 --- a/include/llvm/IR/GVMaterializer.h +++ b/include/llvm/IR/GVMaterializer.h @@ -18,14 +18,12 @@ #ifndef LLVM_IR_GVMATERIALIZER_H #define LLVM_IR_GVMATERIALIZER_H -#include "llvm/ADT/DenseMap.h" #include <system_error> #include <vector> namespace llvm { class Function; class GlobalValue; -class Metadata; class Module; class StructType; @@ -47,14 +45,6 @@ public: virtual std::error_code materializeMetadata() = 0; virtual void setStripDebugInfo() = 0; - /// Client should define this interface if the mapping between metadata - /// values and value ids needs to be preserved, e.g. across materializer - /// instantiations. If OnlyTempMD is true, only those that have remained - /// temporary metadata are recorded in the map. - virtual void - saveMetadataList(DenseMap<const Metadata *, unsigned> &MetadataToIDs, - bool OnlyTempMD) {} - virtual std::vector<StructType *> getIdentifiedStructTypes() const = 0; }; diff --git a/include/llvm/IR/GetElementPtrTypeIterator.h b/include/llvm/IR/GetElementPtrTypeIterator.h index 7cb13fa33aa6..4953aebbe8aa 100644 --- a/include/llvm/IR/GetElementPtrTypeIterator.h +++ b/include/llvm/IR/GetElementPtrTypeIterator.h @@ -33,12 +33,6 @@ namespace llvm { generic_gep_type_iterator() {} public: - static generic_gep_type_iterator begin(Type *Ty, ItTy It) { - generic_gep_type_iterator I; - I.CurTy.setPointer(Ty); - I.OpIt = It; - return I; - } static generic_gep_type_iterator begin(Type *Ty, unsigned AddrSpace, ItTy It) { generic_gep_type_iterator I; @@ -125,13 +119,13 @@ namespace llvm { template<typename T> inline generic_gep_type_iterator<const T *> - gep_type_begin(Type *Op0, ArrayRef<T> A) { - return generic_gep_type_iterator<const T *>::begin(Op0, A.begin()); + gep_type_begin(Type *Op0, unsigned AS, ArrayRef<T> A) { + return generic_gep_type_iterator<const T *>::begin(Op0, AS, A.begin()); } template<typename T> inline generic_gep_type_iterator<const T *> - gep_type_end(Type * /*Op0*/, ArrayRef<T> A) { + gep_type_end(Type * /*Op0*/, unsigned /*AS*/, ArrayRef<T> A) { return generic_gep_type_iterator<const T *>::end(A.end()); } } // end namespace llvm diff --git a/include/llvm/IR/GlobalAlias.h b/include/llvm/IR/GlobalAlias.h index b0772143309f..3ae3e4a001e1 100644 --- a/include/llvm/IR/GlobalAlias.h +++ b/include/llvm/IR/GlobalAlias.h @@ -15,17 +15,17 @@ #ifndef LLVM_IR_GLOBALALIAS_H #define LLVM_IR_GLOBALALIAS_H -#include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/GlobalIndirectSymbol.h" namespace llvm { +class Twine; class Module; template <typename ValueSubClass> class SymbolTableListTraits; -class GlobalAlias : public GlobalValue, public ilist_node<GlobalAlias> { +class GlobalAlias : public GlobalIndirectSymbol, + public ilist_node<GlobalAlias> { friend class SymbolTableListTraits<GlobalAlias>; void operator=(const GlobalAlias &) = delete; GlobalAlias(const GlobalAlias &) = delete; @@ -36,11 +36,6 @@ class GlobalAlias : public GlobalValue, public ilist_node<GlobalAlias> { const Twine &Name, Constant *Aliasee, Module *Parent); public: - // allocate space for exactly one operand - void *operator new(size_t s) { - return User::operator new(s, 1); - } - /// If a parent module is specified, the alias is automatically inserted into /// the end of the specified module's alias list. static GlobalAlias *create(Type *Ty, unsigned AddressSpace, @@ -64,9 +59,6 @@ public: // Linkage, Type, Parent and AddressSpace taken from the Aliasee. static GlobalAlias *create(const Twine &Name, GlobalValue *Aliasee); - /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// removeFromParent - This method unlinks 'this' from the containing module, /// but does not delete it. /// @@ -77,28 +69,13 @@ public: /// void eraseFromParent() override; - /// These methods retrive and set alias target. + /// These methods retrieve and set alias target. void setAliasee(Constant *Aliasee); const Constant *getAliasee() const { - return const_cast<GlobalAlias *>(this)->getAliasee(); + return getIndirectSymbol(); } Constant *getAliasee() { - return getOperand(0); - } - - const GlobalObject *getBaseObject() const { - return const_cast<GlobalAlias *>(this)->getBaseObject(); - } - GlobalObject *getBaseObject() { - return dyn_cast<GlobalObject>(getAliasee()->stripInBoundsOffsets()); - } - - const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const { - return const_cast<GlobalAlias *>(this)->getBaseObject(DL, Offset); - } - GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { - return dyn_cast<GlobalObject>( - getAliasee()->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); + return getIndirectSymbol(); } static bool isValidLinkage(LinkageTypes L) { @@ -112,13 +89,6 @@ public: } }; -template <> -struct OperandTraits<GlobalAlias> : - public FixedNumOperandTraits<GlobalAlias, 1> { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Constant) - } // End llvm namespace #endif diff --git a/include/llvm/IR/GlobalIFunc.h b/include/llvm/IR/GlobalIFunc.h new file mode 100644 index 000000000000..0cbe882c58d8 --- /dev/null +++ b/include/llvm/IR/GlobalIFunc.h @@ -0,0 +1,76 @@ +//===-------- llvm/GlobalIFunc.h - GlobalIFunc class ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \brief +/// This file contains the declaration of the GlobalIFunc class, which +/// represents a single indirect function in the IR. Indirect function uses +/// ELF symbol type extension to mark that the address of a declaration should +/// be resolved at runtime by calling a resolver function. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_GLOBALIFUNC_H +#define LLVM_IR_GLOBALIFUNC_H + +#include "llvm/ADT/ilist_node.h" +#include "llvm/IR/GlobalIndirectSymbol.h" + +namespace llvm { + +class Twine; +class Module; + +// Traits class for using GlobalIFunc in symbol table in Module. +template <typename ValueSubClass> class SymbolTableListTraits; + +class GlobalIFunc final : public GlobalIndirectSymbol, + public ilist_node<GlobalIFunc> { + friend class SymbolTableListTraits<GlobalIFunc>; + void operator=(const GlobalIFunc &) = delete; + GlobalIFunc(const GlobalIFunc &) = delete; + + void setParent(Module *parent); + + GlobalIFunc(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, + const Twine &Name, Constant *Resolver, Module *Parent); + +public: + /// If a parent module is specified, the ifunc is automatically inserted into + /// the end of the specified module's ifunc list. + static GlobalIFunc *create(Type *Ty, unsigned AddressSpace, + LinkageTypes Linkage, const Twine &Name, + Constant *Resolver, Module *Parent); + + /// This method unlinks 'this' from the containing module, but does not + /// delete it. + void removeFromParent() final; + + /// This method unlinks 'this' from the containing module and deletes it. + void eraseFromParent() final; + + /// These methods retrieve and set ifunc resolver function. + void setResolver(Constant *Resolver) { + setIndirectSymbol(Resolver); + } + const Constant *getResolver() const { + return getIndirectSymbol(); + } + Constant *getResolver() { + return getIndirectSymbol(); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::GlobalIFuncVal; + } +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/IR/GlobalIndirectSymbol.h b/include/llvm/IR/GlobalIndirectSymbol.h new file mode 100644 index 000000000000..8edb3d1dbf4b --- /dev/null +++ b/include/llvm/IR/GlobalIndirectSymbol.h @@ -0,0 +1,84 @@ +//===- llvm/GlobalIndirectSymbol.h - GlobalIndirectSymbol class -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the GlobalIndirectSymbol class, which +// is a base class for GlobalAlias and GlobalIFunc. It contains all common code +// for aliases and ifuncs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_GLOBALINDIRECTSYMBOL_H +#define LLVM_IR_GLOBALINDIRECTSYMBOL_H + +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/OperandTraits.h" + +namespace llvm { + +class GlobalIndirectSymbol : public GlobalValue { + void operator=(const GlobalIndirectSymbol &) = delete; + GlobalIndirectSymbol(const GlobalIndirectSymbol &) = delete; + +protected: + GlobalIndirectSymbol(Type *Ty, ValueTy VTy, unsigned AddressSpace, + LinkageTypes Linkage, const Twine &Name, Constant *Symbol); + +public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// These methods set and retrieve indirect symbol. + void setIndirectSymbol(Constant *Symbol) { + setOperand(0, Symbol); + } + const Constant *getIndirectSymbol() const { + return const_cast<GlobalIndirectSymbol *>(this)->getIndirectSymbol(); + } + Constant *getIndirectSymbol() { + return getOperand(0); + } + + const GlobalObject *getBaseObject() const { + return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(); + } + GlobalObject *getBaseObject() { + return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets()); + } + + 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)); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::GlobalAliasVal || + V->getValueID() == Value::GlobalIFuncVal; + } +}; + +template <> +struct OperandTraits<GlobalIndirectSymbol> : + public FixedNumOperandTraits<GlobalIndirectSymbol, 1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalIndirectSymbol, Constant) + +} // End llvm namespace + +#endif diff --git a/include/llvm/IR/GlobalObject.h b/include/llvm/IR/GlobalObject.h index ee111a046d73..04737a045ae5 100644 --- a/include/llvm/IR/GlobalObject.h +++ b/include/llvm/IR/GlobalObject.h @@ -15,12 +15,13 @@ #ifndef LLVM_IR_GLOBALOBJECT_H #define LLVM_IR_GLOBALOBJECT_H -#include "llvm/IR/Constant.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" namespace llvm { class Comdat; +class MDNode; +class Metadata; class Module; class GlobalObject : public GlobalValue { @@ -37,12 +38,19 @@ protected: std::string Section; // Section to emit this into, empty means default Comdat *ObjComdat; - static const unsigned AlignmentBits = 5; + enum { + LastAlignmentBit = 4, + HasMetadataHashEntryBit, + + GlobalObjectBits, + }; static const unsigned GlobalObjectSubClassDataBits = - GlobalValueSubClassDataBits - AlignmentBits; + GlobalValueSubClassDataBits - GlobalObjectBits; private: + static const unsigned AlignmentBits = LastAlignmentBit + 1; static const unsigned AlignmentMask = (1 << AlignmentBits) - 1; + static const unsigned GlobalObjectMask = (1 << GlobalObjectBits) - 1; public: unsigned getAlignment() const { @@ -55,8 +63,8 @@ public: unsigned getGlobalObjectSubClassData() const; void setGlobalObjectSubClassData(unsigned Val); - bool hasSection() const { return !StringRef(getSection()).empty(); } - const char *getSection() const { return Section.c_str(); } + bool hasSection() const { return !getSection().empty(); } + StringRef getSection() const { return Section; } void setSection(StringRef S); bool hasComdat() const { return getComdat() != nullptr; } @@ -64,6 +72,54 @@ public: Comdat *getComdat() { return ObjComdat; } void setComdat(Comdat *C) { ObjComdat = C; } + /// Check if this has any metadata. + bool hasMetadata() const { return hasMetadataHashEntry(); } + + /// Get the current metadata attachments for the given kind, if any. + /// + /// These functions require that the function have at most a single attachment + /// of the given kind, and return \c nullptr if such an attachment is missing. + /// @{ + MDNode *getMetadata(unsigned KindID) const; + MDNode *getMetadata(StringRef Kind) const; + /// @} + + /// Appends all attachments with the given ID to \c MDs in insertion order. + /// If the global has no attachments with the given ID, or if ID is invalid, + /// leaves MDs unchanged. + /// @{ + void getMetadata(unsigned KindID, SmallVectorImpl<MDNode *> &MDs) const; + void getMetadata(StringRef Kind, SmallVectorImpl<MDNode *> &MDs) const; + /// @} + + /// Set a particular kind of metadata attachment. + /// + /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or + /// replacing it if it already exists. + /// @{ + void setMetadata(unsigned KindID, MDNode *MD); + void setMetadata(StringRef Kind, MDNode *MD); + /// @} + + /// Add a metadata attachment. + /// @{ + void addMetadata(unsigned KindID, MDNode &MD); + void addMetadata(StringRef Kind, MDNode &MD); + /// @} + + /// Appends all attachments for the global to \c MDs, sorting by attachment + /// ID. Attachments with the same ID appear in insertion order. + void + getAllMetadata(SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const; + + /// Erase all metadata attachments with the given kind. + void eraseMetadata(unsigned KindID); + + /// Copy metadata from Src, adjusting offsets by Offset. + void copyMetadata(const GlobalObject *Src, unsigned Offset); + + void addTypeMetadata(unsigned Offset, Metadata *TypeID); + void copyAttributesFrom(const GlobalValue *Src) override; // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -71,6 +127,18 @@ public: return V->getValueID() == Value::FunctionVal || V->getValueID() == Value::GlobalVariableVal; } + + void clearMetadata(); + +private: + bool hasMetadataHashEntry() const { + return getGlobalValueSubClassData() & (1 << HasMetadataHashEntryBit); + } + void setHasMetadataHashEntry(bool HasEntry) { + unsigned Mask = 1 << HasMetadataHashEntryBit; + setGlobalValueSubClassData((~Mask & getGlobalValueSubClassData()) | + (HasEntry ? Mask : 0u)); + } }; } // End llvm namespace diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index fa6469aa0ade..09682f7aa349 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -20,6 +20,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/Support/MD5.h" #include <system_error> namespace llvm { @@ -69,17 +70,18 @@ protected: LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace) : Constant(PointerType::get(Ty, AddressSpace), VTy, Ops, NumOps), ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility), - UnnamedAddr(0), DllStorageClass(DefaultStorageClass), - ThreadLocal(NotThreadLocal), IntID((Intrinsic::ID)0U), Parent(nullptr) { + UnnamedAddrVal(unsigned(UnnamedAddr::None)), + DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), + IntID((Intrinsic::ID)0U), Parent(nullptr) { setName(Name); } Type *ValueType; - // Note: VC++ treats enums as signed, so an extra bit is required to prevent - // Linkage and Visibility from turning into negative values. - LinkageTypes Linkage : 5; // The linkage of this global + // All bitfields use unsigned as the underlying type so that MSVC will pack + // them. + unsigned Linkage : 4; // The linkage of this global unsigned Visibility : 2; // The visibility style of this global - unsigned UnnamedAddr : 1; // This value's address is not significant + unsigned UnnamedAddrVal : 2; // This value's address is not significant unsigned DllStorageClass : 2; // DLL storage class unsigned ThreadLocal : 3; // Is this symbol "Thread Local", if so, what is @@ -88,12 +90,36 @@ protected: private: // Give subclasses access to what otherwise would be wasted padding. - // (19 + 3 + 2 + 1 + 2 + 5) == 32. + // (19 + 4 + 2 + 2 + 2 + 3) == 32. unsigned SubClassData : GlobalValueSubClassDataBits; friend class Constant; void destroyConstantImpl(); - Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + Value *handleOperandChangeImpl(Value *From, Value *To); + + /// Returns true if the definition of this global may be replaced by a + /// differently optimized variant of the same source level function at link + /// time. + bool mayBeDerefined() const { + switch (getLinkage()) { + case WeakODRLinkage: + case LinkOnceODRLinkage: + case AvailableExternallyLinkage: + return true; + + case WeakAnyLinkage: + case LinkOnceAnyLinkage: + case CommonLinkage: + case ExternalWeakLinkage: + case ExternalLinkage: + case AppendingLinkage: + case InternalLinkage: + case PrivateLinkage: + return isInterposable(); + } + + llvm_unreachable("Fully covered switch above!"); + } protected: /// \brief The intrinsic ID for this subclass (which must be a Function). @@ -128,8 +154,37 @@ public: unsigned getAlignment() const; - bool hasUnnamedAddr() const { return UnnamedAddr; } - void setUnnamedAddr(bool Val) { UnnamedAddr = Val; } + enum class UnnamedAddr { + None, + Local, + Global, + }; + + bool hasGlobalUnnamedAddr() const { + return getUnnamedAddr() == UnnamedAddr::Global; + } + + /// Returns true if this value's address is not significant in this module. + /// This attribute is intended to be used only by the code generator and LTO + /// to allow the linker to decide whether the global needs to be in the symbol + /// table. It should probably not be used in optimizations, as the value may + /// have uses outside the module; use hasGlobalUnnamedAddr() instead. + bool hasAtLeastLocalUnnamedAddr() const { + return getUnnamedAddr() != UnnamedAddr::None; + } + + UnnamedAddr getUnnamedAddr() const { + return UnnamedAddr(UnnamedAddrVal); + } + void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = unsigned(Val); } + + static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { + if (A == UnnamedAddr::None || B == UnnamedAddr::None) + return UnnamedAddr::None; + if (A == UnnamedAddr::Local || B == UnnamedAddr::Local) + return UnnamedAddr::Local; + return UnnamedAddr::Global; + } bool hasComdat() const { return getComdat() != nullptr; } Comdat *getComdat(); @@ -173,14 +228,8 @@ public: } void setDLLStorageClass(DLLStorageClassTypes C) { DllStorageClass = C; } - bool hasSection() const { return !StringRef(getSection()).empty(); } - // It is unfortunate that we have to use "char *" in here since this is - // always non NULL, but: - // * The C API expects a null terminated string, so we cannot use StringRef. - // * The C API expects us to own it, so we cannot use a std:string. - // * For GlobalAliases we can fail to find the section and we have to - // return "", so we cannot use a "const std::string &". - const char *getSection() const; + bool hasSection() const { return !getSection().empty(); } + StringRef getSection() const; /// Global values are always pointers. PointerType *getType() const { return cast<PointerType>(User::getType()); } @@ -233,6 +282,34 @@ public: static bool isCommonLinkage(LinkageTypes Linkage) { return Linkage == CommonLinkage; } + static bool isValidDeclarationLinkage(LinkageTypes Linkage) { + return isExternalWeakLinkage(Linkage) || isExternalLinkage(Linkage); + } + + /// Whether the definition of this global may be replaced by something + /// non-equivalent at link time. For example, if a function has weak linkage + /// then the code defining it may be replaced by different code. + static bool isInterposableLinkage(LinkageTypes Linkage) { + switch (Linkage) { + case WeakAnyLinkage: + case LinkOnceAnyLinkage: + case CommonLinkage: + case ExternalWeakLinkage: + return true; + + case AvailableExternallyLinkage: + case LinkOnceODRLinkage: + case WeakODRLinkage: + // The above three cannot be overridden but can be de-refined. + + case ExternalLinkage: + case AppendingLinkage: + case InternalLinkage: + case PrivateLinkage: + return false; + } + llvm_unreachable("Fully covered switch above!"); + } /// Whether the definition of this global may be discarded if it is not used /// in its compilation unit. @@ -241,17 +318,9 @@ public: isAvailableExternallyLinkage(Linkage); } - /// Whether the definition of this global may be replaced by something - /// non-equivalent at link time. For example, if a function has weak linkage - /// then the code defining it may be replaced by different code. - static bool mayBeOverridden(LinkageTypes Linkage) { - return Linkage == WeakAnyLinkage || Linkage == LinkOnceAnyLinkage || - Linkage == CommonLinkage || Linkage == ExternalWeakLinkage; - } - /// Whether the definition of this global may be replaced at link time. NB: /// Using this method outside of the code generators is almost always a - /// mistake: when working at the IR level use mayBeOverridden instead as it + /// mistake: when working at the IR level use isInterposable instead as it /// knows about ODR semantics. static bool isWeakForLinker(LinkageTypes Linkage) { return Linkage == WeakAnyLinkage || Linkage == WeakODRLinkage || @@ -259,44 +328,87 @@ public: Linkage == CommonLinkage || Linkage == ExternalWeakLinkage; } - bool hasExternalLinkage() const { return isExternalLinkage(Linkage); } + /// Return true if the currently visible definition of this global (if any) is + /// exactly the definition we will see at runtime. + /// + /// Non-exact linkage types inhibits most non-inlining IPO, since a + /// differently optimized variant of the same function can have different + /// observable or undefined behavior than in the variant currently visible. + /// For instance, we could have started with + /// + /// void foo(int *v) { + /// int t = 5 / v[0]; + /// (void) t; + /// } + /// + /// and "refined" it to + /// + /// void foo(int *v) { } + /// + /// However, we cannot infer readnone for `foo`, since that would justify + /// DSE'ing a store to `v[0]` across a call to `foo`, which can cause + /// undefined behavior if the linker replaces the actual call destination with + /// the unoptimized `foo`. + /// + /// Inlining is okay across non-exact linkage types as long as they're not + /// interposable (see \c isInterposable), since in such cases the currently + /// visible variant is *a* correct implementation of the original source + /// function; it just isn't the *only* correct implementation. + bool isDefinitionExact() const { + return !mayBeDerefined(); + } + + /// Return true if this global has an exact defintion. + bool hasExactDefinition() const { + // While this computes exactly the same thing as + // isStrongDefinitionForLinker, the intended uses are different. This + // function is intended to help decide if specific inter-procedural + // transforms are correct, while isStrongDefinitionForLinker's intended use + // is in low level code generation. + return !isDeclaration() && isDefinitionExact(); + } + + /// Return true if this global's definition can be substituted with an + /// *arbitrary* definition at link time. We cannot do any IPO or inlinining + /// across interposable call edges, since the callee can be replaced with + /// something arbitrary at link time. + bool isInterposable() const { return isInterposableLinkage(getLinkage()); } + + bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); } bool hasAvailableExternallyLinkage() const { - return isAvailableExternallyLinkage(Linkage); - } - bool hasLinkOnceLinkage() const { - return isLinkOnceLinkage(Linkage); + return isAvailableExternallyLinkage(getLinkage()); } - bool hasLinkOnceODRLinkage() const { return isLinkOnceODRLinkage(Linkage); } - bool hasWeakLinkage() const { - return isWeakLinkage(Linkage); + bool hasLinkOnceLinkage() const { return isLinkOnceLinkage(getLinkage()); } + bool hasLinkOnceODRLinkage() const { + return isLinkOnceODRLinkage(getLinkage()); } - bool hasWeakAnyLinkage() const { - return isWeakAnyLinkage(Linkage); + bool hasWeakLinkage() const { return isWeakLinkage(getLinkage()); } + bool hasWeakAnyLinkage() const { return isWeakAnyLinkage(getLinkage()); } + bool hasWeakODRLinkage() const { return isWeakODRLinkage(getLinkage()); } + bool hasAppendingLinkage() const { return isAppendingLinkage(getLinkage()); } + bool hasInternalLinkage() const { return isInternalLinkage(getLinkage()); } + bool hasPrivateLinkage() const { return isPrivateLinkage(getLinkage()); } + bool hasLocalLinkage() const { return isLocalLinkage(getLinkage()); } + bool hasExternalWeakLinkage() const { + return isExternalWeakLinkage(getLinkage()); } - bool hasWeakODRLinkage() const { - return isWeakODRLinkage(Linkage); + bool hasCommonLinkage() const { return isCommonLinkage(getLinkage()); } + bool hasValidDeclarationLinkage() const { + return isValidDeclarationLinkage(getLinkage()); } - bool hasAppendingLinkage() const { return isAppendingLinkage(Linkage); } - bool hasInternalLinkage() const { return isInternalLinkage(Linkage); } - bool hasPrivateLinkage() const { return isPrivateLinkage(Linkage); } - bool hasLocalLinkage() const { return isLocalLinkage(Linkage); } - bool hasExternalWeakLinkage() const { return isExternalWeakLinkage(Linkage); } - bool hasCommonLinkage() const { return isCommonLinkage(Linkage); } void setLinkage(LinkageTypes LT) { if (isLocalLinkage(LT)) Visibility = DefaultVisibility; Linkage = LT; } - LinkageTypes getLinkage() const { return Linkage; } + LinkageTypes getLinkage() const { return LinkageTypes(Linkage); } bool isDiscardableIfUnused() const { - return isDiscardableIfUnused(Linkage); + return isDiscardableIfUnused(getLinkage()); } - bool mayBeOverridden() const { return mayBeOverridden(Linkage); } - - bool isWeakForLinker() const { return isWeakForLinker(Linkage); } + bool isWeakForLinker() const { return isWeakForLinker(getLinkage()); } /// Copy all additional attributes (those not needed to create a GlobalValue) /// from the GlobalValue Src to this one. @@ -311,11 +423,37 @@ public: return Name; } -/// @name Materialization -/// Materialization is used to construct functions only as they're needed. This -/// is useful to reduce memory usage in LLVM or parsing work done by the -/// BitcodeReader to load the Module. -/// @{ + /// Return the modified name for a global value suitable to be + /// used as the key for a global lookup (e.g. profile or ThinLTO). + /// The value's original name is \c Name and has linkage of type + /// \c Linkage. The value is defined in module \c FileName. + static std::string getGlobalIdentifier(StringRef Name, + GlobalValue::LinkageTypes Linkage, + StringRef FileName); + + /// Return the modified name for this global value suitable to be + /// used as the key for a global lookup (e.g. profile or ThinLTO). + std::string getGlobalIdentifier() const; + + /// Declare a type to represent a global unique identifier for a global value. + /// This is a 64 bits hash that is used by PGO and ThinLTO to have a compact + /// unique way to identify a symbol. + using GUID = uint64_t; + + /// Return a 64-bit global unique ID constructed from global value name + /// (i.e. returned by getGlobalIdentifier()). + static GUID getGUID(StringRef GlobalName) { return MD5Hash(GlobalName); } + + /// Return a 64-bit global unique ID constructed from global value name + /// (i.e. returned by getGlobalIdentifier()). + GUID getGUID() const { return getGUID(getGlobalIdentifier()); } + + /// @name Materialization + /// Materialization is used to construct functions only as they're needed. + /// This + /// is useful to reduce memory usage in LLVM or parsing work done by the + /// BitcodeReader to load the Module. + /// @{ /// If this function's Module is being lazily streamed in functions from disk /// or some other source, this method can be used to check to see if the @@ -342,6 +480,10 @@ public: /// Returns true if this global's definition will be the one chosen by the /// linker. + /// + /// NB! Ideally this should not be used at the IR level at all. If you're + /// interested in optimization constraints implied by the linker's ability to + /// choose an implementation, prefer using \c hasExactDefinition. bool isStrongDefinitionForLinker() const { return !(isDeclarationForLinker() || isWeakForLinker()); } @@ -365,7 +507,8 @@ public: static bool classof(const Value *V) { return V->getValueID() == Value::FunctionVal || V->getValueID() == Value::GlobalVariableVal || - V->getValueID() == Value::GlobalAliasVal; + V->getValueID() == Value::GlobalAliasVal || + V->getValueID() == Value::GlobalIFuncVal; } }; diff --git a/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h index 342bdc01bfbd..ebeb635468d0 100644 --- a/include/llvm/IR/GlobalVariable.h +++ b/include/llvm/IR/GlobalVariable.h @@ -65,6 +65,8 @@ public: bool isExternallyInitialized = false); ~GlobalVariable() override { + dropAllReferences(); + // FIXME: needed by operator delete setGlobalVariableNumOperands(1); } @@ -94,9 +96,9 @@ public: /// unique. inline bool hasDefinitiveInitializer() const { return hasInitializer() && - // The initializer of a global variable with weak linkage may change at - // link time. - !mayBeOverridden() && + // The initializer of a global variable may change to something arbitrary + // at link time. + !isInterposable() && // The initializer of a global variable with the externally_initialized // marker may change at runtime before C++ initializers are evaluated. !isExternallyInitialized(); @@ -159,6 +161,10 @@ public: /// void eraseFromParent() override; + /// Drop all references in preparation to destroy the GlobalVariable. This + /// drops not only the reference to the initializer but also to any metadata. + void dropAllReferences(); + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { return V->getValueID() == Value::GlobalVariableVal; diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 2f8c3c499295..016e9e1d2c50 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -16,36 +16,54 @@ #define LLVM_IR_IRBUILDER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/ConstantFolder.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Casting.h" +#include "llvm-c/Types.h" +#include <cassert> +#include <cstddef> +#include <cstdint> namespace llvm { + +class APInt; class MDNode; +class Module; +class Use; /// \brief This provides the default implementation of the IRBuilder /// 'InsertHelper' method that is called whenever an instruction is created by /// IRBuilder and needs to be inserted. /// /// By default, this inserts the instruction at the insertion point. -template <bool preserveNames = true> class IRBuilderDefaultInserter { protected: void InsertHelper(Instruction *I, const Twine &Name, BasicBlock *BB, BasicBlock::iterator InsertPt) const { if (BB) BB->getInstList().insert(InsertPt, I); - if (preserveNames) - I->setName(Name); + I->setName(Name); } }; @@ -436,6 +454,16 @@ public: CallInst *CreateMaskedStore(Value *Val, Value *Ptr, unsigned Align, Value *Mask); + /// \brief Create a call to Masked Gather intrinsic + CallInst *CreateMaskedGather(Value *Ptrs, unsigned Align, + Value *Mask = nullptr, + Value *PassThru = nullptr, + const Twine& Name = ""); + + /// \brief Create a call to Masked Scatter intrinsic + CallInst *CreateMaskedScatter(Value *Val, Value *Ptrs, unsigned Align, + Value *Mask = nullptr); + /// \brief Create an assume intrinsic call that allows the optimizer to /// assume that the provided condition will be true. CallInst *CreateAssumption(Value *Cond); @@ -512,9 +540,9 @@ public: private: /// \brief Create a call to a masked intrinsic with given Id. - /// Masked intrinsic has only one overloaded type - data type. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef<Value *> Ops, - Type *DataTy, const Twine &Name = ""); + ArrayRef<Type *> OverloadedTypes, + const Twine &Name = ""); Value *getCastedInt8PtrValue(Value *Ptr); }; @@ -529,14 +557,12 @@ private: /// created. Convenience state exists to specify fast-math flags and fp-math /// tags. /// -/// The first template argument handles whether or not to preserve names in the -/// final instruction output. This defaults to on. The second template argument -/// specifies a class to use for creating constants. This defaults to creating -/// minimally folded constants. The third template argument allows clients to -/// specify custom insertion hooks that are called on every newly created -/// insertion. -template<bool preserveNames = true, typename T = ConstantFolder, - typename Inserter = IRBuilderDefaultInserter<preserveNames> > +/// The first template argument specifies a class to use for creating constants. +/// This defaults to creating minimally folded constants. The second template +/// argument allows clients to specify custom insertion hooks that are called on +/// every newly created insertion. +template <typename T = ConstantFolder, + typename Inserter = IRBuilderDefaultInserter> class IRBuilder : public IRBuilderBase, public Inserter { T Folder; @@ -586,10 +612,6 @@ public: /// \brief Get the constant folder being used. const T &getFolder() { return Folder; } - /// \brief Return true if this builder is configured to actually add the - /// requested names to IR created through it. - bool isNamePreserving() const { return preserveNames; } - /// \brief Insert and return the specified instruction. template<typename InstTy> InstTy *Insert(InstTy *I, const Twine &Name = "") const { @@ -676,28 +698,10 @@ public: return Insert(IndirectBrInst::Create(Addr, NumDests)); } - InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, const Twine &Name = "") { - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, None), - Name); - } - InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, Value *Arg1, - const Twine &Name = "") { - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Arg1), - Name); - } - InvokeInst *CreateInvoke3(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, Value *Arg1, - Value *Arg2, Value *Arg3, - const Twine &Name = "") { - Value *Args[] = { Arg1, Arg2, Arg3 }; - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), - Name); - } /// \brief Create an invoke instruction. InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, ArrayRef<Value *> Args, + BasicBlock *UnwindDest, + ArrayRef<Value *> Args = None, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), Name); @@ -1569,12 +1573,19 @@ public: } Value *CreateSelect(Value *C, Value *True, Value *False, - const Twine &Name = "") { + const Twine &Name = "", Instruction *MDFrom = nullptr) { if (Constant *CC = dyn_cast<Constant>(C)) if (Constant *TC = dyn_cast<Constant>(True)) if (Constant *FC = dyn_cast<Constant>(False)) return Insert(Folder.CreateSelect(CC, TC, FC), Name); - return Insert(SelectInst::Create(C, True, False), Name); + + SelectInst *Sel = SelectInst::Create(C, True, False); + if (MDFrom) { + MDNode *Prof = MDFrom->getMetadata(LLVMContext::MD_prof); + MDNode *Unpred = MDFrom->getMetadata(LLVMContext::MD_unpredictable); + Sel = addBranchMetadata(Sel, Prof, Unpred); + } + return Insert(Sel, Name); } VAArgInst *CreateVAArg(Value *List, Type *Ty, const Twine &Name = "") { @@ -1617,13 +1628,9 @@ public: return Insert(new ShuffleVectorInst(V1, V2, Mask), Name); } - Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef<int> IntMask, + Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef<uint32_t> IntMask, const Twine &Name = "") { - size_t MaskSize = IntMask.size(); - SmallVector<Constant*, 8> MaskVec(MaskSize); - for (size_t i = 0; i != MaskSize; ++i) - MaskVec[i] = getInt32(IntMask[i]); - Value *Mask = ConstantVector::get(MaskVec); + Value *Mask = ConstantDataVector::get(Context, IntMask); return CreateShuffleVector(V1, V2, Mask, Name); } diff --git a/include/llvm/IR/IRPrintingPasses.h b/include/llvm/IR/IRPrintingPasses.h index 88b18e826daf..bc6de19a6c3a 100644 --- a/include/llvm/IR/IRPrintingPasses.h +++ b/include/llvm/IR/IRPrintingPasses.h @@ -30,6 +30,7 @@ class Module; class ModulePass; class PreservedAnalyses; class raw_ostream; +template <typename IRUnitT> class AnalysisManager; /// \brief Create and return a pass that writes the module to the specified /// \c raw_ostream. @@ -67,7 +68,7 @@ public: PrintModulePass(raw_ostream &OS, const std::string &Banner = "", bool ShouldPreserveUseListOrder = false); - PreservedAnalyses run(Module &M); + PreservedAnalyses run(Module &M, AnalysisManager<Module> &); static StringRef name() { return "PrintModulePass"; } }; @@ -84,7 +85,7 @@ public: PrintFunctionPass(); PrintFunctionPass(raw_ostream &OS, const std::string &Banner = ""); - PreservedAnalyses run(Function &F); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &); static StringRef name() { return "PrintFunctionPass"; } }; diff --git a/include/llvm/IR/InlineAsm.h b/include/llvm/IR/InlineAsm.h index d2e9e48539ce..40ba830b8819 100644 --- a/include/llvm/IR/InlineAsm.h +++ b/include/llvm/IR/InlineAsm.h @@ -223,6 +223,7 @@ public: Extra_AsmDialect = 4, Extra_MayLoad = 8, Extra_MayStore = 16, + Extra_IsConvergent = 32, // Inline asm operands map to multiple SDNode / MachineInstr operands. // The first operand is an immediate describing the asm operand, the low @@ -271,6 +272,16 @@ public: return Kind | (NumOps << 3); } + static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;} + static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; } + static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; } + static bool isRegDefEarlyClobberKind(unsigned Flag) { + return getKind(Flag) == Kind_RegDefEarlyClobber; + } + static bool isClobberKind(unsigned Flag) { + return getKind(Flag) == Kind_Clobber; + } + /// getFlagWordForMatchingOp - Augment an existing flag word returned by /// getFlagWord with information indicating that this input operand is tied /// to a previous output operand. @@ -289,6 +300,8 @@ public: static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC) { // Store RC + 1, reserve the value 0 to mean 'no register class'. ++RC; + assert(!isImmKind(InputFlag) && "Immediates cannot have a register class"); + assert(!isMemKind(InputFlag) && "Memory operand cannot have a register class"); assert(RC <= 0x7fff && "Too large register class ID"); assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); return InputFlag | (RC << 16); @@ -297,6 +310,7 @@ public: /// Augment an existing flag word returned by getFlagWord with the constraint /// code for a memory constraint. static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) { + assert(isMemKind(InputFlag) && "InputFlag is not a memory constraint!"); assert(Constraint <= 0x7fff && "Too large a memory constraint ID"); assert(Constraint <= Constraints_Max && "Unknown constraint ID"); assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); @@ -312,16 +326,6 @@ public: return Flags & 7; } - static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;} - static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; } - static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; } - static bool isRegDefEarlyClobberKind(unsigned Flag) { - return getKind(Flag) == Kind_RegDefEarlyClobber; - } - static bool isClobberKind(unsigned Flag) { - return getKind(Flag) == Kind_Clobber; - } - static unsigned getMemoryConstraintID(unsigned Flag) { assert(isMemKind(Flag)); return (Flag >> Constraints_ShiftAmount) & 0x7fff; diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index 5091bb407833..39514c5675a7 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -386,6 +386,15 @@ public: } #include "llvm/IR/Instruction.def" + static BinaryOperator *CreateWithCopiedFlags(BinaryOps Opc, + Value *V1, Value *V2, + BinaryOperator *CopyBO, + const Twine &Name = "") { + BinaryOperator *BO = Create(Opc, V1, V2, Name); + BO->copyIRFlags(CopyBO); + return BO; + } + static BinaryOperator *CreateNSW(BinaryOps Opc, Value *V1, Value *V2, const Twine &Name = "") { BinaryOperator *BO = Create(Opc, V1, V2, Name); @@ -526,35 +535,6 @@ public: /// bool swapOperands(); - /// Set or clear the nsw flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setHasNoUnsignedWrap(bool b = true); - - /// Set or clear the nsw flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setHasNoSignedWrap(bool b = true); - - /// Set or clear the exact flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setIsExact(bool b = true); - - /// Determine whether the no unsigned wrap flag is set. - bool hasNoUnsignedWrap() const; - - /// Determine whether the no signed wrap flag is set. - bool hasNoSignedWrap() const; - - /// Determine whether the exact flag is set. - bool isExact() const; - - /// Convenience method to copy supported wrapping, exact, and fast-math flags - /// from V to this instruction. - void copyIRFlags(const Value *V); - - /// Logical 'and' of any supported wrapping, exact, and fast-math flags of - /// V and this instruction. - void andIRFlags(const Value *V); - // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->isBinaryOp(); @@ -879,6 +859,10 @@ public: /// Values in the range 0-31 are reserved for FCmpInst, while values in the /// range 32-64 are reserved for ICmpInst. This is necessary to ensure the /// predicate values are not overlapping between the classes. + /// + /// Some passes (e.g. InstCombine) depend on the bit-wise characteristics of + /// FCMP_* values. Changing the bit patterns requires a potential change to + /// those passes. enum Predicate { // Opcode U L G E Intuitive operation FCMP_FALSE = 0, ///< 0 0 0 0 Always false (always folded) @@ -1058,6 +1042,18 @@ public: return isFalseWhenEqual(getPredicate()); } + /// @brief Determine if Pred1 implies Pred2 is true when two compares have + /// matching operands. + bool isImpliedTrueByMatchingCmp(Predicate Pred2) { + return isImpliedTrueByMatchingCmp(getPredicate(), Pred2); + } + + /// @brief Determine if Pred1 implies Pred2 is false when two compares have + /// matching operands. + bool isImpliedFalseByMatchingCmp(Predicate Pred2) { + return isImpliedFalseByMatchingCmp(getPredicate(), Pred2); + } + /// @returns true if the predicate is unsigned, false otherwise. /// @brief Determine if the predicate is an unsigned operation. static bool isUnsigned(Predicate predicate); @@ -1078,6 +1074,14 @@ public: /// Determine if the predicate is false when comparing a value with itself. static bool isFalseWhenEqual(Predicate predicate); + /// Determine if Pred1 implies Pred2 is true when two compares have matching + /// operands. + static bool isImpliedTrueByMatchingCmp(Predicate Pred1, Predicate Pred2); + + /// Determine if Pred1 implies Pred2 is false when two compares have matching + /// operands. + static bool isImpliedFalseByMatchingCmp(Predicate Pred1, Predicate Pred2); + /// @brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ICmp || @@ -1469,6 +1473,17 @@ public: Other.bundle_op_info_begin()); }; + /// \brief Return true if this operand bundle user contains operand bundles + /// with tags other than those specified in \p IDs. + bool hasOperandBundlesOtherThan(ArrayRef<uint32_t> IDs) const { + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) { + uint32_t ID = getOperandBundleAt(i).getTagID(); + if (std::find(IDs.begin(), IDs.end(), ID) == IDs.end()) + return true; + } + return false; + } + protected: /// \brief Is the function attribute S disallowed by some operand bundle on /// this operand bundle user? diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index 03c45497fa95..df4f8df78b12 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -42,23 +42,23 @@ class Instruction : public User, DebugLoc DbgLoc; // 'dbg' Metadata cache. enum { - /// HasMetadataBit - This is a bit stored in the SubClassData field which - /// indicates whether this instruction has metadata attached to it or not. + /// This is a bit stored in the SubClassData field which indicates whether + /// this instruction has metadata attached to it or not. HasMetadataBit = 1 << 15 }; public: // Out of line virtual method, so the vtable, etc has a home. ~Instruction() override; - /// user_back - Specialize the methods defined in Value, as we know that an - /// instruction can only be used by other instructions. + /// Specialize the methods defined in Value, as we know that an instruction + /// can only be used by other instructions. Instruction *user_back() { return cast<Instruction>(*user_begin());} const Instruction *user_back() const { return cast<Instruction>(*user_begin());} inline const BasicBlock *getParent() const { return Parent; } inline BasicBlock *getParent() { return Parent; } - /// \brief Return the module owning the function this instruction belongs to + /// Return the module owning the function this instruction belongs to /// or nullptr it the function does not have a module. /// /// Note: this is undefined behavior if the instruction does not have a @@ -66,20 +66,18 @@ public: const Module *getModule() const; Module *getModule(); - /// \brief Return the function this instruction belongs to. + /// 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(); - /// removeFromParent - This method unlinks 'this' from the containing basic - /// block, but does not delete it. - /// + /// This method unlinks 'this' from the containing basic block, but does not + /// delete it. void removeFromParent(); - /// eraseFromParent - This method unlinks 'this' from the containing basic - /// block and deletes it. + /// This method unlinks 'this' from the containing basic block and deletes it. /// /// \returns an iterator pointing to the element after the erased one SymbolTableList<Instruction>::iterator eraseFromParent(); @@ -92,16 +90,15 @@ public: /// specified instruction. void insertAfter(Instruction *InsertPos); - /// moveBefore - Unlink this instruction from its current basic block and - /// insert it into the basic block that MovePos lives in, right before - /// MovePos. + /// Unlink this instruction from its current basic block and insert it into + /// the basic block that MovePos lives in, right before MovePos. void moveBefore(Instruction *MovePos); //===--------------------------------------------------------------------===// // Subclass classification. //===--------------------------------------------------------------------===// - /// getOpcode() returns a member of one of the enums like Instruction::Add. + /// Returns a member of one of the enums like Instruction::Add. unsigned getOpcode() const { return getValueID() - InstructionVal; } const char *getOpcodeName() const { return getOpcodeName(getOpcode()); } @@ -121,28 +118,27 @@ public: return Opcode >= BinaryOpsBegin && Opcode < BinaryOpsEnd; } - /// @brief Determine if the Opcode is one of the shift instructions. + /// Determine if the Opcode is one of the shift instructions. static inline bool isShift(unsigned Opcode) { return Opcode >= Shl && Opcode <= AShr; } - /// isLogicalShift - Return true if this is a logical shift left or a logical - /// shift right. + /// Return true if this is a logical shift left or a logical shift right. inline bool isLogicalShift() const { return getOpcode() == Shl || getOpcode() == LShr; } - /// isArithmeticShift - Return true if this is an arithmetic shift right. + /// Return true if this is an arithmetic shift right. inline bool isArithmeticShift() const { return getOpcode() == AShr; } - /// @brief Determine if the OpCode is one of the CastInst instructions. + /// Determine if the OpCode is one of the CastInst instructions. static inline bool isCast(unsigned OpCode) { return OpCode >= CastOpsBegin && OpCode < CastOpsEnd; } - /// @brief Determine if the OpCode is one of the FuncletPadInst instructions. + /// Determine if the OpCode is one of the FuncletPadInst instructions. static inline bool isFuncletPad(unsigned OpCode) { return OpCode >= FuncletPadOpsBegin && OpCode < FuncletPadOpsEnd; } @@ -151,55 +147,53 @@ public: // Metadata manipulation. //===--------------------------------------------------------------------===// - /// hasMetadata() - Return true if this instruction has any metadata attached - /// to it. + /// Return true if this instruction has any metadata attached to it. bool hasMetadata() const { return DbgLoc || hasMetadataHashEntry(); } - /// hasMetadataOtherThanDebugLoc - Return true if this instruction has - /// metadata attached to it other than a debug location. + /// Return true if this instruction has metadata attached to it other than a + /// debug location. bool hasMetadataOtherThanDebugLoc() const { return hasMetadataHashEntry(); } - /// getMetadata - Get the metadata of given kind attached to this Instruction. + /// Get the metadata of given kind attached to this Instruction. /// If the metadata is not found then return null. MDNode *getMetadata(unsigned KindID) const { if (!hasMetadata()) return nullptr; return getMetadataImpl(KindID); } - /// getMetadata - Get the metadata of given kind attached to this Instruction. + /// Get the metadata of given kind attached to this Instruction. /// If the metadata is not found then return null. MDNode *getMetadata(StringRef Kind) const { if (!hasMetadata()) return nullptr; return getMetadataImpl(Kind); } - /// getAllMetadata - Get all metadata attached to this Instruction. The first - /// element of each pair returned is the KindID, the second element is the - /// metadata value. This list is returned sorted by the KindID. + /// Get all metadata attached to this Instruction. The first element of each + /// pair returned is the KindID, the second element is the metadata value. + /// This list is returned sorted by the KindID. void getAllMetadata(SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const { if (hasMetadata()) getAllMetadataImpl(MDs); } - /// getAllMetadataOtherThanDebugLoc - This does the same thing as - /// getAllMetadata, except that it filters out the debug location. + /// This does the same thing as getAllMetadata, except that it filters out the + /// debug location. void getAllMetadataOtherThanDebugLoc( SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const { if (hasMetadataOtherThanDebugLoc()) getAllMetadataOtherThanDebugLocImpl(MDs); } - /// getAAMetadata - Fills the AAMDNodes structure with AA metadata from - /// this instruction. When Merge is true, the existing AA metadata is - /// merged with that from this instruction providing the most-general result. + /// Fills the AAMDNodes structure with AA metadata from this instruction. + /// When Merge is true, the existing AA metadata is merged with that from this + /// instruction providing the most-general result. void getAAMetadata(AAMDNodes &N, bool Merge = false) const; - /// setMetadata - Set the metadata of the specified kind to the specified - /// node. This updates/replaces metadata if already present, or removes it if - /// Node is null. + /// Set the metadata of the specified kind to the specified node. This updates + /// or replaces metadata if already present, or removes it if Node is null. void setMetadata(unsigned KindID, MDNode *Node); void setMetadata(StringRef Kind, MDNode *Node); @@ -220,16 +214,46 @@ public: } /// @} - /// setAAMetadata - Sets the metadata on this instruction from the - /// AAMDNodes structure. + /// Sets the metadata on this instruction from the AAMDNodes structure. void setAAMetadata(const AAMDNodes &N); - /// setDebugLoc - Set the debug location information for this instruction. + /// Retrieve the raw weight values of a conditional branch or select. + /// Returns true on success with profile weights filled in. + /// Returns false if no metadata or invalid metadata was found. + bool extractProfMetadata(uint64_t &TrueVal, uint64_t &FalseVal); + + /// Retrieve total raw weight values of a branch. + /// Returns true on success with profile total weights filled in. + /// Returns false if no metadata was found. + bool extractProfTotalWeight(uint64_t &TotalVal); + + /// Set the debug location information for this instruction. void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); } - /// getDebugLoc - Return the debug location for this node as a DebugLoc. + /// Return the debug location for this node as a DebugLoc. const DebugLoc &getDebugLoc() const { return DbgLoc; } + /// Set or clear the nsw flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setHasNoUnsignedWrap(bool b = true); + + /// Set or clear the nsw flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setHasNoSignedWrap(bool b = true); + + /// Set or clear the exact flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setIsExact(bool b = true); + + /// Determine whether the no unsigned wrap flag is set. + bool hasNoUnsignedWrap() const; + + /// Determine whether the no signed wrap flag is set. + bool hasNoSignedWrap() const; + + /// Determine whether the exact flag is set. + bool isExact() const; + /// Set or clear the unsafe-algebra flag on this instruction, which must be an /// operator which supports this flag. See LangRef.html for the meaning of /// this flag. @@ -288,9 +312,16 @@ public: /// Copy I's fast-math flags void copyFastMathFlags(const Instruction *I); + /// Convenience method to copy supported wrapping, exact, and fast-math flags + /// from V to this instruction. + void copyIRFlags(const Value *V); + + /// Logical 'and' of any supported wrapping, exact, and fast-math flags of + /// V and this instruction. + void andIRFlags(const Value *V); + private: - /// hasMetadataHashEntry - Return true if we have an entry in the on-the-side - /// metadata hash. + /// Return true if we have an entry in the on-the-side metadata hash. bool hasMetadataHashEntry() const { return (getSubclassDataFromValue() & HasMetadataBit) != 0; } @@ -302,6 +333,7 @@ private: getAllMetadataImpl(SmallVectorImpl<std::pair<unsigned, MDNode *>> &) const; void getAllMetadataOtherThanDebugLocImpl( SmallVectorImpl<std::pair<unsigned, MDNode *>> &) const; + /// Clear all hashtable-based metadata from this instruction. void clearMetadataHashEntries(); public: //===--------------------------------------------------------------------===// @@ -309,7 +341,7 @@ public: //===--------------------------------------------------------------------===// - /// isAssociative - Return true if the instruction is associative: + /// Return true if the instruction is associative: /// /// Associative operators satisfy: x op (y op z) === (x op y) op z /// @@ -318,7 +350,7 @@ public: bool isAssociative() const; static bool isAssociative(unsigned op); - /// isCommutative - Return true if the instruction is commutative: + /// Return true if the instruction is commutative: /// /// Commutative operators satisfy: (x op y) === (y op x) /// @@ -328,7 +360,7 @@ public: bool isCommutative() const { return isCommutative(getOpcode()); } static bool isCommutative(unsigned op); - /// isIdempotent - Return true if the instruction is idempotent: + /// Return true if the instruction is idempotent: /// /// Idempotent operators satisfy: x op x === x /// @@ -337,7 +369,7 @@ public: bool isIdempotent() const { return isIdempotent(getOpcode()); } static bool isIdempotent(unsigned op); - /// isNilpotent - Return true if the instruction is nilpotent: + /// Return true if the instruction is nilpotent: /// /// Nilpotent operators satisfy: x op x === Id, /// @@ -349,47 +381,50 @@ public: bool isNilpotent() const { return isNilpotent(getOpcode()); } static bool isNilpotent(unsigned op); - /// mayWriteToMemory - Return true if this instruction may modify memory. - /// + /// Return true if this instruction may modify memory. bool mayWriteToMemory() const; - /// mayReadFromMemory - Return true if this instruction may read memory. - /// + /// Return true if this instruction may read memory. bool mayReadFromMemory() const; - /// mayReadOrWriteMemory - Return true if this instruction may read or - /// write memory. - /// + /// Return true if this instruction may read or write memory. bool mayReadOrWriteMemory() const { return mayReadFromMemory() || mayWriteToMemory(); } - /// isAtomic - Return true if this instruction has an - /// AtomicOrdering of unordered or higher. - /// + /// Return true if this instruction has an AtomicOrdering of unordered or + /// higher. bool isAtomic() const; - /// mayThrow - Return true if this instruction may throw an exception. - /// + /// Return true if this instruction may throw an exception. bool mayThrow() const; - /// mayReturn - Return true if this is a function that may return. - /// this is true for all normal instructions. The only exception - /// is functions that are marked with the 'noreturn' attribute. - /// - bool mayReturn() const; + /// Return true if this instruction behaves like a memory fence: it can load + /// or store to memory location without being given a memory location. + bool isFenceLike() const { + switch (getOpcode()) { + default: + return false; + // This list should be kept in sync with the list in mayWriteToMemory for + // all opcodes which don't have a memory location. + case Instruction::Fence: + case Instruction::CatchPad: + case Instruction::CatchRet: + case Instruction::Call: + case Instruction::Invoke: + return true; + } + } - /// mayHaveSideEffects - Return true if the instruction may have side effects. + /// Return true if the instruction may have side effects. /// /// Note that this does not consider malloc and alloca to have side /// effects because the newly allocated memory is completely invisible to /// instructions which don't use the returned value. For cases where this /// matters, isSafeToSpeculativelyExecute may be more appropriate. - bool mayHaveSideEffects() const { - return mayWriteToMemory() || mayThrow() || !mayReturn(); - } + bool mayHaveSideEffects() const { return mayWriteToMemory() || mayThrow(); } - /// \brief Return true if the instruction is a variety of EH-block. + /// Return true if the instruction is a variety of EH-block. bool isEHPad() const { switch (getOpcode()) { case Instruction::CatchSwitch: @@ -402,21 +437,21 @@ public: } } - /// clone() - Create a copy of 'this' instruction that is identical in all - /// ways except the following: + /// Create a copy of 'this' instruction that is identical in all ways except + /// the following: /// * The instruction has no parent /// * The instruction has no name /// Instruction *clone() const; - /// isIdenticalTo - Return true if the specified instruction is exactly - /// identical to the current one. This means that all operands match and any - /// extra information (e.g. load is volatile) agree. + /// Return true if the specified instruction is exactly identical to the + /// current one. This means that all operands match and any extra information + /// (e.g. load is volatile) agree. bool isIdenticalTo(const Instruction *I) const; - /// isIdenticalToWhenDefined - This is like isIdenticalTo, except that it - /// ignores the SubclassOptionalData flags, which specify conditions - /// under which the instruction's result is undefined. + /// This is like isIdenticalTo, except that it ignores the + /// SubclassOptionalData flags, which specify conditions under which the + /// instruction's result is undefined. bool isIdenticalToWhenDefined(const Instruction *I) const; /// When checking for operation equivalence (using isSameOperationAs) it is @@ -439,10 +474,9 @@ public: /// @brief Determine if one instruction is the same operation as another. bool isSameOperationAs(const Instruction *I, unsigned flags = 0) const; - /// isUsedOutsideOfBlock - Return true if there are any uses of this - /// instruction in blocks other than the specified block. Note that PHI nodes - /// are considered to evaluate their operands in the corresponding predecessor - /// block. + /// Return true if there are any uses of this instruction in blocks other than + /// the specified block. Note that PHI nodes are considered to evaluate their + /// operands in the corresponding predecessor block. bool isUsedOutsideOfBlock(const BasicBlock *BB) const; diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 28e1fd90fdf6..be077725f7bc 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -25,6 +25,7 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" +#include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/ErrorHandling.h" #include <iterator> @@ -36,38 +37,11 @@ class ConstantRange; class DataLayout; class LLVMContext; -enum AtomicOrdering { - NotAtomic = 0, - Unordered = 1, - Monotonic = 2, - // Consume = 3, // Not specified yet. - Acquire = 4, - Release = 5, - AcquireRelease = 6, - SequentiallyConsistent = 7 -}; - enum SynchronizationScope { SingleThread = 0, CrossThread = 1 }; -/// Returns true if the ordering is at least as strong as acquire -/// (i.e. acquire, acq_rel or seq_cst) -inline bool isAtLeastAcquire(AtomicOrdering Ord) { - return (Ord == Acquire || - Ord == AcquireRelease || - Ord == SequentiallyConsistent); -} - -/// Returns true if the ordering is at least as strong as release -/// (i.e. release, acq_rel or seq_cst) -inline bool isAtLeastRelease(AtomicOrdering Ord) { -return (Ord == Release || - Ord == AcquireRelease || - Ord == SequentiallyConsistent); -} - //===----------------------------------------------------------------------===// // AllocaInst Class //===----------------------------------------------------------------------===// @@ -152,6 +126,18 @@ public: (V ? 32 : 0)); } + /// \brief Return true if this alloca is used as a swifterror argument to a + /// call. + bool isSwiftError() const { + return getSubclassDataFromInstruction() & 64; + } + + /// \brief Specify whether this alloca is used to represent a swifterror. + void setSwiftError(bool V) { + setInstructionSubclassData((getSubclassDataFromInstruction() & ~64) | + (V ? 64 : 0)); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Alloca); @@ -257,7 +243,7 @@ public: /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - (Ordering << 7)); + ((unsigned)Ordering << 7)); } SynchronizationScope getSynchScope() const { @@ -280,7 +266,9 @@ public: bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { - return getOrdering() <= Unordered && !isVolatile(); + return (getOrdering() == AtomicOrdering::NotAtomic || + getOrdering() == AtomicOrdering::Unordered) && + !isVolatile(); } Value *getPointerOperand() { return getOperand(0); } @@ -378,7 +366,7 @@ public: /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - (Ordering << 7)); + ((unsigned)Ordering << 7)); } SynchronizationScope getSynchScope() const { @@ -401,7 +389,9 @@ public: bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { - return getOrdering() <= Unordered && !isVolatile(); + return (getOrdering() == AtomicOrdering::NotAtomic || + getOrdering() == AtomicOrdering::Unordered) && + !isVolatile(); } Value *getValueOperand() { return getOperand(0); } @@ -477,7 +467,7 @@ public: /// AcquireRelease, or SequentiallyConsistent. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | - (Ordering << 1)); + ((unsigned)Ordering << 1)); } SynchronizationScope getSynchScope() const { @@ -572,17 +562,17 @@ public: /// Set the ordering constraint on this cmpxchg. void setSuccessOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x1c) | - (Ordering << 2)); + ((unsigned)Ordering << 2)); } void setFailureOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0xe0) | - (Ordering << 5)); + ((unsigned)Ordering << 5)); } /// Specify whether this cmpxchg is atomic and orders other operations with @@ -634,15 +624,16 @@ public: static AtomicOrdering getStrongestFailureOrdering(AtomicOrdering SuccessOrdering) { switch (SuccessOrdering) { - default: llvm_unreachable("invalid cmpxchg success ordering"); - case Release: - case Monotonic: - return Monotonic; - case AcquireRelease: - case Acquire: - return Acquire; - case SequentiallyConsistent: - return SequentiallyConsistent; + default: + llvm_unreachable("invalid cmpxchg success ordering"); + case AtomicOrdering::Release: + case AtomicOrdering::Monotonic: + return AtomicOrdering::Monotonic; + case AtomicOrdering::AcquireRelease: + case AtomicOrdering::Acquire: + return AtomicOrdering::Acquire; + case AtomicOrdering::SequentiallyConsistent: + return AtomicOrdering::SequentiallyConsistent; } } @@ -758,10 +749,10 @@ public: /// Set the ordering constraint on this RMW. void setOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "atomicrmw instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 2)) | - (Ordering << 2)); + ((unsigned)Ordering << 2)); } /// Specify whether this RMW orders other operations with respect to all @@ -1490,9 +1481,29 @@ public: Value *AllocSize, Value *ArraySize = nullptr, Function* MallocF = nullptr, const Twine &Name = ""); + static Instruction *CreateMalloc(Instruction *InsertBefore, + Type *IntPtrTy, Type *AllocTy, + Value *AllocSize, Value *ArraySize = nullptr, + ArrayRef<OperandBundleDef> Bundles = None, + Function* MallocF = nullptr, + const Twine &Name = ""); + static Instruction *CreateMalloc(BasicBlock *InsertAtEnd, + Type *IntPtrTy, Type *AllocTy, + Value *AllocSize, Value *ArraySize = nullptr, + ArrayRef<OperandBundleDef> Bundles = None, + Function* MallocF = nullptr, + const Twine &Name = ""); /// CreateFree - Generate the IR for a call to the builtin free function. - static Instruction* CreateFree(Value* Source, Instruction *InsertBefore); - static Instruction* CreateFree(Value* Source, BasicBlock *InsertAtEnd); + static Instruction *CreateFree(Value *Source, + Instruction *InsertBefore); + static Instruction *CreateFree(Value *Source, + BasicBlock *InsertAtEnd); + static Instruction *CreateFree(Value *Source, + ArrayRef<OperandBundleDef> Bundles, + Instruction *InsertBefore); + static Instruction *CreateFree(Value *Source, + ArrayRef<OperandBundleDef> Bundles, + BasicBlock *InsertAtEnd); ~CallInst() override; @@ -1586,6 +1597,10 @@ public: return getOperandUse(i); } + /// If one of the arguments has the 'returned' attribute, return its + /// operand value. Otherwise, return nullptr. + Value *getReturnedArgOperand() const; + /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { @@ -1607,13 +1622,22 @@ public: void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); /// addAttribute - adds the attribute to the list of attributes. void addAttribute(unsigned i, StringRef Kind, StringRef Value); + /// addAttribute - adds the attribute to the list of attributes. + void addAttribute(unsigned i, Attribute Attr); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute::AttrKind Kind); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, StringRef Kind); + /// removeAttribute - removes the attribute from the list of attributes. - void removeAttribute(unsigned i, Attribute attr); + void removeAttribute(unsigned i, Attribute Attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); @@ -1623,19 +1647,25 @@ public: void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - assert(A != Attribute::NoBuiltin && + bool hasFnAttr(Attribute::AttrKind Kind) const { + assert(Kind != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); - return hasFnAttrImpl(A); + return hasFnAttrImpl(Kind); } /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(StringRef A) const { - return hasFnAttrImpl(A); + bool hasFnAttr(StringRef Kind) const { + return hasFnAttrImpl(Kind); } /// \brief Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, StringRef Kind) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. @@ -1650,7 +1680,7 @@ public: /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { @@ -1713,6 +1743,14 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } + /// \brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { @@ -1745,6 +1783,10 @@ public: void setConvergent() { addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); } + void setNotConvergent() { + removeAttribute(AttributeSet::FunctionIndex, + Attribute::get(getContext(), Attribute::Convergent)); + } /// \brief Determine if the call returns a structure through first /// pointer argument. @@ -1906,6 +1948,10 @@ public: Value *getTrueValue() { return Op<1>(); } Value *getFalseValue() { return Op<2>(); } + void setCondition(Value *V) { Op<0>() = V; } + void setTrueValue(Value *V) { Op<1>() = V; } + void setFalseValue(Value *V) { Op<2>() = V; } + /// areInvalidOperands - Return a string if the specified operands are invalid /// for a select operation, otherwise return null. static const char *areInvalidOperands(Value *Cond, Value *True, Value *False); @@ -2619,6 +2665,11 @@ public: /// same value, return the value, otherwise return null. Value *hasConstantValue() const; + /// hasConstantOrUndefValue - Whether the specified PHI node always merges + /// together the same value, assuming undefs are equal to a unique + /// non-undef value. + bool hasConstantOrUndefValue() const; + /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::PHI; @@ -2928,7 +2979,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BranchInst, Value) //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- -/// SwitchInst - Multiway switch +/// Multiway switch /// class SwitchInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; @@ -2944,17 +2995,17 @@ class SwitchInst : public TerminatorInst { void *operator new(size_t s) { return User::operator new(s); } - /// SwitchInst ctor - Create a new switch instruction, specifying a value to - /// switch on and a default destination. The number of additional cases can - /// be specified here to make memory allocation more efficient. This - /// constructor can also autoinsert before another instruction. + /// Create a new switch instruction, specifying a value to switch on and a + /// default destination. The number of additional cases can be specified here + /// to make memory allocation more efficient. This constructor can also + /// auto-insert before another instruction. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore); - /// SwitchInst ctor - Create a new switch instruction, specifying a value to - /// switch on and a default destination. The number of additional cases can - /// be specified here to make memory allocation more efficient. This - /// constructor also autoinserts at the end of the specified BasicBlock. + /// Create a new switch instruction, specifying a value to switch on and a + /// default destination. The number of additional cases can be specified here + /// to make memory allocation more efficient. This constructor also + /// auto-inserts at the end of the specified BasicBlock. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, BasicBlock *InsertAtEnd); @@ -3104,40 +3155,40 @@ public: setOperand(1, reinterpret_cast<Value*>(DefaultCase)); } - /// getNumCases - return the number of 'cases' in this switch instruction, - /// except the default case + /// Return the number of 'cases' in this switch instruction, excluding the + /// default case. unsigned getNumCases() const { return getNumOperands()/2 - 1; } - /// Returns a read/write iterator that points to the first - /// case in SwitchInst. + /// Returns a read/write iterator that points to the first case in the + /// SwitchInst. CaseIt case_begin() { return CaseIt(this, 0); } - /// Returns a read-only iterator that points to the first - /// case in the SwitchInst. + /// Returns a read-only iterator that points to the first case in the + /// SwitchInst. ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); } - /// Returns a read/write iterator that points one past the last - /// in the SwitchInst. + /// Returns a read/write iterator that points one past the last in the + /// SwitchInst. CaseIt case_end() { return CaseIt(this, getNumCases()); } - /// Returns a read-only iterator that points one past the last - /// in the SwitchInst. + /// Returns a read-only iterator that points one past the last in the + /// SwitchInst. ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); } - /// cases - iteration adapter for range-for loops. + /// Iteration adapter for range-for loops. iterator_range<CaseIt> cases() { return make_range(case_begin(), case_end()); } - /// cases - iteration adapter for range-for loops. + /// Constant iteration adapter for range-for loops. iterator_range<ConstCaseIt> cases() const { return make_range(case_begin(), case_end()); } @@ -3154,10 +3205,10 @@ public: return ConstCaseIt(this, DefaultPseudoIndex); } - /// findCaseValue - Search all of the case values for the specified constant. - /// If it is explicitly handled, return the case iterator of it, otherwise - /// return default case iterator to indicate - /// that it is handled by the default handler. + /// Search all of the case values for the specified constant. If it is + /// explicitly handled, return the case iterator of it, otherwise return + /// 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) @@ -3171,8 +3222,8 @@ public: return case_default(); } - /// findCaseDest - Finds the unique case value for a given successor. Returns - /// null if the successor is not found, not unique, or is the default case. + /// 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; @@ -3186,15 +3237,15 @@ public: return CI; } - /// addCase - Add an entry to the switch instruction... + /// Add an entry to the switch instruction. /// Note: /// This action invalidates case_end(). Old case_end() iterator will /// point to the added case. void addCase(ConstantInt *OnVal, BasicBlock *Dest); - /// removeCase - This method removes the specified case and its successor - /// from the switch instruction. Note that this operation may reorder the - /// remaining cases at index idx and above. + /// This method removes the specified case and its successor from the switch + /// instruction. Note that this operation may reorder the remaining cases at + /// index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, /// including the case_end() iterator. @@ -3519,6 +3570,10 @@ public: return getOperandUse(i); } + /// If one of the arguments has the 'returned' attribute, return its + /// operand value. Otherwise, return nullptr. + Value *getReturnedArgOperand() const; + /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { @@ -3539,10 +3594,19 @@ public: void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); + + /// addAttribute - adds the attribute to the list of attributes. + void addAttribute(unsigned i, Attribute Attr); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute::AttrKind Kind); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, StringRef Kind); /// removeAttribute - removes the attribute from the list of attributes. - void removeAttribute(unsigned i, Attribute attr); + void removeAttribute(unsigned i, Attribute Attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); @@ -3552,19 +3616,25 @@ public: void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - assert(A != Attribute::NoBuiltin && + bool hasFnAttr(Attribute::AttrKind Kind) const { + assert(Kind != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); - return hasFnAttrImpl(A); + return hasFnAttrImpl(Kind); } /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(StringRef A) const { - return hasFnAttrImpl(A); + bool hasFnAttr(StringRef Kind) const { + return hasFnAttrImpl(Kind); } /// \brief Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, StringRef Kind) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. @@ -3580,7 +3650,7 @@ public: /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { @@ -3637,6 +3707,14 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } + /// \brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + } + /// @brief Determine if the call access memmory only using it's pointer /// arguments. bool onlyAccessesArgMemory() const { @@ -3664,6 +3742,16 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); } + /// \brief Determine if the invoke is convergent + bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } + void setConvergent() { + addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + } + void setNotConvergent() { + removeAttribute(AttributeSet::FunctionIndex, + Attribute::get(getContext(), Attribute::Convergent)); + } + /// \brief Determine if the call returns a structure through first /// pointer argument. bool hasStructRetAttr() const { @@ -4160,7 +4248,9 @@ public: } unsigned getNumSuccessors() const { return 1; } - Value *getParentPad() const { + /// Get the parentPad of this catchret's catchpad's catchswitch. + /// The successor block is implicitly a member of this funclet. + Value *getCatchSwitchParentPad() const { return getCatchPad()->getCatchSwitch()->getParentPad(); } @@ -4826,6 +4916,31 @@ public: static inline bool classof(const Value *V) { return isa<Instruction>(V) && classof(cast<Instruction>(V)); } + + /// \brief Gets the pointer operand. + Value *getPointerOperand() { + return getOperand(0); + } + + /// \brief Gets the pointer operand. + const Value *getPointerOperand() const { + return getOperand(0); + } + + /// \brief Gets the operand index of the pointer operand. + static unsigned getPointerOperandIndex() { + return 0U; + } + + /// \brief Returns the address space of the pointer operand. + unsigned getSrcAddressSpace() const { + return getPointerOperand()->getType()->getPointerAddressSpace(); + } + + /// \brief Returns the address space of the result. + unsigned getDestAddressSpace() const { + return getType()->getPointerAddressSpace(); + } }; } // End llvm namespace diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index 169bcc021984..52044e0a0cc8 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -31,16 +31,15 @@ #include "llvm/IR/Metadata.h" namespace llvm { - /// IntrinsicInst - A useful wrapper class for inspecting calls to intrinsic - /// functions. This allows the standard isa/dyncast/cast functionality to - /// work with calls to intrinsic functions. + /// A wrapper class for inspecting calls to intrinsic functions. + /// This allows the standard isa/dyncast/cast functionality to work with calls + /// to intrinsic functions. class IntrinsicInst : public CallInst { IntrinsicInst() = delete; IntrinsicInst(const IntrinsicInst&) = delete; void operator=(const IntrinsicInst&) = delete; public: - /// getIntrinsicID - Return the intrinsic ID of this intrinsic. - /// + /// Return the intrinsic ID of this intrinsic. Intrinsic::ID getIntrinsicID() const { return getCalledFunction()->getIntrinsicID(); } @@ -56,10 +55,13 @@ namespace llvm { } }; - /// DbgInfoIntrinsic - This is the common base class for debug info intrinsics - /// + /// This is the common base class for debug info intrinsics. class DbgInfoIntrinsic : public IntrinsicInst { public: + /// Get the location corresponding to the variable referenced by the debug + /// info intrinsic. Depending on the intrinsic, this could be the + /// variable's value or its address. + Value *getVariableLocation(bool AllowNullOp = true) const; // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const IntrinsicInst *I) { @@ -73,15 +75,12 @@ namespace llvm { static inline bool classof(const Value *V) { return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); } - - static Value *StripCast(Value *C); }; - /// DbgDeclareInst - This represents the llvm.dbg.declare instruction. - /// + /// This represents the llvm.dbg.declare instruction. class DbgDeclareInst : public DbgInfoIntrinsic { public: - Value *getAddress() const; + Value *getAddress() const { return getVariableLocation(); } DILocalVariable *getVariable() const { return cast<DILocalVariable>(getRawVariable()); } @@ -105,12 +104,12 @@ namespace llvm { } }; - /// DbgValueInst - This represents the llvm.dbg.value instruction. - /// + /// This represents the llvm.dbg.value instruction. class DbgValueInst : public DbgInfoIntrinsic { public: - const Value *getValue() const; - Value *getValue(); + Value *getValue() const { + return getVariableLocation(/* AllowNullOp = */ false); + } uint64_t getOffset() const { return cast<ConstantInt>( const_cast<Value*>(getArgOperand(1)))->getZExtValue(); @@ -138,8 +137,7 @@ namespace llvm { } }; - /// MemIntrinsic - This is the common base class for memset/memcpy/memmove. - /// + /// This is the common base class for memset/memcpy/memmove. class MemIntrinsic : public IntrinsicInst { public: Value *getRawDest() const { return const_cast<Value*>(getArgOperand(0)); } @@ -169,13 +167,12 @@ namespace llvm { return cast<PointerType>(getRawDest()->getType())->getAddressSpace(); } - /// getDest - This is just like getRawDest, but it strips off any cast + /// This is just like getRawDest, but it strips off any cast /// instructions that feed it, giving the original input. The returned /// value is guaranteed to be a pointer. Value *getDest() const { return getRawDest()->stripPointerCasts(); } - /// set* - Set the specified arguments of the instruction. - /// + /// Set the specified arguments of the instruction. void setDest(Value *Ptr) { assert(getRawDest()->getType() == Ptr->getType() && "setDest called with pointer of wrong type!"); @@ -215,12 +212,10 @@ namespace llvm { } }; - /// MemSetInst - This class wraps the llvm.memset intrinsic. - /// + /// This class wraps the llvm.memset intrinsic. class MemSetInst : public MemIntrinsic { public: - /// get* - Return the arguments to the instruction. - /// + /// Return the arguments to the instruction. Value *getValue() const { return const_cast<Value*>(getArgOperand(1)); } const Use &getValueUse() const { return getArgOperandUse(1); } Use &getValueUse() { return getArgOperandUse(1); } @@ -240,17 +235,15 @@ namespace llvm { } }; - /// MemTransferInst - This class wraps the llvm.memcpy/memmove intrinsics. - /// + /// This class wraps the llvm.memcpy/memmove intrinsics. class MemTransferInst : public MemIntrinsic { public: - /// get* - Return the arguments to the instruction. - /// + /// Return the arguments to the instruction. Value *getRawSource() const { return const_cast<Value*>(getArgOperand(1)); } const Use &getRawSourceUse() const { return getArgOperandUse(1); } Use &getRawSourceUse() { return getArgOperandUse(1); } - /// getSource - This is just like getRawSource, but it strips off any cast + /// This is just like getRawSource, but it strips off any cast /// instructions that feed it, giving the original input. The returned /// value is guaranteed to be a pointer. Value *getSource() const { return getRawSource()->stripPointerCasts(); } @@ -276,8 +269,7 @@ namespace llvm { }; - /// MemCpyInst - This class wraps the llvm.memcpy intrinsic. - /// + /// This class wraps the llvm.memcpy intrinsic. class MemCpyInst : public MemTransferInst { public: // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -289,8 +281,7 @@ namespace llvm { } }; - /// MemMoveInst - This class wraps the llvm.memmove intrinsic. - /// + /// This class wraps the llvm.memmove intrinsic. class MemMoveInst : public MemTransferInst { public: // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -302,8 +293,7 @@ namespace llvm { } }; - /// VAStartInst - This represents the llvm.va_start intrinsic. - /// + /// This represents the llvm.va_start intrinsic. class VAStartInst : public IntrinsicInst { public: static inline bool classof(const IntrinsicInst *I) { @@ -316,8 +306,7 @@ namespace llvm { Value *getArgList() const { return const_cast<Value*>(getArgOperand(0)); } }; - /// VAEndInst - This represents the llvm.va_end intrinsic. - /// + /// This represents the llvm.va_end intrinsic. class VAEndInst : public IntrinsicInst { public: static inline bool classof(const IntrinsicInst *I) { @@ -330,8 +319,7 @@ namespace llvm { Value *getArgList() const { return const_cast<Value*>(getArgOperand(0)); } }; - /// VACopyInst - This represents the llvm.va_copy intrinsic. - /// + /// This represents the llvm.va_copy intrinsic. class VACopyInst : public IntrinsicInst { public: static inline bool classof(const IntrinsicInst *I) { diff --git a/include/llvm/IR/Intrinsics.h b/include/llvm/IR/Intrinsics.h index 314e2aaecf4b..7a87c2167710 100644 --- a/include/llvm/IR/Intrinsics.h +++ b/include/llvm/IR/Intrinsics.h @@ -17,6 +17,8 @@ #define LLVM_IR_INTRINSICS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include <string> namespace llvm { @@ -69,6 +71,13 @@ namespace Intrinsic { /// the intrinsic. Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> Tys = None); + /// Looks up Name in NameTable via binary search. NameTable must be sorted + /// and all entries must start with "llvm.". If NameTable contains an exact + /// match for Name or a prefix of Name followed by a dot, its index in + /// NameTable is returned. Otherwise, -1 is returned. + int lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable, + StringRef Name); + /// Map a GCC builtin name to an intrinsic ID. ID getIntrinsicForGCCBuiltin(const char *Prefix, const char *BuiltinName); @@ -126,6 +135,25 @@ namespace Intrinsic { /// of IITDescriptors. void getIntrinsicInfoTableEntries(ID id, SmallVectorImpl<IITDescriptor> &T); + /// Match the specified type (which comes from an intrinsic argument or return + /// value) with the type constraints specified by the .td file. If the given + /// type is an overloaded type it is pushed to the ArgTys vector. + /// + /// Returns false if the given type matches with the constraints, true + /// otherwise. + bool matchIntrinsicType(Type *Ty, ArrayRef<IITDescriptor> &Infos, + SmallVectorImpl<Type*> &ArgTys); + + /// Verify if the intrinsic has variable arguments. This method is intended to + /// be called after all the fixed arguments have been matched first. + /// + /// This method returns true on error. + bool matchIntrinsicVarArg(bool isVarArg, ArrayRef<IITDescriptor> &Infos); + + // Checks if the intrinsic name matches with its signature and if not + // returns the declaration with the same signature and remangled name. + llvm::Optional<Function*> remangleIntrinsicFunction(Function *F); + } // End Intrinsic namespace } // End llvm namespace diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index f67029ab56e3..5ece731fa143 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -19,9 +19,7 @@ include "llvm/CodeGen/ValueTypes.td" class IntrinsicProperty; -// Intr*Mem - Memory properties. An intrinsic is allowed to have at most one of -// these properties set. They are listed from the most aggressive (best to use -// if correct) to the least aggressive. If no property is set, the worst case +// Intr*Mem - Memory properties. If no property is set, the worst case // is assumed (it may read and write any memory it can get access to and it may // have other side effects). @@ -29,20 +27,21 @@ class IntrinsicProperty; // effects. It may be CSE'd deleted if dead, etc. def IntrNoMem : IntrinsicProperty; -// IntrReadArgMem - This intrinsic reads only from memory that one of its -// pointer-typed arguments points to, but may read an unspecified amount. -def IntrReadArgMem : IntrinsicProperty; - -// IntrReadMem - This intrinsic reads from unspecified memory, so it cannot be -// moved across stores. However, it can be reordered otherwise and can be -// deleted if dead. +// IntrReadMem - This intrinsic only reads from memory. It does not write to +// memory and has no other side effects. Therefore, it cannot be moved across +// potentially aliasing stores. However, it can be reordered otherwise and can +// be deleted if dead. def IntrReadMem : IntrinsicProperty; -// IntrReadWriteArgMem - This intrinsic reads and writes only from memory that -// one of its arguments points to, but may access an unspecified amount. The -// reads and writes may be volatile, but except for this it has no other side -// effects. -def IntrReadWriteArgMem : IntrinsicProperty; +// IntrWriteMem - This intrinsic only writes to memory, but does not read from +// memory, and has no other side effects. This means dead stores before calls +// to this intrinsics may be removed. +def IntrWriteMem : IntrinsicProperty; + +// IntrArgMemOnly - This intrinsic only accesses memory that its pointer-typed +// argument(s) points to, but may access an unspecified amount. Other than +// reads from and (possibly volatile) writes to memory, it has no side effects. +def IntrArgMemOnly : IntrinsicProperty; // Commutative - This intrinsic is commutative: X op Y == Y op X. def Commutative : IntrinsicProperty; @@ -55,12 +54,24 @@ class NoCapture<int argNo> : IntrinsicProperty { int ArgNo = argNo; } +// Returned - The specified argument is always the return value of the +// intrinsic. +class Returned<int argNo> : IntrinsicProperty { + int ArgNo = argNo; +} + // ReadOnly - The specified argument pointer is not written to through the // pointer by the intrinsic. class ReadOnly<int argNo> : IntrinsicProperty { int ArgNo = argNo; } +// WriteOnly - The intrinsic does not read memory through the specified +// argument pointer. +class WriteOnly<int argNo> : IntrinsicProperty { + int ArgNo = argNo; +} + // ReadNone - The specified argument pointer is not dereferenced by the // intrinsic. class ReadNone<int argNo> : IntrinsicProperty { @@ -240,7 +251,7 @@ class Intrinsic<list<LLVMType> ret_types, string TargetPrefix = ""; // Set to a prefix for target-specific intrinsics. list<LLVMType> RetTypes = ret_types; list<LLVMType> ParamTypes = param_types; - list<IntrinsicProperty> Properties = properties; + list<IntrinsicProperty> IntrProperties = properties; bit isTarget = 0; } @@ -271,10 +282,10 @@ def int_gcroot : Intrinsic<[], [llvm_ptrptr_ty, llvm_ptr_ty]>; def int_gcread : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_ptrptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_gcwrite : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptrptr_ty], - [IntrReadWriteArgMem, NoCapture<1>, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<1>, NoCapture<2>]>; //===--------------------- Code Generator Intrinsics ----------------------===// // @@ -306,13 +317,16 @@ def int_stackrestore : Intrinsic<[], [llvm_ptr_ty]>, def int_get_dynamic_area_offset : Intrinsic<[llvm_anyint_ty]>; -// IntrReadWriteArgMem is more pessimistic than strictly necessary for prefetch, +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], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; @@ -324,8 +338,7 @@ def int_assume : Intrinsic<[], [llvm_i1_ty], []>; // Stack Protector Intrinsic - The stackprotector intrinsic writes the stack // guard to the correct place on the stack frame. def int_stackprotector : Intrinsic<[], [llvm_ptr_ty, llvm_ptrptr_ty], []>; -def int_stackprotectorcheck : Intrinsic<[], [llvm_ptrptr_ty], - [IntrReadWriteArgMem]>; +def int_stackguard : Intrinsic<[llvm_ptr_ty], [], []>; // A counter increment for instrumentation based profiling. def int_instrprof_increment : Intrinsic<[], @@ -347,19 +360,19 @@ def int_instrprof_value_profile : Intrinsic<[], def int_memcpy : Intrinsic<[], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>, NoCapture<1>, - ReadOnly<1>]>; + [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, + WriteOnly<0>, ReadOnly<1>]>; def int_memmove : Intrinsic<[], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>, NoCapture<1>, + [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, ReadOnly<1>]>; def int_memset : Intrinsic<[], [llvm_anyptr_ty, llvm_i8_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>; -let Properties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem] in { def int_fma : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>; @@ -382,8 +395,6 @@ let Properties = [IntrNoMem] in { def int_exp : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_exp2 : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_fabs : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; - def int_minnum : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>]>; - def int_maxnum : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>]>; def int_copysign : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>]>; def int_floor : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; @@ -396,6 +407,13 @@ let Properties = [IntrNoMem] in { [IntrNoMem]>; } +def int_minnum : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative] +>; +def int_maxnum : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative] +>; + // NOTE: these are internal interfaces. def int_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; def int_longjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>; @@ -416,7 +434,7 @@ def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, // // None of these intrinsics accesses memory at all. -let Properties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem] in { def int_bswap: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>; def int_ctpop: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>; def int_ctlz : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_i1_ty]>; @@ -430,7 +448,7 @@ let Properties = [IntrNoMem] in { // None of these intrinsics accesses memory at all...but that doesn't mean the // optimizers can change them aggressively. Special handling needed in a few // places. -let Properties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem] in { def int_dbg_declare : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, @@ -467,7 +485,7 @@ def int_eh_unwind_init: Intrinsic<[]>, def int_eh_dwarf_cfa : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty]>; -let Properties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem] in { def int_eh_sjlj_lsda : Intrinsic<[llvm_ptr_ty]>; def int_eh_sjlj_callsite : Intrinsic<[], [llvm_i32_ty]>; } @@ -495,11 +513,11 @@ def int_annotation : Intrinsic<[llvm_anyint_ty], // def int_init_trampoline : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>, + [IntrArgMemOnly, NoCapture<0>]>, GCCBuiltin<"__builtin_init_trampoline">; def int_adjust_trampoline : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], - [IntrReadArgMem]>, + [IntrReadMem, IntrArgMemOnly]>, GCCBuiltin<"__builtin_adjust_trampoline">; //===------------------------ Overflow Intrinsics -------------------------===// @@ -531,17 +549,17 @@ def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], // def int_lifetime_start : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_lifetime_end : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_end : Intrinsic<[], [llvm_descriptor_ty, llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], @@ -588,11 +606,19 @@ def int_trap : Intrinsic<[], [], [IntrNoReturn]>, def int_debugtrap : Intrinsic<[]>, GCCBuiltin<"__builtin_debugtrap">; +// Support for dynamic deoptimization (or de-specialization) +def int_experimental_deoptimize : Intrinsic<[llvm_any_ty], [llvm_vararg_ty], + [Throws]>; + +// Support for speculative runtime guards +def int_experimental_guard : Intrinsic<[], [llvm_i1_ty, llvm_vararg_ty], + [Throws]>; + // NOP: calls/invokes to this intrinsic are removed by codegen def int_donothing : Intrinsic<[], [], [IntrNoMem]>; // Intrisics to support half precision floating point format -let Properties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem] in { def int_convert_to_fp16 : Intrinsic<[llvm_i16_ty], [llvm_anyfloat_ty]>; def int_convert_from_fp16 : Intrinsic<[llvm_anyfloat_ty], [llvm_i16_ty]>; } @@ -627,31 +653,40 @@ def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], //===-------------------------- Masked Intrinsics -------------------------===// // -def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, LLVMPointerTo<0>, +def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, + LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_masked_load : Intrinsic<[llvm_anyvector_ty], - [LLVMPointerTo<0>, llvm_i32_ty, + [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_masked_gather: Intrinsic<[llvm_anyvector_ty], [LLVMVectorOfPointersToElt<0>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_masked_scatter: Intrinsic<[], [llvm_anyvector_ty, LLVMVectorOfPointersToElt<0>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; + +// Test whether a pointer is associated with a type metadata identifier. +def int_type_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], + [IntrNoMem]>; + +// Safely loads a function pointer from a virtual table pointer using type metadata. +def int_type_checked_load : Intrinsic<[llvm_ptr_ty, llvm_i1_ty], + [llvm_ptr_ty, llvm_i32_ty, llvm_metadata_ty], + [IntrNoMem]>; -// Intrinsics to support bit sets. -def int_bitset_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], - [IntrNoMem]>; +def int_load_relative: Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_anyint_ty], + [IntrReadMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // Target-specific intrinsics diff --git a/include/llvm/IR/IntrinsicsAArch64.td b/include/llvm/IR/IntrinsicsAArch64.td index 578f259aae14..d1e331775b7b 100644 --- a/include/llvm/IR/IntrinsicsAArch64.td +++ b/include/llvm/IR/IntrinsicsAArch64.td @@ -13,9 +13,6 @@ let TargetPrefix = "aarch64" in { -def int_aarch64_thread_pointer : GCCBuiltin<"__builtin_thread_pointer">, - Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; - def int_aarch64_ldxr : Intrinsic<[llvm_i64_ty], [llvm_anyptr_ty]>; def int_aarch64_ldaxr : Intrinsic<[llvm_i64_ty], [llvm_anyptr_ty]>; def int_aarch64_stxr : Intrinsic<[llvm_i32_ty], [llvm_i64_ty, llvm_anyptr_ty]>; @@ -159,7 +156,7 @@ let TargetPrefix = "aarch64" in { // All intrinsics start with "llvm.aarch64.". // Arithmetic ops -let Properties = [IntrNoMem] in { +let TargetPrefix = "aarch64", IntrProperties = [IntrNoMem] in { // Vector Add Across Lanes def int_aarch64_neon_saddv : AdvSIMD_1VectorArg_Int_Across_Intrinsic; def int_aarch64_neon_uaddv : AdvSIMD_1VectorArg_Int_Across_Intrinsic; @@ -212,7 +209,7 @@ let Properties = [IntrNoMem] in { // Vector Extending Multiply def int_aarch64_neon_fmulx : AdvSIMD_2FloatArg_Intrinsic { - let Properties = [IntrNoMem, Commutative]; + let IntrProperties = [IntrNoMem, Commutative]; } // Vector Saturating Doubling Long Multiply @@ -436,70 +433,70 @@ def int_aarch64_neon_vcopy_lane: AdvSIMD_2Vector2Index_Intrinsic; let TargetPrefix = "aarch64" in { // All intrinsics start with "llvm.aarch64.". class AdvSIMD_1Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty], [LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_1Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; class AdvSIMD_2Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_2Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_2Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; class AdvSIMD_2Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<3>]>; + [IntrArgMemOnly, NoCapture<3>]>; class AdvSIMD_3Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_3Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_3Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadWriteArgMem, NoCapture<3>]>; + [IntrArgMemOnly, NoCapture<3>]>; class AdvSIMD_3Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<4>]>; + [IntrArgMemOnly, NoCapture<4>]>; class AdvSIMD_4Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_4Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_4Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMAnyPointerType<LLVMMatchType<0>>], - [IntrReadWriteArgMem, NoCapture<4>]>; + [IntrArgMemOnly, NoCapture<4>]>; class AdvSIMD_4Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<5>]>; + [IntrArgMemOnly, NoCapture<5>]>; } // Memory ops diff --git a/include/llvm/IR/IntrinsicsAMDGPU.td b/include/llvm/IR/IntrinsicsAMDGPU.td index 84582e8b9925..9bf2a4dd5a1d 100644 --- a/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/include/llvm/IR/IntrinsicsAMDGPU.td @@ -11,28 +11,45 @@ // //===----------------------------------------------------------------------===// +class AMDGPUReadPreloadRegisterIntrinsic + : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; + +class AMDGPUReadPreloadRegisterIntrinsicNamed<string name> + : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, GCCBuiltin<name>; + let TargetPrefix = "r600" in { -class R600ReadPreloadRegisterIntrinsic<string name> - : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<name>; +multiclass AMDGPUReadPreloadRegisterIntrinsic_xyz { + def _x : AMDGPUReadPreloadRegisterIntrinsic; + def _y : AMDGPUReadPreloadRegisterIntrinsic; + def _z : AMDGPUReadPreloadRegisterIntrinsic; +} -multiclass R600ReadPreloadRegisterIntrinsic_xyz<string prefix> { - def _x : R600ReadPreloadRegisterIntrinsic<!strconcat(prefix, "_x")>; - def _y : R600ReadPreloadRegisterIntrinsic<!strconcat(prefix, "_y")>; - def _z : R600ReadPreloadRegisterIntrinsic<!strconcat(prefix, "_z")>; +multiclass AMDGPUReadPreloadRegisterIntrinsic_xyz_named<string prefix> { + def _x : AMDGPUReadPreloadRegisterIntrinsicNamed<!strconcat(prefix, "_x")>; + def _y : AMDGPUReadPreloadRegisterIntrinsicNamed<!strconcat(prefix, "_y")>; + def _z : AMDGPUReadPreloadRegisterIntrinsicNamed<!strconcat(prefix, "_z")>; } -defm int_r600_read_global_size : R600ReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_global_size">; -defm int_r600_read_local_size : R600ReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_local_size">; -defm int_r600_read_ngroups : R600ReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_ngroups">; -defm int_r600_read_tgid : R600ReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_tgid">; -defm int_r600_read_tidig : R600ReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_tidig">; +defm int_r600_read_global_size : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_global_size">; +defm int_r600_read_ngroups : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_ngroups">; +defm int_r600_read_tgid : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_tgid">; + +defm int_r600_read_local_size : AMDGPUReadPreloadRegisterIntrinsic_xyz; +defm int_r600_read_tidig : AMDGPUReadPreloadRegisterIntrinsic_xyz; + +def int_r600_read_workdim : AMDGPUReadPreloadRegisterIntrinsic; + +def int_r600_group_barrier : GCCBuiltin<"__builtin_r600_group_barrier">, + Intrinsic<[], [], [IntrConvergent]>; + +// AS 7 is PARAM_I_ADDRESS, used for kernel arguments +def int_r600_implicitarg_ptr : + GCCBuiltin<"__builtin_r600_implicitarg_ptr">, + Intrinsic<[LLVMQualPointerType<llvm_i8_ty, 7>], [], [IntrNoMem]>; def int_r600_rat_store_typed : // 1st parameter: Data @@ -41,69 +58,253 @@ def int_r600_rat_store_typed : Intrinsic<[], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty], []>, GCCBuiltin<"__builtin_r600_rat_store_typed">; +def int_r600_recipsqrt_ieee : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_r600_recipsqrt_clamped : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + } // End TargetPrefix = "r600" -let TargetPrefix = "AMDGPU" in { +let TargetPrefix = "amdgcn" in { -class AMDGPUReadPreloadRegisterIntrinsic<string name> - : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<name>; +defm int_amdgcn_workitem_id : AMDGPUReadPreloadRegisterIntrinsic_xyz; +defm int_amdgcn_workgroup_id : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_amdgcn_workgroup_id">; -def int_AMDGPU_div_scale : GCCBuiltin<"__builtin_amdgpu_div_scale">, +def int_amdgcn_s_barrier : GCCBuiltin<"__builtin_amdgcn_s_barrier">, + Intrinsic<[], [], [IntrConvergent]>; + +def int_amdgcn_s_waitcnt : Intrinsic<[], [llvm_i32_ty], []>; + +def int_amdgcn_div_scale : Intrinsic< // 1st parameter: Numerator // 2nd parameter: Denominator // 3rd parameter: Constant to select select between first and // second. (0 = first, 1 = second). - Intrinsic<[llvm_anyfloat_ty, llvm_i1_ty], - [LLVMMatchType<0>, LLVMMatchType<0>, llvm_i1_ty], - [IntrNoMem]>; - -def int_AMDGPU_div_fmas : GCCBuiltin<"__builtin_amdgpu_div_fmas">, - Intrinsic<[llvm_anyfloat_ty], - [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i1_ty], - [IntrNoMem]>; - -def int_AMDGPU_div_fixup : GCCBuiltin<"__builtin_amdgpu_div_fixup">, - Intrinsic<[llvm_anyfloat_ty], - [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], - [IntrNoMem]>; - -def int_AMDGPU_trig_preop : GCCBuiltin<"__builtin_amdgpu_trig_preop">, - Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty], - [IntrNoMem]>; - -def int_AMDGPU_rcp : GCCBuiltin<"__builtin_amdgpu_rcp">, - Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; - -def int_AMDGPU_rsq : GCCBuiltin<"__builtin_amdgpu_rsq">, - Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; - -def int_AMDGPU_rsq_clamped : GCCBuiltin<"__builtin_amdgpu_rsq_clamped">, - Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; - -def int_AMDGPU_ldexp : GCCBuiltin<"__builtin_amdgpu_ldexp">, - Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty], [IntrNoMem]>; + [llvm_anyfloat_ty, llvm_i1_ty], + [LLVMMatchType<0>, LLVMMatchType<0>, llvm_i1_ty], + [IntrNoMem] +>; + +def int_amdgcn_div_fmas : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i1_ty], + [IntrNoMem] +>; + +def int_amdgcn_div_fixup : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], + [IntrNoMem] +>; + +def int_amdgcn_trig_preop : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty], [IntrNoMem] +>; + +def int_amdgcn_sin : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_cos : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_log_clamp : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_rcp : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_rsq : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_rsq_legacy : GCCBuiltin<"__builtin_amdgcn_rsq_legacy">, + Intrinsic< + [llvm_float_ty], [llvm_float_ty], [IntrNoMem] +>; + +def int_amdgcn_rsq_clamp : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; + +def int_amdgcn_ldexp : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty], [IntrNoMem] +>; + +def int_amdgcn_frexp_mant : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_frexp_exp : Intrinsic< + [llvm_i32_ty], [llvm_anyfloat_ty], [IntrNoMem] +>; + +// v_fract is buggy on SI/CI. It mishandles infinities, may return 1.0 +// and always uses rtz, so is not suitable for implementing the OpenCL +// fract function. It should be ok on VI. +def int_amdgcn_fract : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + +def int_amdgcn_class : Intrinsic< + [llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem] +>; + +def int_amdgcn_cubeid : GCCBuiltin<"__builtin_amdgcn_cubeid">, + Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; -def int_AMDGPU_class : GCCBuiltin<"__builtin_amdgpu_class">, - Intrinsic<[llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem]>; +def int_amdgcn_cubema : GCCBuiltin<"__builtin_amdgcn_cubema">, + Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; -def int_AMDGPU_read_workdim : AMDGPUReadPreloadRegisterIntrinsic < - "__builtin_amdgpu_read_workdim">; +def int_amdgcn_cubesc : GCCBuiltin<"__builtin_amdgcn_cubesc">, + Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; -} // End TargetPrefix = "AMDGPU" +def int_amdgcn_cubetc : GCCBuiltin<"__builtin_amdgcn_cubetc">, + Intrinsic<[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], [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>], + [IntrArgMemOnly, NoCapture<0>] +>; + +class AMDGPUImageLoad : Intrinsic < + [llvm_v4f32_ty], // vdata(VGPR) + [llvm_anyint_ty, // vaddr(VGPR) + llvm_v8i32_ty, // rsrc(SGPR) + llvm_i32_ty, // dmask(imm) + llvm_i1_ty, // r128(imm) + llvm_i1_ty, // da(imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + [IntrReadMem]>; + +def int_amdgcn_image_load : AMDGPUImageLoad; +def int_amdgcn_image_load_mip : AMDGPUImageLoad; + +class AMDGPUImageStore : Intrinsic < + [], + [llvm_v4f32_ty, // vdata(VGPR) + llvm_anyint_ty, // vaddr(VGPR) + llvm_v8i32_ty, // rsrc(SGPR) + llvm_i32_ty, // dmask(imm) + llvm_i1_ty, // r128(imm) + llvm_i1_ty, // da(imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + []>; + +def int_amdgcn_image_store : AMDGPUImageStore; +def int_amdgcn_image_store_mip : AMDGPUImageStore; + +class AMDGPUImageAtomic : Intrinsic < + [llvm_i32_ty], + [llvm_i32_ty, // vdata(VGPR) + llvm_anyint_ty, // vaddr(VGPR) + llvm_v8i32_ty, // rsrc(SGPR) + llvm_i1_ty, // r128(imm) + llvm_i1_ty, // da(imm) + llvm_i1_ty], // slc(imm) + []>; + +def int_amdgcn_image_atomic_swap : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_add : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_sub : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_smin : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_umin : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_smax : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_umax : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_and : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_or : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_xor : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_inc : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_dec : AMDGPUImageAtomic; +def int_amdgcn_image_atomic_cmpswap : Intrinsic < + [llvm_i32_ty], + [llvm_i32_ty, // src(VGPR) + llvm_i32_ty, // cmp(VGPR) + llvm_anyint_ty, // vaddr(VGPR) + llvm_v8i32_ty, // rsrc(SGPR) + llvm_i1_ty, // r128(imm) + llvm_i1_ty, // da(imm) + llvm_i1_ty], // slc(imm) + []>; + +class AMDGPUBufferLoad : Intrinsic < + [llvm_anyfloat_ty], + [llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // offset(SGPR/VGPR/imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + [IntrReadMem]>; +def int_amdgcn_buffer_load_format : AMDGPUBufferLoad; +def int_amdgcn_buffer_load : AMDGPUBufferLoad; + +class AMDGPUBufferStore : Intrinsic < + [], + [llvm_anyfloat_ty, // vdata(VGPR) -- can currently only select f32, v2f32, v4f32 + llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // offset(SGPR/VGPR/imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + [IntrWriteMem]>; +def int_amdgcn_buffer_store_format : AMDGPUBufferStore; +def int_amdgcn_buffer_store : AMDGPUBufferStore; + +class AMDGPUBufferAtomic : Intrinsic < + [llvm_i32_ty], + [llvm_i32_ty, // vdata(VGPR) + llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // offset(SGPR/VGPR/imm) + llvm_i1_ty], // slc(imm) + []>; +def int_amdgcn_buffer_atomic_swap : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_add : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_sub : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_smin : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_umin : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_smax : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_umax : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_and : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_or : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_xor : AMDGPUBufferAtomic; +def int_amdgcn_buffer_atomic_cmpswap : Intrinsic< + [llvm_i32_ty], + [llvm_i32_ty, // src(VGPR) + llvm_i32_ty, // cmp(VGPR) + llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // offset(SGPR/VGPR/imm) + llvm_i1_ty], // slc(imm) + []>; + +def int_amdgcn_read_workdim : AMDGPUReadPreloadRegisterIntrinsic; -let TargetPrefix = "amdgcn" in { -// SI only def int_amdgcn_buffer_wbinvl1_sc : GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1_sc">, Intrinsic<[], [], []>; -// On CI+ -def int_amdgcn_buffer_wbinvl1_vol : - GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1_vol">, - Intrinsic<[], [], []>; - def int_amdgcn_buffer_wbinvl1 : GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1">, Intrinsic<[], [], []>; @@ -112,25 +313,39 @@ def int_amdgcn_s_dcache_inv : GCCBuiltin<"__builtin_amdgcn_s_dcache_inv">, Intrinsic<[], [], []>; -// CI+ -def int_amdgcn_s_dcache_inv_vol : - GCCBuiltin<"__builtin_amdgcn_s_dcache_inv_vol">, - Intrinsic<[], [], []>; +def int_amdgcn_s_memtime : + GCCBuiltin<"__builtin_amdgcn_s_memtime">, + Intrinsic<[llvm_i64_ty], [], []>; -// VI -def int_amdgcn_s_dcache_wb : - GCCBuiltin<"__builtin_amdgcn_s_dcache_wb">, - Intrinsic<[], [], []>; +def int_amdgcn_s_sleep : + GCCBuiltin<"__builtin_amdgcn_s_sleep">, + Intrinsic<[], [llvm_i32_ty], []> { +} -// VI -def int_amdgcn_s_dcache_wb_vol : - GCCBuiltin<"__builtin_amdgcn_s_dcache_wb_vol">, - Intrinsic<[], [], []>; +def int_amdgcn_s_getreg : + GCCBuiltin<"__builtin_amdgcn_s_getreg">, + Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrReadMem]>; + +def int_amdgcn_groupstaticsize : + GCCBuiltin<"__builtin_amdgcn_groupstaticsize">, + Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; def int_amdgcn_dispatch_ptr : GCCBuiltin<"__builtin_amdgcn_dispatch_ptr">, Intrinsic<[LLVMQualPointerType<llvm_i8_ty, 2>], [], [IntrNoMem]>; +def int_amdgcn_queue_ptr : + GCCBuiltin<"__builtin_amdgcn_queue_ptr">, + Intrinsic<[LLVMQualPointerType<llvm_i8_ty, 2>], [], [IntrNoMem]>; + +def int_amdgcn_kernarg_segment_ptr : + GCCBuiltin<"__builtin_amdgcn_kernarg_segment_ptr">, + Intrinsic<[LLVMQualPointerType<llvm_i8_ty, 2>], [], [IntrNoMem]>; + +def int_amdgcn_implicitarg_ptr : + GCCBuiltin<"__builtin_amdgcn_implicitarg_ptr">, + Intrinsic<[LLVMQualPointerType<llvm_i8_ty, 2>], [], [IntrNoMem]>; + // __builtin_amdgcn_interp_p1 <i>, <attr_chan>, <attr>, <m0> def int_amdgcn_interp_p1 : GCCBuiltin<"__builtin_amdgcn_interp_p1">, @@ -147,6 +362,13 @@ def int_amdgcn_interp_p2 : [IntrNoMem]>; // See int_amdgcn_v_interp_p1 for why this is // IntrNoMem. +// Pixel shaders only: whether the current pixel is live (i.e. not a helper +// invocation for derivative computation). +def int_amdgcn_ps_live : Intrinsic < + [llvm_i1_ty], + [], + [IntrNoMem]>; + def int_amdgcn_mbcnt_lo : GCCBuiltin<"__builtin_amdgcn_mbcnt_lo">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; @@ -154,4 +376,57 @@ def int_amdgcn_mbcnt_lo : def int_amdgcn_mbcnt_hi : GCCBuiltin<"__builtin_amdgcn_mbcnt_hi">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; + +// llvm.amdgcn.ds.swizzle src offset +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_lerp : + GCCBuiltin<"__builtin_amdgcn_lerp">, + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; + +//===----------------------------------------------------------------------===// +// CI+ Intrinsics +//===----------------------------------------------------------------------===// + +def int_amdgcn_s_dcache_inv_vol : + GCCBuiltin<"__builtin_amdgcn_s_dcache_inv_vol">, + Intrinsic<[], [], []>; + +def int_amdgcn_buffer_wbinvl1_vol : + GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1_vol">, + Intrinsic<[], [], []>; + +//===----------------------------------------------------------------------===// +// VI Intrinsics +//===----------------------------------------------------------------------===// + +// llvm.amdgcn.mov.dpp.i32 <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl> +def int_amdgcn_mov_dpp : + Intrinsic<[llvm_anyint_ty], + [LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, + llvm_i1_ty], [IntrNoMem, IntrConvergent]>; + +def int_amdgcn_s_dcache_wb : + GCCBuiltin<"__builtin_amdgcn_s_dcache_wb">, + Intrinsic<[], [], []>; + +def int_amdgcn_s_dcache_wb_vol : + GCCBuiltin<"__builtin_amdgcn_s_dcache_wb_vol">, + Intrinsic<[], [], []>; + +def int_amdgcn_s_memrealtime : + GCCBuiltin<"__builtin_amdgcn_s_memrealtime">, + Intrinsic<[llvm_i64_ty], [], []>; + +// llvm.amdgcn.ds.permute <index> <src> +def int_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 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; + } diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index c1d911cefee2..099598596885 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -17,9 +17,6 @@ let TargetPrefix = "arm" in { // All intrinsics start with "llvm.arm.". -def int_arm_thread_pointer : GCCBuiltin<"__builtin_thread_pointer">, - Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; - // A space-consuming intrinsic primarily for testing ARMConstantIslands. The // first argument is the number of bytes this "instruction" takes up, the second // and return value are essentially chains, used to force ordering during ISel. @@ -81,6 +78,24 @@ def int_arm_vcvtru : Intrinsic<[llvm_float_ty], [llvm_anyfloat_ty], //===----------------------------------------------------------------------===// // Coprocessor +def int_arm_ldc : GCCBuiltin<"__builtin_arm_ldc">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldcl : GCCBuiltin<"__builtin_arm_ldcl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldc2 : GCCBuiltin<"__builtin_arm_ldc2">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldc2l : GCCBuiltin<"__builtin_arm_ldc2l">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; + +def int_arm_stc : GCCBuiltin<"__builtin_arm_stc">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stcl : GCCBuiltin<"__builtin_arm_stcl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stc2 : GCCBuiltin<"__builtin_arm_stc2">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stc2l : GCCBuiltin<"__builtin_arm_stc2l">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; + // Move to coprocessor def int_arm_mcr : GCCBuiltin<"__builtin_arm_mcr">, Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, @@ -108,12 +123,15 @@ def int_arm_cdp2 : GCCBuiltin<"__builtin_arm_cdp2">, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; // Move from two registers to coprocessor -def int_arm_mcrr : GCCBuiltin<"__builtin_arm_mcrr">, - Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty, llvm_i32_ty], []>; -def int_arm_mcrr2 : GCCBuiltin<"__builtin_arm_mcrr2">, - Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mcrr : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mcrr2 : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; + +def int_arm_mrrc : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mrrc2 : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; //===----------------------------------------------------------------------===// // CRC32 @@ -207,7 +225,7 @@ class Neon_Tbl6Arg_Intrinsic // Arithmetic ops -let Properties = [IntrNoMem, Commutative] in { +let IntrProperties = [IntrNoMem, Commutative] in { // Vector Add. def int_arm_neon_vhadds : Neon_2Arg_Intrinsic; @@ -406,18 +424,18 @@ def int_arm_neon_vrintp : Neon_1Arg_Intrinsic; // Source operands are the address and alignment. def int_arm_neon_vld1 : Intrinsic<[llvm_anyvector_ty], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld2 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld3 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld4 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; // Vector load N-element structure to one lane. // Source operands are: the address, the N input vectors (since only one @@ -425,38 +443,38 @@ def int_arm_neon_vld4 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, def int_arm_neon_vld2lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, - llvm_i32_ty], [IntrReadArgMem]>; + llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld3lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld4lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, - llvm_i32_ty], [IntrReadArgMem]>; + llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; // Interleaving vector stores from N-element structures. // Source operands are: the address, the N vectors, and the alignment. def int_arm_neon_vst1 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst2 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_arm_neon_vst3 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst4 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // Vector store N-element structure from one lane. // Source operands are: the address, the N vectors, the lane number, and @@ -464,17 +482,17 @@ def int_arm_neon_vst4 : Intrinsic<[], def int_arm_neon_vst2lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, llvm_i32_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst3lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_arm_neon_vst4lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; // Vector bitwise select. def int_arm_neon_vbsl : Intrinsic<[llvm_anyvector_ty], diff --git a/include/llvm/IR/IntrinsicsHexagon.td b/include/llvm/IR/IntrinsicsHexagon.td index ca6fcbd44337..6519f051deeb 100644 --- a/include/llvm/IR/IntrinsicsHexagon.td +++ b/include/llvm/IR/IntrinsicsHexagon.td @@ -428,42 +428,42 @@ class Hexagon_mem_memmemsi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_mem_memsisi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_mem_memdisi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_mem_memmemsisi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_mem_memsisisi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_mem_memdisisi_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_ptr_ty], [llvm_ptr_ty, llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; class Hexagon_v256_v256v256_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, [llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // // Hexagon_sf_df_Intrinsic<string GCCIntSuffix> @@ -2998,7 +2998,7 @@ Hexagon_di_di_Intrinsic<"HEXAGON_A2_tfrp">; // BUILTIN_INFO(HEXAGON.A2_tfrpi,DI_ftype_SI,1) // def int_hexagon_A2_tfrpi : -Hexagon_di_di_Intrinsic<"HEXAGON_A2_tfrpi">; +Hexagon_di_si_Intrinsic<"HEXAGON_A2_tfrpi">; // // BUILTIN_INFO(HEXAGON.A2_zxtb,SI_ftype_SI,1) // @@ -4971,17 +4971,17 @@ def llvm_ptr64_ty : LLVMPointerType<llvm_i64_ty>; // Mark locked loads as read/write to prevent any accidental reordering. def int_hexagon_L2_loadw_locked : Hexagon_Intrinsic<"HEXAGON_L2_loadw_locked", [llvm_i32_ty], [llvm_ptr32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_L4_loadd_locked : Hexagon_Intrinsic<"HEXAGON_L4_loadd_locked", [llvm_i64_ty], [llvm_ptr64_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_S2_storew_locked : Hexagon_Intrinsic<"HEXAGON_S2_storew_locked", [llvm_i32_ty], - [llvm_ptr32_ty, llvm_i32_ty], [IntrReadWriteArgMem, NoCapture<0>]>; + [llvm_ptr32_ty, llvm_i32_ty], [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_S4_stored_locked : Hexagon_Intrinsic<"HEXAGON_S4_stored_locked", [llvm_i32_ty], - [llvm_ptr64_ty, llvm_i64_ty], [IntrReadWriteArgMem, NoCapture<0>]>; + [llvm_ptr64_ty, llvm_i64_ty], [IntrArgMemOnly, NoCapture<0>]>; // V60 diff --git a/include/llvm/IR/IntrinsicsMips.td b/include/llvm/IR/IntrinsicsMips.td index 34557612cb96..421a79be4ebc 100644 --- a/include/llvm/IR/IntrinsicsMips.td +++ b/include/llvm/IR/IntrinsicsMips.td @@ -264,11 +264,11 @@ def int_mips_bposge32: GCCBuiltin<"__builtin_mips_bposge32">, Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>; def int_mips_lbux: GCCBuiltin<"__builtin_mips_lbux">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_mips_lhx: GCCBuiltin<"__builtin_mips_lhx">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_mips_lwx: GCCBuiltin<"__builtin_mips_lwx">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // MIPS DSP Rev 2 @@ -1261,16 +1261,16 @@ def int_mips_insve_d : GCCBuiltin<"__builtin_msa_insve_d">, def int_mips_ld_b : GCCBuiltin<"__builtin_msa_ld_b">, Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_h : GCCBuiltin<"__builtin_msa_ld_h">, Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_w : GCCBuiltin<"__builtin_msa_ld_w">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_d : GCCBuiltin<"__builtin_msa_ld_d">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ldi_b : GCCBuiltin<"__builtin_msa_ldi_b">, Intrinsic<[llvm_v16i8_ty], [llvm_i32_ty], [IntrNoMem]>; @@ -1685,16 +1685,16 @@ def int_mips_srlri_d : GCCBuiltin<"__builtin_msa_srlri_d">, def int_mips_st_b : GCCBuiltin<"__builtin_msa_st_b">, Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_h : GCCBuiltin<"__builtin_msa_st_h">, Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_w : GCCBuiltin<"__builtin_msa_st_w">, Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_d : GCCBuiltin<"__builtin_msa_st_d">, Intrinsic<[], [llvm_v2i64_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_subs_s_b : GCCBuiltin<"__builtin_msa_subs_s_b">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; diff --git a/include/llvm/IR/IntrinsicsNVVM.td b/include/llvm/IR/IntrinsicsNVVM.td index 9deed414b50a..6919ec47eb9a 100644 --- a/include/llvm/IR/IntrinsicsNVVM.td +++ b/include/llvm/IR/IntrinsicsNVVM.td @@ -17,6 +17,7 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // MISC // +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">, @@ -720,25 +721,30 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // Atomic not available as an llvm intrinsic. def int_nvvm_atomic_load_add_f32 : Intrinsic<[llvm_float_ty], [LLVMAnyPointerType<llvm_float_ty>, llvm_float_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_nvvm_atomic_load_inc_32 : Intrinsic<[llvm_i32_ty], [LLVMAnyPointerType<llvm_i32_ty>, llvm_i32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_nvvm_atomic_load_dec_32 : Intrinsic<[llvm_i32_ty], [LLVMAnyPointerType<llvm_i32_ty>, llvm_i32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; // Bar.Sync - def int_cuda_syncthreads : GCCBuiltin<"__syncthreads">, - Intrinsic<[], [], [IntrNoDuplicate]>; - def int_nvvm_barrier0 : GCCBuiltin<"__nvvm_bar0">, - Intrinsic<[], [], [IntrNoDuplicate]>; + + // The builtin for "bar.sync 0" is called __syncthreads. Unlike most of the + // intrinsics in this file, this one is a user-facing API. + def int_nvvm_barrier0 : GCCBuiltin<"__syncthreads">, + Intrinsic<[], [], [IntrConvergent]>; def int_nvvm_barrier0_popc : GCCBuiltin<"__nvvm_bar0_popc">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoDuplicate]>; + Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_and : GCCBuiltin<"__nvvm_bar0_and">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoDuplicate]>; + Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_or : GCCBuiltin<"__nvvm_bar0_or">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoDuplicate]>; + Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; + + def int_nvvm_bar_sync : + Intrinsic<[], [llvm_i32_ty], [IntrConvergent]>, + GCCBuiltin<"__nvvm_bar_sync">; // Membar def int_nvvm_membar_cta : GCCBuiltin<"__nvvm_membar_cta">, @@ -748,79 +754,34 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* def int_nvvm_membar_sys : GCCBuiltin<"__nvvm_membar_sys">, Intrinsic<[], [], []>; - -// Accessing special registers - def int_nvvm_read_ptx_sreg_tid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_x">; - def int_nvvm_read_ptx_sreg_tid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_y">; - def int_nvvm_read_ptx_sreg_tid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_z">; - - def int_nvvm_read_ptx_sreg_ntid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_x">; - def int_nvvm_read_ptx_sreg_ntid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_y">; - def int_nvvm_read_ptx_sreg_ntid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_z">; - - def int_nvvm_read_ptx_sreg_ctaid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_x">; - def int_nvvm_read_ptx_sreg_ctaid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_y">; - def int_nvvm_read_ptx_sreg_ctaid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_z">; - - def int_nvvm_read_ptx_sreg_nctaid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_x">; - def int_nvvm_read_ptx_sreg_nctaid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_y">; - def int_nvvm_read_ptx_sreg_nctaid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_z">; - - def int_nvvm_read_ptx_sreg_warpsize : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_warpsize">; - - -// Generated within nvvm. Use for ldu on sm_20 or later +// Generated within nvvm. Use for ldu on sm_20 or later. Second arg is the +// pointer's alignment. def int_nvvm_ldu_global_i : Intrinsic<[llvm_anyint_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.i">; def int_nvvm_ldu_global_f : Intrinsic<[llvm_anyfloat_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.f">; def int_nvvm_ldu_global_p : Intrinsic<[llvm_anyptr_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.p">; -// Generated within nvvm. Use for ldg on sm_35 or later +// Generated within nvvm. Use for ldg on sm_35 or later. Second arg is the +// pointer's alignment. def int_nvvm_ldg_global_i : Intrinsic<[llvm_anyint_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.i">; def int_nvvm_ldg_global_f : Intrinsic<[llvm_anyfloat_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.f">; def int_nvvm_ldg_global_p : Intrinsic<[llvm_anyptr_ty], [LLVMAnyPointerType<LLVMMatchType<0>>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.p">; // Use for generic pointers @@ -3666,9 +3627,8 @@ def int_nvvm_swap_lo_hi_b64 GCCBuiltin<"__nvvm_swap_lo_hi_b64">; -// Old PTX back-end intrinsics retained here for backwards-compatibility - -multiclass PTXReadSpecialRegisterIntrinsic_v4i32<string prefix> { +// Accessing special registers. +multiclass PTXReadSRegIntrinsic_v4i32<string regname> { // FIXME: Do we need the 128-bit integer type version? // def _r64 : Intrinsic<[llvm_i128_ty], [], [IntrNoMem]>; @@ -3676,71 +3636,99 @@ multiclass PTXReadSpecialRegisterIntrinsic_v4i32<string prefix> { // def _v4i16 : Intrinsic<[llvm_v4i32_ty], [], [IntrNoMem]>; def _x : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<!strconcat(prefix, "_x")>; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_x">; def _y : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<!strconcat(prefix, "_y")>; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_y">; def _z : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<!strconcat(prefix, "_z")>; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_z">; def _w : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<!strconcat(prefix, "_w")>; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_w">; } -class PTXReadSpecialRegisterIntrinsic_r32<string name> +class PTXReadSRegIntrinsic_r32<string name> : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<name>; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # name>; -class PTXReadSpecialRegisterIntrinsic_r64<string name> +class PTXReadSRegIntrinsic_r64<string name> : Intrinsic<[llvm_i64_ty], [], [IntrNoMem]>, - GCCBuiltin<name>; - -defm int_ptx_read_tid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_tid">; -defm int_ptx_read_ntid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_ntid">; - -def int_ptx_read_laneid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_laneid">; -def int_ptx_read_warpid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_warpid">; -def int_ptx_read_nwarpid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_nwarpid">; - -defm int_ptx_read_ctaid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_ctaid">; -defm int_ptx_read_nctaid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_nctaid">; - -def int_ptx_read_smid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_smid">; -def int_ptx_read_nsmid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_nsmid">; -def int_ptx_read_gridid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_gridid">; - -def int_ptx_read_lanemask_eq : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_eq">; -def int_ptx_read_lanemask_le : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_le">; -def int_ptx_read_lanemask_lt : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_lt">; -def int_ptx_read_lanemask_ge : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_ge">; -def int_ptx_read_lanemask_gt : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_gt">; - -def int_ptx_read_clock : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_clock">; -def int_ptx_read_clock64 : PTXReadSpecialRegisterIntrinsic_r64 - <"__builtin_ptx_read_clock64">; - -def int_ptx_read_pm0 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm0">; -def int_ptx_read_pm1 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm1">; -def int_ptx_read_pm2 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm2">; -def int_ptx_read_pm3 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm3">; - -def int_ptx_bar_sync : Intrinsic<[], [llvm_i32_ty], []>, - GCCBuiltin<"__builtin_ptx_bar_sync">; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # name>; + +defm int_nvvm_read_ptx_sreg_tid : PTXReadSRegIntrinsic_v4i32<"tid">; +defm int_nvvm_read_ptx_sreg_ntid : PTXReadSRegIntrinsic_v4i32<"ntid">; + +def int_nvvm_read_ptx_sreg_laneid : PTXReadSRegIntrinsic_r32<"laneid">; +def int_nvvm_read_ptx_sreg_warpid : PTXReadSRegIntrinsic_r32<"warpid">; +def int_nvvm_read_ptx_sreg_nwarpid : PTXReadSRegIntrinsic_r32<"nwarpid">; + +defm int_nvvm_read_ptx_sreg_ctaid : PTXReadSRegIntrinsic_v4i32<"ctaid">; +defm int_nvvm_read_ptx_sreg_nctaid : PTXReadSRegIntrinsic_v4i32<"nctaid">; + +def int_nvvm_read_ptx_sreg_smid : PTXReadSRegIntrinsic_r32<"smid">; +def int_nvvm_read_ptx_sreg_nsmid : PTXReadSRegIntrinsic_r32<"nsmid">; +def int_nvvm_read_ptx_sreg_gridid : PTXReadSRegIntrinsic_r32<"gridid">; + +def int_nvvm_read_ptx_sreg_lanemask_eq : + PTXReadSRegIntrinsic_r32<"lanemask_eq">; +def int_nvvm_read_ptx_sreg_lanemask_le : + PTXReadSRegIntrinsic_r32<"lanemask_le">; +def int_nvvm_read_ptx_sreg_lanemask_lt : + PTXReadSRegIntrinsic_r32<"lanemask_lt">; +def int_nvvm_read_ptx_sreg_lanemask_ge : + PTXReadSRegIntrinsic_r32<"lanemask_ge">; +def int_nvvm_read_ptx_sreg_lanemask_gt : + PTXReadSRegIntrinsic_r32<"lanemask_gt">; + +def int_nvvm_read_ptx_sreg_clock : PTXReadSRegIntrinsic_r32<"clock">; +def int_nvvm_read_ptx_sreg_clock64 : PTXReadSRegIntrinsic_r64<"clock64">; + +def int_nvvm_read_ptx_sreg_pm0 : PTXReadSRegIntrinsic_r32<"pm0">; +def int_nvvm_read_ptx_sreg_pm1 : PTXReadSRegIntrinsic_r32<"pm1">; +def int_nvvm_read_ptx_sreg_pm2 : PTXReadSRegIntrinsic_r32<"pm2">; +def int_nvvm_read_ptx_sreg_pm3 : PTXReadSRegIntrinsic_r32<"pm3">; + +def int_nvvm_read_ptx_sreg_warpsize : PTXReadSRegIntrinsic_r32<"warpsize">; + +// +// SHUFFLE +// + +// shfl.down.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_down_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.down.i32">, + GCCBuiltin<"__nvvm_shfl_down_i32">; +def int_nvvm_shfl_down_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.down.f32">, + GCCBuiltin<"__nvvm_shfl_down_f32">; + +// shfl.up.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_up_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.up.i32">, + GCCBuiltin<"__nvvm_shfl_up_i32">; +def int_nvvm_shfl_up_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.up.f32">, + GCCBuiltin<"__nvvm_shfl_up_f32">; + +// shfl.bfly.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_bfly_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.bfly.i32">, + GCCBuiltin<"__nvvm_shfl_bfly_i32">; +def int_nvvm_shfl_bfly_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.bfly.f32">, + GCCBuiltin<"__nvvm_shfl_bfly_f32">; + +// shfl.idx.b32 dest, val, lane, mask_and_clamp +def int_nvvm_shfl_idx_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.idx.i32">, + GCCBuiltin<"__nvvm_shfl_idx_i32">; +def int_nvvm_shfl_idx_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.idx.f32">, + GCCBuiltin<"__nvvm_shfl_idx_f32">; +} diff --git a/include/llvm/IR/IntrinsicsPowerPC.td b/include/llvm/IR/IntrinsicsPowerPC.td index 5512b1063fb0..e195c0ebac3a 100644 --- a/include/llvm/IR/IntrinsicsPowerPC.td +++ b/include/llvm/IR/IntrinsicsPowerPC.td @@ -23,9 +23,9 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". def int_ppc_dcbi : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbst : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbt : Intrinsic<[], [llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_ppc_dcbtst: Intrinsic<[], [llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_ppc_dcbz : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbzl : Intrinsic<[], [llvm_ptr_ty], []>; @@ -189,33 +189,33 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // Loads. These don't map directly to GCC builtins because they represent the // source address with a single pointer. def int_ppc_altivec_lvx : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvxl : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvebx : - Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvehx : - Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvewx : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; // Stores. These don't map directly to GCC builtins because they represent the // source address with a single pointer. def int_ppc_altivec_stvx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvxl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvebx : Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvehx : Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvewx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // Comparisons setting a vector. def int_ppc_altivec_vcmpbfp : GCCBuiltin<"__builtin_altivec_vcmpbfp">, @@ -664,15 +664,15 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // Vector load. def int_ppc_vsx_lxvw4x : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_vsx_lxvd2x : - Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; // Vector store. def int_ppc_vsx_stxvw4x : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; def int_ppc_vsx_stxvd2x : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; // Vector and scalar maximum. def int_ppc_vsx_xvmaxdp : PowerPC_VSX_Vec_DDD_Intrinsic<"xvmaxdp">; @@ -790,7 +790,7 @@ class PowerPC_QPX_FFFF_Intrinsic<string GCCIntSuffix> /// and returns a v4f64. class PowerPC_QPX_Load_Intrinsic<string GCCIntSuffix> : PowerPC_QPX_Intrinsic<GCCIntSuffix, - [llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + [llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; /// PowerPC_QPX_LoadPerm_Intrinsic - A PowerPC intrinsic that takes a pointer /// and returns a v4f64 permutation. @@ -803,7 +803,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], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // PowerPC QPX Intrinsic Definitions. diff --git a/include/llvm/IR/IntrinsicsSystemZ.td b/include/llvm/IR/IntrinsicsSystemZ.td index 96e7ca525696..bfc15b9bc09e 100644 --- a/include/llvm/IR/IntrinsicsSystemZ.td +++ b/include/llvm/IR/IntrinsicsSystemZ.td @@ -217,7 +217,7 @@ let TargetPrefix = "s390" in { Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; def int_s390_ntstg : Intrinsic<[], [llvm_i64_ty, llvm_ptr64_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_s390_ppa_txassist : GCCBuiltin<"__builtin_tx_assist">, Intrinsic<[], [llvm_i32_ty]>; @@ -236,11 +236,11 @@ let TargetPrefix = "s390" in { def int_s390_vlbb : GCCBuiltin<"__builtin_s390_vlbb">, Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_s390_vll : GCCBuiltin<"__builtin_s390_vll">, Intrinsic<[llvm_v16i8_ty], [llvm_i32_ty, llvm_ptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_s390_vpdi : GCCBuiltin<"__builtin_s390_vpdi">, Intrinsic<[llvm_v2i64_ty], @@ -262,7 +262,7 @@ let TargetPrefix = "s390" in { Intrinsic<[], [llvm_v16i8_ty, llvm_i32_ty, llvm_ptr_ty], // In fact write-only but there's no property // for that. - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; defm int_s390_vupl : SystemZUnaryExtBHWF<"vupl">; defm int_s390_vupll : SystemZUnaryExtBHF<"vupll">; @@ -374,3 +374,14 @@ let TargetPrefix = "s390" in { [llvm_v2f64_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; } + +//===----------------------------------------------------------------------===// +// +// Misc intrinsics +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "s390" in { + def int_s390_tdc : Intrinsic<[llvm_i32_ty], [llvm_anyfloat_ty, llvm_i64_ty], + [IntrNoMem]>; +} diff --git a/include/llvm/IR/IntrinsicsWebAssembly.td b/include/llvm/IR/IntrinsicsWebAssembly.td index 3953aef43dad..4234c466d973 100644 --- a/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/include/llvm/IR/IntrinsicsWebAssembly.td @@ -14,9 +14,9 @@ let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.". -// Note that memory_size is not IntrNoMem because it must be sequenced with +// Note that current_memory is not IntrNoMem because it must be sequenced with // respect to grow_memory calls. -def int_wasm_memory_size : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; +def int_wasm_current_memory : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; def int_wasm_grow_memory : Intrinsic<[], [llvm_anyint_ty], []>; } diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index 8023a9f6e8e9..74c971552bb3 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -25,6 +25,9 @@ let TargetPrefix = "x86" in { // Marks the EH registration node created in LLVM IR prior to code generation. def int_x86_seh_ehregnode : Intrinsic<[], [llvm_ptr_ty], []>; + // Marks the EH guard slot node created in LLVM IR prior to code generation. + def int_x86_seh_ehguard : Intrinsic<[], [llvm_ptr_ty], []>; + // Given a pointer to the end of an EH registration object, returns the true // parent frame address that can be used with llvm.localrecover. def int_x86_seh_recoverfp : Intrinsic<[llvm_ptr_ty], @@ -51,7 +54,7 @@ let TargetPrefix = "x86" in { def int_x86_rdtsc : GCCBuiltin<"__builtin_ia32_rdtsc">, Intrinsic<[llvm_i64_ty], [], []>; def int_x86_rdtscp : GCCBuiltin<"__builtin_ia32_rdtscp">, - Intrinsic<[llvm_i64_ty], [llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[llvm_i64_ty], [llvm_ptr_ty], [IntrArgMemOnly]>; } // Read Performance-Monitoring Counter. @@ -142,16 +145,16 @@ let TargetPrefix = "x86" in { // Arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse_add_ss : GCCBuiltin<"__builtin_ia32_addss">, + def int_x86_sse_add_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_sub_ss : GCCBuiltin<"__builtin_ia32_subss">, + def int_x86_sse_sub_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_mul_ss : GCCBuiltin<"__builtin_ia32_mulss">, + def int_x86_sse_mul_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_div_ss : GCCBuiltin<"__builtin_ia32_divss">, + def int_x86_sse_div_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse_sqrt_ss : GCCBuiltin<"__builtin_ia32_sqrtss">, @@ -191,7 +194,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse_cmp_ss : GCCBuiltin<"__builtin_ia32_cmpss">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_sse_cmp_ps : GCCBuiltin<"__builtin_ia32_cmpps">, + def int_x86_sse_cmp_ps : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse_comieq_ss : GCCBuiltin<"__builtin_ia32_comieq">, @@ -259,13 +262,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_x86mmx_ty], [IntrNoMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse_storeu_ps : GCCBuiltin<"__builtin_ia32_storeups">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v4f32_ty], [IntrReadWriteArgMem]>; -} - // Cacheability support ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse_sfence : GCCBuiltin<"__builtin_ia32_sfence">, @@ -291,16 +287,16 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // FP arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_add_sd : GCCBuiltin<"__builtin_ia32_addsd">, + def int_x86_sse2_add_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_sub_sd : GCCBuiltin<"__builtin_ia32_subsd">, + def int_x86_sse2_sub_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_mul_sd : GCCBuiltin<"__builtin_ia32_mulsd">, + def int_x86_sse2_mul_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_div_sd : GCCBuiltin<"__builtin_ia32_divsd">, + def int_x86_sse2_div_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_sqrt_sd : GCCBuiltin<"__builtin_ia32_sqrtsd">, @@ -328,7 +324,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_cmp_sd : GCCBuiltin<"__builtin_ia32_cmpsd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_sse2_cmp_pd : GCCBuiltin<"__builtin_ia32_cmppd">, + def int_x86_sse2_cmp_pd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse2_comieq_sd : GCCBuiltin<"__builtin_ia32_comisdeq">, @@ -413,18 +409,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_pavg_w : GCCBuiltin<"__builtin_ia32_pavgw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmaxu_b : GCCBuiltin<"__builtin_ia32_pmaxub128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, - llvm_v16i8_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmaxs_w : GCCBuiltin<"__builtin_ia32_pmaxsw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_v8i16_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pminu_b : GCCBuiltin<"__builtin_ia32_pminub128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, - llvm_v16i8_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmins_w : GCCBuiltin<"__builtin_ia32_pminsw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_v8i16_ty], [IntrNoMem, Commutative]>; def int_x86_sse2_psad_bw : GCCBuiltin<"__builtin_ia32_psadbw128">, Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem, Commutative]>; @@ -485,8 +469,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Conversion ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_cvtdq2pd : GCCBuiltin<"__builtin_ia32_cvtdq2pd">, - Intrinsic<[llvm_v2f64_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_sse2_cvtdq2ps : GCCBuiltin<"__builtin_ia32_cvtdq2ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_sse2_cvtpd2dq : GCCBuiltin<"__builtin_ia32_cvtpd2dq">, @@ -497,10 +479,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v4f32_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_cvtps2dq : GCCBuiltin<"__builtin_ia32_cvtps2dq">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse2_cvttps2dq : GCCBuiltin<"__builtin_ia32_cvttps2dq">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse2_cvtps2pd : GCCBuiltin<"__builtin_ia32_cvtps2pd">, - Intrinsic<[llvm_v2f64_ty], [llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse2_cvtsd2si : GCCBuiltin<"__builtin_ia32_cvtsd2si">, Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_cvtsd2si64 : GCCBuiltin<"__builtin_ia32_cvtsd2si64">, @@ -529,19 +507,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2f64_ty], [llvm_x86mmx_ty], [IntrNoMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_storeu_pd : GCCBuiltin<"__builtin_ia32_storeupd">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v2f64_ty], [IntrReadWriteArgMem]>; - def int_x86_sse2_storeu_dq : GCCBuiltin<"__builtin_ia32_storedqu">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v16i8_ty], [IntrReadWriteArgMem]>; - def int_x86_sse2_storel_dq : GCCBuiltin<"__builtin_ia32_storelv4si">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v4i32_ty], [IntrReadWriteArgMem]>; -} - // Misc. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_packsswb_128 : GCCBuiltin<"__builtin_ia32_packsswb128">, @@ -688,15 +653,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_pshuf_b_128 : GCCBuiltin<"__builtin_ia32_pshufb128">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; - def int_x86_sse2_pshuf_d : GCCBuiltin<"__builtin_ia32_pshufd">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_sse2_pshufl_w : GCCBuiltin<"__builtin_ia32_pshuflw">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_sse2_pshufh_w : GCCBuiltin<"__builtin_ia32_pshufhw">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; def int_x86_sse_pshuf_w : GCCBuiltin<"__builtin_ia32_pshufw">, Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i8_ty], [IntrNoMem]>; @@ -763,46 +719,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_i32_ty], [IntrNoMem]>; } -// Vector sign and zero extend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pmovsxbd : GCCBuiltin<"__builtin_ia32_pmovsxbd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxbq : GCCBuiltin<"__builtin_ia32_pmovsxbq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxbw : GCCBuiltin<"__builtin_ia32_pmovsxbw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxdq : GCCBuiltin<"__builtin_ia32_pmovsxdq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxwd : GCCBuiltin<"__builtin_ia32_pmovsxwd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxwq : GCCBuiltin<"__builtin_ia32_pmovsxwq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbd : GCCBuiltin<"__builtin_ia32_pmovzxbd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbq : GCCBuiltin<"__builtin_ia32_pmovzxbq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbw : GCCBuiltin<"__builtin_ia32_pmovzxbw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxwd : GCCBuiltin<"__builtin_ia32_pmovzxwd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxwq : GCCBuiltin<"__builtin_ia32_pmovzxwq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; -} - // Vector min element let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_phminposuw : GCCBuiltin<"__builtin_ia32_phminposuw128">, @@ -810,34 +726,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; } -// Vector compare, min, max -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pmaxsb : GCCBuiltin<"__builtin_ia32_pmaxsb128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxsd : GCCBuiltin<"__builtin_ia32_pmaxsd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxud : GCCBuiltin<"__builtin_ia32_pmaxud128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxuw : GCCBuiltin<"__builtin_ia32_pmaxuw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminsb : GCCBuiltin<"__builtin_ia32_pminsb128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminsd : GCCBuiltin<"__builtin_ia32_pminsd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminud : GCCBuiltin<"__builtin_ia32_pminud128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminuw : GCCBuiltin<"__builtin_ia32_pminuw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], - [IntrNoMem, Commutative]>; -} - // Advanced Encryption Standard (AES) Instructions let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_aesni_aesimc : GCCBuiltin<"__builtin_ia32_aesimc128">, @@ -882,22 +770,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem, Commutative]>; } -// Vector extract -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pextrb : - Intrinsic<[llvm_i32_ty], [llvm_v16i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pextrd : - Intrinsic<[llvm_i32_ty], [llvm_v4i32_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pextrq : - Intrinsic<[llvm_i64_ty], [llvm_v2i64_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_extractps : GCCBuiltin<"__builtin_ia32_extractps128">, - Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_i32_ty], - [IntrNoMem]>; -} - // Vector insert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_insertps : GCCBuiltin<"__builtin_ia32_insertps128">, @@ -1056,11 +928,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_i8_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse4a_insertq : GCCBuiltin<"__builtin_ia32_insertq">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty], [IntrNoMem]>; - - def int_x86_sse4a_movnt_ss : GCCBuiltin<"__builtin_ia32_movntss">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty], []>; - def int_x86_sse4a_movnt_sd : GCCBuiltin<"__builtin_ia32_movntsd">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty], []>; } //===----------------------------------------------------------------------===// @@ -1151,91 +1018,91 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_d_128 : + def int_x86_avx512_mask_vpermi2var_d_128 : GCCBuiltin<"__builtin_ia32_vpermi2vard128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_d_256 : + def int_x86_avx512_mask_vpermi2var_d_256 : GCCBuiltin<"__builtin_ia32_vpermi2vard256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_d_512 : + def int_x86_avx512_mask_vpermi2var_d_512 : GCCBuiltin<"__builtin_ia32_vpermi2vard512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_hi_128 : + def int_x86_avx512_mask_vpermi2var_hi_128 : GCCBuiltin<"__builtin_ia32_vpermi2varhi128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_hi_256 : + def int_x86_avx512_mask_vpermi2var_hi_256 : GCCBuiltin<"__builtin_ia32_vpermi2varhi256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_hi_512 : + def int_x86_avx512_mask_vpermi2var_hi_512 : GCCBuiltin<"__builtin_ia32_vpermi2varhi512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_pd_128 : + def int_x86_avx512_mask_vpermi2var_pd_128 : GCCBuiltin<"__builtin_ia32_vpermi2varpd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2i64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_pd_256 : + def int_x86_avx512_mask_vpermi2var_pd_256 : GCCBuiltin<"__builtin_ia32_vpermi2varpd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_pd_512 : + def int_x86_avx512_mask_vpermi2var_pd_512 : GCCBuiltin<"__builtin_ia32_vpermi2varpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8i64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_ps_128 : + def int_x86_avx512_mask_vpermi2var_ps_128 : GCCBuiltin<"__builtin_ia32_vpermi2varps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_ps_256 : + def int_x86_avx512_mask_vpermi2var_ps_256 : GCCBuiltin<"__builtin_ia32_vpermi2varps256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_ps_512 : + def int_x86_avx512_mask_vpermi2var_ps_512 : GCCBuiltin<"__builtin_ia32_vpermi2varps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_q_128 : + def int_x86_avx512_mask_vpermi2var_q_128 : GCCBuiltin<"__builtin_ia32_vpermi2varq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_q_256 : + def int_x86_avx512_mask_vpermi2var_q_256 : GCCBuiltin<"__builtin_ia32_vpermi2varq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermi2var_q_512 : + def int_x86_avx512_mask_vpermi2var_q_512 : GCCBuiltin<"__builtin_ia32_vpermi2varq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], @@ -1261,196 +1128,214 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8f64_ty], [llvm_v8i64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_d_128 : + def int_x86_avx512_mask_vpermt2var_d_128 : GCCBuiltin<"__builtin_ia32_vpermt2vard128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_d_128 : + def int_x86_avx512_maskz_vpermt2var_d_128 : GCCBuiltin<"__builtin_ia32_vpermt2vard128_maskz">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_d_256 : + def int_x86_avx512_mask_vpermt2var_d_256 : GCCBuiltin<"__builtin_ia32_vpermt2vard256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_d_256 : + def int_x86_avx512_maskz_vpermt2var_d_256 : GCCBuiltin<"__builtin_ia32_vpermt2vard256_maskz">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_d_512 : + def int_x86_avx512_maskz_vpermt2var_d_512 : GCCBuiltin<"__builtin_ia32_vpermt2vard512_maskz">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_hi_128 : + def int_x86_avx512_mask_vpermt2var_hi_128 : GCCBuiltin<"__builtin_ia32_vpermt2varhi128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_hi_128 : + def int_x86_avx512_maskz_vpermt2var_hi_128 : GCCBuiltin<"__builtin_ia32_vpermt2varhi128_maskz">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_hi_256 : + def int_x86_avx512_mask_vpermt2var_hi_256 : GCCBuiltin<"__builtin_ia32_vpermt2varhi256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_hi_256 : + def int_x86_avx512_maskz_vpermt2var_hi_256 : GCCBuiltin<"__builtin_ia32_vpermt2varhi256_maskz">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_hi_512 : + def int_x86_avx512_mask_vpermt2var_hi_512 : GCCBuiltin<"__builtin_ia32_vpermt2varhi512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_hi_512 : + def int_x86_avx512_maskz_vpermt2var_hi_512 : GCCBuiltin<"__builtin_ia32_vpermt2varhi512_maskz">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_pd_128 : + def int_x86_avx512_mask_vpermt2var_pd_128 : GCCBuiltin<"__builtin_ia32_vpermt2varpd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2i64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_pd_128 : + def int_x86_avx512_maskz_vpermt2var_pd_128 : GCCBuiltin<"__builtin_ia32_vpermt2varpd128_maskz">, Intrinsic<[llvm_v2f64_ty], [llvm_v2i64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_pd_256 : + def int_x86_avx512_mask_vpermt2var_pd_256 : GCCBuiltin<"__builtin_ia32_vpermt2varpd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_pd_256 : + def int_x86_avx512_maskz_vpermt2var_pd_256 : GCCBuiltin<"__builtin_ia32_vpermt2varpd256_maskz">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_pd_512 : + def int_x86_avx512_maskz_vpermt2var_pd_512 : GCCBuiltin<"__builtin_ia32_vpermt2varpd512_maskz">, Intrinsic<[llvm_v8f64_ty], [llvm_v8i64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_ps_128 : + def int_x86_avx512_mask_vpermt2var_ps_128 : GCCBuiltin<"__builtin_ia32_vpermt2varps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_ps_128 : + def int_x86_avx512_maskz_vpermt2var_ps_128 : GCCBuiltin<"__builtin_ia32_vpermt2varps128_maskz">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_ps_256 : + def int_x86_avx512_mask_vpermt2var_ps_256 : GCCBuiltin<"__builtin_ia32_vpermt2varps256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_ps_256 : + def int_x86_avx512_maskz_vpermt2var_ps_256 : GCCBuiltin<"__builtin_ia32_vpermt2varps256_maskz">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_ps_512 : + def int_x86_avx512_maskz_vpermt2var_ps_512 : GCCBuiltin<"__builtin_ia32_vpermt2varps512_maskz">, Intrinsic<[llvm_v16f32_ty], [llvm_v16i32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_q_128 : + def int_x86_avx512_mask_vpermt2var_q_128 : GCCBuiltin<"__builtin_ia32_vpermt2varq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_q_128 : + def int_x86_avx512_maskz_vpermt2var_q_128 : GCCBuiltin<"__builtin_ia32_vpermt2varq128_maskz">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermt2var_q_256 : + def int_x86_avx512_mask_vpermt2var_q_256 : GCCBuiltin<"__builtin_ia32_vpermt2varq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_q_256 : + def int_x86_avx512_maskz_vpermt2var_q_256 : GCCBuiltin<"__builtin_ia32_vpermt2varq256_maskz">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_maskz_vpermt2var_q_512 : + def int_x86_avx512_maskz_vpermt2var_q_512 : GCCBuiltin<"__builtin_ia32_vpermt2varq512_maskz">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_pd_128 : - GCCBuiltin<"__builtin_ia32_vpermilpd_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty], + def int_x86_avx512_mask_vpermi2var_qi_128 : + GCCBuiltin<"__builtin_ia32_vpermi2varqi128_mask">, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_pd_256 : - GCCBuiltin<"__builtin_ia32_vpermilpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_i32_ty, llvm_v4f64_ty, llvm_i8_ty], + def int_x86_avx512_mask_vpermt2var_qi_128 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi128_mask">, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_pd_512 : - GCCBuiltin<"__builtin_ia32_vpermilpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_i32_ty, llvm_v8f64_ty, llvm_i8_ty], + def int_x86_avx512_maskz_vpermt2var_qi_128 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi128_maskz">, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_ps_128 : - GCCBuiltin<"__builtin_ia32_vpermilps_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty], + def int_x86_avx512_mask_vpermi2var_qi_256 : + GCCBuiltin<"__builtin_ia32_vpermi2varqi256_mask">, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_ps_256 : - GCCBuiltin<"__builtin_ia32_vpermilps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_i32_ty, llvm_v8f32_ty, llvm_i8_ty], + def int_x86_avx512_mask_vpermt2var_qi_256 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi256_mask">, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_ps_512 : - GCCBuiltin<"__builtin_ia32_vpermilps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], + def int_x86_avx512_maskz_vpermt2var_qi_256 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi256_maskz">, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], + [IntrNoMem]>; + + def int_x86_avx512_mask_vpermi2var_qi_512 : + GCCBuiltin<"__builtin_ia32_vpermi2varqi512_mask">, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], + [IntrNoMem]>; + + def int_x86_avx512_mask_vpermt2var_qi_512 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi512_mask">, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], + [IntrNoMem]>; + + def int_x86_avx512_maskz_vpermt2var_qi_512 : + GCCBuiltin<"__builtin_ia32_vpermt2varqi512_maskz">, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_mask_vpermilvar_pd_256 : @@ -1489,78 +1374,24 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [llvm_v4f32_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pshuf_b_128 : + def int_x86_avx512_mask_pshuf_b_128 : GCCBuiltin<"__builtin_ia32_pshufb128_mask">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pshuf_b_256 : + def int_x86_avx512_mask_pshuf_b_256 : GCCBuiltin<"__builtin_ia32_pshufb256_mask">, Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pshuf_b_512 : + def int_x86_avx512_mask_pshuf_b_512 : GCCBuiltin<"__builtin_ia32_pshufb512_mask">, Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pshuf_d_128 : - GCCBuiltin<"__builtin_ia32_pshufd128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_i16_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshuf_d_256 : - GCCBuiltin<"__builtin_ia32_pshufd256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_i16_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshuf_d_512 : - GCCBuiltin<"__builtin_ia32_pshufd512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_128 : - GCCBuiltin<"__builtin_ia32_pshufhw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_256 : - GCCBuiltin<"__builtin_ia32_pshufhw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_512 : - GCCBuiltin<"__builtin_ia32_pshufhw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_128 : - GCCBuiltin<"__builtin_ia32_pshuflw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_256 : - GCCBuiltin<"__builtin_ia32_pshuflw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_512 : - GCCBuiltin<"__builtin_ia32_pshuflw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_shuf_f32x4_256 : GCCBuiltin<"__builtin_ia32_shuf_f32x4_256_mask">, Intrinsic<[llvm_v8f32_ty], @@ -1644,60 +1475,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_128 : - GCCBuiltin<"__builtin_ia32_movshdup128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_256 : - GCCBuiltin<"__builtin_ia32_movshdup256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_512 : - GCCBuiltin<"__builtin_ia32_movshdup512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_128 : - GCCBuiltin<"__builtin_ia32_movsldup128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_256 : - GCCBuiltin<"__builtin_ia32_movsldup256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_512 : - GCCBuiltin<"__builtin_ia32_movsldup512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_128 : - GCCBuiltin<"__builtin_ia32_movddup128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_256 : - GCCBuiltin<"__builtin_ia32_movddup256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_512 : - GCCBuiltin<"__builtin_ia32_movddup512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; } // Vector blend @@ -1719,32 +1496,24 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Vector compare let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_cmp_pd_256 : GCCBuiltin<"__builtin_ia32_cmppd256">, + def int_x86_avx_cmp_pd_256 : Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx_cmp_ps_256 : GCCBuiltin<"__builtin_ia32_cmpps256">, + def int_x86_avx_cmp_ps_256 : Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; } // Vector convert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_cvtdq2_pd_256 : GCCBuiltin<"__builtin_ia32_cvtdq2pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_avx_cvtdq2_ps_256 : GCCBuiltin<"__builtin_ia32_cvtdq2ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty], [IntrNoMem]>; def int_x86_avx_cvt_pd2_ps_256 : GCCBuiltin<"__builtin_ia32_cvtpd2ps256">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f64_ty], [IntrNoMem]>; def int_x86_avx_cvt_ps2dq_256 : GCCBuiltin<"__builtin_ia32_cvtps2dq256">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty], [IntrNoMem]>; - def int_x86_avx_cvt_ps2_pd_256 : GCCBuiltin<"__builtin_ia32_cvtps2pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_avx_cvtt_pd2dq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2dq256">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty], [IntrNoMem]>; def int_x86_avx_cvt_pd2dq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2dq256">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty], [IntrNoMem]>; - def int_x86_avx_cvtt_ps2dq_256 : GCCBuiltin<"__builtin_ia32_cvttps2dq256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty], [IntrNoMem]>; } // Vector bit test @@ -1794,42 +1563,111 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_ptestnzc_256 : GCCBuiltin<"__builtin_ia32_ptestnzc256">, Intrinsic<[llvm_i32_ty], [llvm_v4i64_ty, llvm_v4i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ptestm_d_512 : GCCBuiltin<"__builtin_ia32_ptestmd512">, + def int_x86_avx512_ptestm_d_512 : GCCBuiltin<"__builtin_ia32_ptestmd512">, Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ptestm_q_512 : GCCBuiltin<"__builtin_ia32_ptestmq512">, + def int_x86_avx512_ptestm_q_512 : GCCBuiltin<"__builtin_ia32_ptestmq512">, Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_pd_128 : + + def int_x86_avx512_ptestm_b_128 : GCCBuiltin<"__builtin_ia32_ptestmb128">, + Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_b_256 : GCCBuiltin<"__builtin_ia32_ptestmb256">, + Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_b_512 : GCCBuiltin<"__builtin_ia32_ptestmb512">, + Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_d_128 : GCCBuiltin<"__builtin_ia32_ptestmd128">, + Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, + llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_d_256 : GCCBuiltin<"__builtin_ia32_ptestmd256">, + Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, + llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_q_128 : GCCBuiltin<"__builtin_ia32_ptestmq128">, + Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_q_256 : GCCBuiltin<"__builtin_ia32_ptestmq256">, + Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_w_128 : GCCBuiltin<"__builtin_ia32_ptestmw128">, + Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, + llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_w_256 : GCCBuiltin<"__builtin_ia32_ptestmw256">, + Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, + llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_ptestm_w_512 : GCCBuiltin<"__builtin_ia32_ptestmw512">, + Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, + llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_ptestnm_b_128 : GCCBuiltin<"__builtin_ia32_ptestnmb128">, + Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_b_256 : GCCBuiltin<"__builtin_ia32_ptestnmb256">, + Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_b_512 : GCCBuiltin<"__builtin_ia32_ptestnmb512">, + Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_d_128 : GCCBuiltin<"__builtin_ia32_ptestnmd128">, + Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, + llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_d_256 : GCCBuiltin<"__builtin_ia32_ptestnmd256">, + Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, + llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_d_512 : GCCBuiltin<"__builtin_ia32_ptestnmd512">, + Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, + llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_q_128 : GCCBuiltin<"__builtin_ia32_ptestnmq128">, + Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_q_256 : GCCBuiltin<"__builtin_ia32_ptestnmq256">, + Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_q_512 : GCCBuiltin<"__builtin_ia32_ptestnmq512">, + Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, + llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_w_128 : GCCBuiltin<"__builtin_ia32_ptestnmw128">, + Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, + llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_w_256 : GCCBuiltin<"__builtin_ia32_ptestnmw256">, + Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, + llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_ptestnm_w_512 : GCCBuiltin<"__builtin_ia32_ptestnmw512">, + Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, + llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_fpclass_pd_128 : GCCBuiltin<"__builtin_ia32_fpclasspd128_mask">, Intrinsic<[llvm_i8_ty], [llvm_v2f64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_pd_256 : + def int_x86_avx512_mask_fpclass_pd_256 : GCCBuiltin<"__builtin_ia32_fpclasspd256_mask">, Intrinsic<[llvm_i8_ty], [llvm_v4f64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_pd_512 : + def int_x86_avx512_mask_fpclass_pd_512 : GCCBuiltin<"__builtin_ia32_fpclasspd512_mask">, Intrinsic<[llvm_i8_ty], [llvm_v8f64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_ps_128 : + def int_x86_avx512_mask_fpclass_ps_128 : GCCBuiltin<"__builtin_ia32_fpclassps128_mask">, Intrinsic<[llvm_i8_ty], [llvm_v4f32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_ps_256 : + def int_x86_avx512_mask_fpclass_ps_256 : GCCBuiltin<"__builtin_ia32_fpclassps256_mask">, Intrinsic<[llvm_i8_ty], [llvm_v8f32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_ps_512 : + def int_x86_avx512_mask_fpclass_ps_512 : GCCBuiltin<"__builtin_ia32_fpclassps512_mask">, Intrinsic<[llvm_i16_ty], [llvm_v16f32_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_sd : - GCCBuiltin<"__builtin_ia32_fpclasssd">, + def int_x86_avx512_mask_fpclass_sd : + GCCBuiltin<"__builtin_ia32_fpclasssd_mask">, Intrinsic<[llvm_i8_ty], [llvm_v2f64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_fpclass_ss : - GCCBuiltin<"__builtin_ia32_fpclassss">, + def int_x86_avx512_mask_fpclass_ss : + GCCBuiltin<"__builtin_ia32_fpclassss_mask">, Intrinsic<[llvm_i8_ty], [llvm_v4f32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; } @@ -1854,10 +1692,10 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_vbroadcastf128_pd_256 : GCCBuiltin<"__builtin_ia32_vbroadcastf128_pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_vbroadcastf128_ps_256 : GCCBuiltin<"__builtin_ia32_vbroadcastf128_ps256">, - Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; } // SIMD load ops @@ -1866,91 +1704,32 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v32i8_ty], [llvm_ptr_ty], [IntrReadMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_storeu_pd_256 : GCCBuiltin<"__builtin_ia32_storeupd256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty], [IntrReadWriteArgMem]>; - def int_x86_avx_storeu_ps_256 : GCCBuiltin<"__builtin_ia32_storeups256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty], [IntrReadWriteArgMem]>; - def int_x86_avx_storeu_dq_256 : GCCBuiltin<"__builtin_ia32_storedqu256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v32i8_ty], [IntrReadWriteArgMem]>; -} - // Conditional load ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_maskload_pd : GCCBuiltin<"__builtin_ia32_maskloadpd">, Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty, llvm_v2i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_ps : GCCBuiltin<"__builtin_ia32_maskloadps">, Intrinsic<[llvm_v4f32_ty], [llvm_ptr_ty, llvm_v4i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_pd_256 : GCCBuiltin<"__builtin_ia32_maskloadpd256">, Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty, llvm_v4i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_ps_256 : GCCBuiltin<"__builtin_ia32_maskloadps256">, Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; +} - def int_x86_avx512_mask_loadu_ps_128 : - GCCBuiltin<"__builtin_ia32_loadups128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_ps_256 : - GCCBuiltin<"__builtin_ia32_loadups256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_ps_512 : - GCCBuiltin<"__builtin_ia32_loadups512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_pd_128 : - GCCBuiltin<"__builtin_ia32_loadupd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_pd_256 : - GCCBuiltin<"__builtin_ia32_loadupd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_pd_512 : - GCCBuiltin<"__builtin_ia32_loadupd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_ps_128 : - GCCBuiltin<"__builtin_ia32_loadaps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_ps_256 : - GCCBuiltin<"__builtin_ia32_loadaps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_ps_512 : - GCCBuiltin<"__builtin_ia32_loadaps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_pd_128 : - GCCBuiltin<"__builtin_ia32_loadapd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_pd_256 : - GCCBuiltin<"__builtin_ia32_loadapd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_pd_512 : - GCCBuiltin<"__builtin_ia32_loadapd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_move_ss : +// Conditional move ops +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_avx512_mask_move_ss : GCCBuiltin<"__builtin_ia32_movss_mask">, - Intrinsic<[llvm_v4f32_ty], + Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_move_sd : + def int_x86_avx512_mask_move_sd : GCCBuiltin<"__builtin_ia32_movsd_mask">, - Intrinsic<[llvm_v2f64_ty], + Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; } @@ -1959,38 +1738,23 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_maskstore_pd : GCCBuiltin<"__builtin_ia32_maskstorepd">, Intrinsic<[], [llvm_ptr_ty, - llvm_v2i64_ty, llvm_v2f64_ty], [IntrReadWriteArgMem]>; + llvm_v2i64_ty, llvm_v2f64_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_ps : GCCBuiltin<"__builtin_ia32_maskstoreps">, Intrinsic<[], [llvm_ptr_ty, - llvm_v4i32_ty, llvm_v4f32_ty], [IntrReadWriteArgMem]>; + llvm_v4i32_ty, llvm_v4f32_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_pd_256 : GCCBuiltin<"__builtin_ia32_maskstorepd256">, Intrinsic<[], [llvm_ptr_ty, - llvm_v4i64_ty, llvm_v4f64_ty], [IntrReadWriteArgMem]>; + llvm_v4i64_ty, llvm_v4f64_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_ps_256 : GCCBuiltin<"__builtin_ia32_maskstoreps256">, Intrinsic<[], [llvm_ptr_ty, - llvm_v8i32_ty, llvm_v8f32_ty], [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_ps_512 : - GCCBuiltin<"__builtin_ia32_storeups512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_pd_512 : - GCCBuiltin<"__builtin_ia32_storeupd512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_ps_512 : - GCCBuiltin<"__builtin_ia32_storeaps512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_pd_512 : - GCCBuiltin<"__builtin_ia32_storeapd512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + llvm_v8i32_ty, llvm_v8f32_ty], [IntrArgMemOnly]>; + def int_x86_avx512_mask_store_ss : GCCBuiltin<"__builtin_ia32_storess_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } //===----------------------------------------------------------------------===// @@ -2050,83 +1814,47 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Vector min, max let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx2_pmaxu_b : GCCBuiltin<"__builtin_ia32_pmaxub256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxu_w : GCCBuiltin<"__builtin_ia32_pmaxuw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxu_d : GCCBuiltin<"__builtin_ia32_pmaxud256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_b : GCCBuiltin<"__builtin_ia32_pmaxsb256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_w : GCCBuiltin<"__builtin_ia32_pmaxsw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_d : GCCBuiltin<"__builtin_ia32_pmaxsd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_b : GCCBuiltin<"__builtin_ia32_pminub256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_w : GCCBuiltin<"__builtin_ia32_pminuw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_d : GCCBuiltin<"__builtin_ia32_pminud256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_b : GCCBuiltin<"__builtin_ia32_pminsb256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_w : GCCBuiltin<"__builtin_ia32_pminsw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_d : GCCBuiltin<"__builtin_ia32_pminsd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; def int_x86_avx512_mask_pmaxs_b_128 : GCCBuiltin<"__builtin_ia32_pmaxsb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxs_b_256 : GCCBuiltin<"__builtin_ia32_pmaxsb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxs_b_512 : GCCBuiltin<"__builtin_ia32_pmaxsb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_b_128 : GCCBuiltin<"__builtin_ia32_pmaxub128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_b_256 : GCCBuiltin<"__builtin_ia32_pmaxub256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_b_512 : GCCBuiltin<"__builtin_ia32_pmaxub512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxs_w_128 : GCCBuiltin<"__builtin_ia32_pmaxsw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxs_w_256 : GCCBuiltin<"__builtin_ia32_pmaxsw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxs_w_512 : GCCBuiltin<"__builtin_ia32_pmaxsw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty],[IntrNoMem]>; def int_x86_avx512_mask_pmaxu_w_128 : GCCBuiltin<"__builtin_ia32_pmaxuw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_w_256 : GCCBuiltin<"__builtin_ia32_pmaxuw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_w_512 : GCCBuiltin<"__builtin_ia32_pmaxuw512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty],[IntrNoMem]>; def int_x86_avx512_mask_pmins_b_128 : GCCBuiltin<"__builtin_ia32_pminsb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty,llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmins_b_256 : GCCBuiltin<"__builtin_ia32_pminsb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmins_b_512 : GCCBuiltin<"__builtin_ia32_pminsb512_mask">, Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, @@ -2135,28 +1863,28 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pminu_b_256 : GCCBuiltin<"__builtin_ia32_pminub256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pminu_b_512 : GCCBuiltin<"__builtin_ia32_pminub512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmins_w_128 : GCCBuiltin<"__builtin_ia32_pminsw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmins_w_256 : GCCBuiltin<"__builtin_ia32_pminsw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmins_w_512 : GCCBuiltin<"__builtin_ia32_pminsw512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty],[IntrNoMem]>; def int_x86_avx512_mask_pminu_w_128 : GCCBuiltin<"__builtin_ia32_pminuw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pminu_w_256 : GCCBuiltin<"__builtin_ia32_pminuw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pminu_w_512 : GCCBuiltin<"__builtin_ia32_pminuw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaxu_d_512 : GCCBuiltin<"__builtin_ia32_pmaxud512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, @@ -2284,25 +2012,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pslli_d : GCCBuiltin<"__builtin_ia32_pslldi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pslli_q : GCCBuiltin<"__builtin_ia32_psllqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrli_d : GCCBuiltin<"__builtin_ia32_psrldi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrli_q : GCCBuiltin<"__builtin_ia32_psrlqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrai_d : GCCBuiltin<"__builtin_ia32_psradi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrai_q : GCCBuiltin<"__builtin_ia32_psraqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrl_w_128 : GCCBuiltin<"__builtin_ia32_psrlw128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; @@ -2314,13 +2023,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_wi_128 : GCCBuiltin<"__builtin_ia32_psrlwi128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_wi_256 : GCCBuiltin<"__builtin_ia32_psrlwi256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_wi_512 : GCCBuiltin<"__builtin_ia32_psrlwi512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, - llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_w_128 : GCCBuiltin<"__builtin_ia32_psraw128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, @@ -2333,13 +2042,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_wi_128 : GCCBuiltin<"__builtin_ia32_psrawi128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_wi_256 : GCCBuiltin<"__builtin_ia32_psrawi256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_wi_512 : GCCBuiltin<"__builtin_ia32_psrawi512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, - llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_d : GCCBuiltin<"__builtin_ia32_pslld512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, @@ -2371,13 +2080,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_wi_128 : GCCBuiltin<"__builtin_ia32_psllwi128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_wi_256 : GCCBuiltin<"__builtin_ia32_psllwi256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_wi_512 : GCCBuiltin<"__builtin_ia32_psllwi512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, - llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psllv16_hi : GCCBuiltin<"__builtin_ia32_psllv16hi_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; @@ -2404,64 +2113,76 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_d_256 : GCCBuiltin<"__builtin_ia32_psrad256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v4i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_di_128 : GCCBuiltin<"__builtin_ia32_psradi128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, - llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, + llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_di_256 : GCCBuiltin<"__builtin_ia32_psradi256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_di_512 : GCCBuiltin<"__builtin_ia32_psradi512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_q_128 : GCCBuiltin<"__builtin_ia32_psraq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_q_256 : GCCBuiltin<"__builtin_ia32_psraq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v2i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_qi_128 : GCCBuiltin<"__builtin_ia32_psraqi128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, - llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, + llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_qi_256 : GCCBuiltin<"__builtin_ia32_psraqi256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + llvm_i32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psra_qi_512 : GCCBuiltin<"__builtin_ia32_psraqi512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, + llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_d_128: GCCBuiltin<"__builtin_ia32_psrld128_mask">, Intrinsic<[llvm_v4i32_ty], [ llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty ], [IntrNoMem]>; def int_x86_avx512_mask_psrl_d_256: GCCBuiltin<"__builtin_ia32_psrld256_mask">, - Intrinsic<[llvm_v8i32_ty], [ llvm_v8i32_ty, + Intrinsic<[llvm_v8i32_ty], [ llvm_v8i32_ty, llvm_v4i32_ty, llvm_v8i32_ty, llvm_i8_ty ], [IntrNoMem]>; def int_x86_avx512_mask_psrl_di_128: GCCBuiltin<"__builtin_ia32_psrldi128_mask">, - Intrinsic<[llvm_v4i32_ty], [ llvm_v4i32_ty, - llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty ], [IntrNoMem]>; + Intrinsic<[llvm_v4i32_ty], [ llvm_v4i32_ty, + llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty ], [IntrNoMem]>; def int_x86_avx512_mask_psrl_di_256: GCCBuiltin<"__builtin_ia32_psrldi256_mask">, - Intrinsic<[llvm_v8i32_ty], [ llvm_v8i32_ty, - llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty ], [IntrNoMem]>; + Intrinsic<[llvm_v8i32_ty], [ llvm_v8i32_ty, + llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty ], [IntrNoMem]>; def int_x86_avx512_mask_psrl_di_512: GCCBuiltin<"__builtin_ia32_psrldi512_mask">, - Intrinsic<[llvm_v16i32_ty], [ llvm_v16i32_ty, - llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty ], [IntrNoMem]>; + Intrinsic<[llvm_v16i32_ty], [ llvm_v16i32_ty, + llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty ], [IntrNoMem]>; def int_x86_avx512_mask_psrl_q_128: GCCBuiltin<"__builtin_ia32_psrlq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_q_256: GCCBuiltin<"__builtin_ia32_psrlq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v2i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_qi_128: GCCBuiltin<"__builtin_ia32_psrlqi128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, - llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_qi_256: GCCBuiltin<"__builtin_ia32_psrlqi256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrl_qi_512: GCCBuiltin<"__builtin_ia32_psrlqi512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, + llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pmultishift_qb_128: + GCCBuiltin<"__builtin_ia32_vpmultishiftqb128_mask">, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pmultishift_qb_256: + GCCBuiltin<"__builtin_ia32_vpmultishiftqb256_mask">, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pmultishift_qb_512: + GCCBuiltin<"__builtin_ia32_vpmultishiftqb512_mask">, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; } // Pack ops. @@ -2489,73 +2210,73 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_pabs_d : GCCBuiltin<"__builtin_ia32_pabsd256">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_b_128 : + def int_x86_avx512_mask_pabs_b_128 : GCCBuiltin<"__builtin_ia32_pabsb128_mask">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_b_256 : + def int_x86_avx512_mask_pabs_b_256 : GCCBuiltin<"__builtin_ia32_pabsb256_mask">, Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_b_512 : + def int_x86_avx512_mask_pabs_b_512 : GCCBuiltin<"__builtin_ia32_pabsb512_mask">, Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_d_128 : + def int_x86_avx512_mask_pabs_d_128 : GCCBuiltin<"__builtin_ia32_pabsd128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_d_256 : + def int_x86_avx512_mask_pabs_d_256 : GCCBuiltin<"__builtin_ia32_pabsd256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_d_512 : + def int_x86_avx512_mask_pabs_d_512 : GCCBuiltin<"__builtin_ia32_pabsd512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_q_128 : + def int_x86_avx512_mask_pabs_q_128 : GCCBuiltin<"__builtin_ia32_pabsq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_q_256 : + def int_x86_avx512_mask_pabs_q_256 : GCCBuiltin<"__builtin_ia32_pabsq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_q_512 : + def int_x86_avx512_mask_pabs_q_512 : GCCBuiltin<"__builtin_ia32_pabsq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_w_128 : + def int_x86_avx512_mask_pabs_w_128 : GCCBuiltin<"__builtin_ia32_pabsw128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_w_256 : + def int_x86_avx512_mask_pabs_w_256 : GCCBuiltin<"__builtin_ia32_pabsw256_mask">, Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pabs_w_512 : + def int_x86_avx512_mask_pabs_w_512 : GCCBuiltin<"__builtin_ia32_pabsw512_mask">, Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], @@ -2606,56 +2327,16 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty], [IntrNoMem, Commutative]>; def int_x86_avx512_mask_pmul_hr_sw_128 : GCCBuiltin<"__builtin_ia32_pmulhrsw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmul_hr_sw_256 : GCCBuiltin<"__builtin_ia32_pmulhrsw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmul_hr_sw_512 : GCCBuiltin<"__builtin_ia32_pmulhrsw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; } -// Vector sign and zero extend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx2_pmovsxbd : GCCBuiltin<"__builtin_ia32_pmovsxbd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxbq : GCCBuiltin<"__builtin_ia32_pmovsxbq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxbw : GCCBuiltin<"__builtin_ia32_pmovsxbw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxdq : GCCBuiltin<"__builtin_ia32_pmovsxdq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxwd : GCCBuiltin<"__builtin_ia32_pmovsxwd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxwq : GCCBuiltin<"__builtin_ia32_pmovsxwq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbd : GCCBuiltin<"__builtin_ia32_pmovzxbd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbq : GCCBuiltin<"__builtin_ia32_pmovzxbq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbw : GCCBuiltin<"__builtin_ia32_pmovzxbw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxwd : GCCBuiltin<"__builtin_ia32_pmovzxwd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxwq : GCCBuiltin<"__builtin_ia32_pmovzxwq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; -} - // Vector blend let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_pblendvb : GCCBuiltin<"__builtin_ia32_pblendvb256">, @@ -2665,18 +2346,62 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Vector load with broadcast let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_avx512_mask_pbroadcast_b_gpr_128 : + GCCBuiltin<"__builtin_ia32_pbroadcastb128_gpr_mask">, + Intrinsic<[llvm_v16i8_ty], + [llvm_i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_b_gpr_256 : + GCCBuiltin<"__builtin_ia32_pbroadcastb256_gpr_mask">, + Intrinsic<[llvm_v32i8_ty], + [llvm_i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_b_gpr_512 : + GCCBuiltin<"__builtin_ia32_pbroadcastb512_gpr_mask">, + Intrinsic<[llvm_v64i8_ty], + [llvm_i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_pbroadcast_w_gpr_128 : + GCCBuiltin<"__builtin_ia32_pbroadcastw128_gpr_mask">, + Intrinsic<[llvm_v8i16_ty], + [llvm_i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_w_gpr_256 : + GCCBuiltin<"__builtin_ia32_pbroadcastw256_gpr_mask">, + Intrinsic<[llvm_v16i16_ty], + [llvm_i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_w_gpr_512 : + GCCBuiltin<"__builtin_ia32_pbroadcastw512_gpr_mask">, + Intrinsic<[llvm_v32i16_ty], + [llvm_i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_pbroadcast_d_gpr_128 : + GCCBuiltin<"__builtin_ia32_pbroadcastd128_gpr_mask">, + Intrinsic<[llvm_v4i32_ty], + [llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_d_gpr_256 : + GCCBuiltin<"__builtin_ia32_pbroadcastd256_gpr_mask">, + Intrinsic<[llvm_v8i32_ty], + [llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pbroadcast_d_gpr_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastd512_gpr_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_i32_ty, llvm_v16i32_ty, - llvm_i16_ty], [IntrNoMem]>; + GCCBuiltin<"__builtin_ia32_pbroadcastd512_gpr_mask">, + Intrinsic<[llvm_v16i32_ty], + [llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_pbroadcast_q_gpr_128 : + GCCBuiltin<"__builtin_ia32_pbroadcastq128_gpr_mask">, + Intrinsic<[llvm_v2i64_ty], + [llvm_i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_q_gpr_256 : + GCCBuiltin<"__builtin_ia32_pbroadcastq256_gpr_mask">, + Intrinsic<[llvm_v4i64_ty], + [llvm_i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pbroadcast_q_gpr_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastq512_gpr_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_i64_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrNoMem]>; + GCCBuiltin<"__builtin_ia32_pbroadcastq512_gpr_mask">, + Intrinsic<[llvm_v8i64_ty], + [llvm_i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_pbroadcast_q_mem_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastq512_mem_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_i64_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrNoMem]>; + GCCBuiltin<"__builtin_ia32_pbroadcastq512_mem_mask">, + Intrinsic<[llvm_v8i64_ty], + [llvm_i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } // Vector permutation @@ -2750,9 +2475,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_insertf32x4_512 : - GCCBuiltin<"__builtin_ia32_insertf32x4_512_mask">, + GCCBuiltin<"__builtin_ia32_insertf32x4_mask">, Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i8_ty], + [llvm_v16f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_insertf32x8_512 : @@ -2786,9 +2511,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_inserti32x4_512 : - GCCBuiltin<"__builtin_ia32_inserti32x4_512_mask">, + GCCBuiltin<"__builtin_ia32_inserti32x4_mask">, Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v16i32_ty, llvm_i8_ty], + [llvm_v16i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_inserti32x8_512 : @@ -2813,55 +2538,41 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". GCCBuiltin<"__builtin_ia32_inserti64x4_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; + [IntrNoMem]>; } // Conditional load ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_maskload_d : GCCBuiltin<"__builtin_ia32_maskloadd">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_v4i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_q : GCCBuiltin<"__builtin_ia32_maskloadq">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_v2i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_d_256 : GCCBuiltin<"__builtin_ia32_maskloadd256">, Intrinsic<[llvm_v8i32_ty], [llvm_ptr_ty, llvm_v8i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_q_256 : GCCBuiltin<"__builtin_ia32_maskloadq256">, Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty, llvm_v4i64_ty], - [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_d_512 : GCCBuiltin<"__builtin_ia32_loaddqusi512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_q_512 : GCCBuiltin<"__builtin_ia32_loaddqudi512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; } // Conditional store ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_maskstore_d : GCCBuiltin<"__builtin_ia32_maskstored">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_q : GCCBuiltin<"__builtin_ia32_maskstoreq">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_v2i64_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_d_256 : GCCBuiltin<"__builtin_ia32_maskstored256">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_v8i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_q_256 : GCCBuiltin<"__builtin_ia32_maskstoreq256">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i64_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_d_512 : - GCCBuiltin<"__builtin_ia32_storedqusi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_q_512 : - GCCBuiltin<"__builtin_ia32_storedqudi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } // Variable bit shift ops @@ -2905,7 +2616,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_psllv_q : GCCBuiltin<"__builtin_ia32_psllv8di_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], + llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav_d : GCCBuiltin<"__builtin_ia32_psrav16si_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, @@ -2921,66 +2632,60 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_psrlv_q : GCCBuiltin<"__builtin_ia32_psrlv8di_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_psll_dq_512 : GCCBuiltin<"__builtin_ia32_pslldq512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_i32_ty], + llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_psrl_dq_512 : GCCBuiltin<"__builtin_ia32_psrldq512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_i32_ty], - [IntrNoMem]>; def int_x86_avx512_mask_psll_d_128 : GCCBuiltin<"__builtin_ia32_pslld128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_d_256 : GCCBuiltin<"__builtin_ia32_pslld256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v4i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_di_128 : GCCBuiltin<"__builtin_ia32_pslldi128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, - llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, + llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_di_256 : GCCBuiltin<"__builtin_ia32_pslldi256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_di_512 : GCCBuiltin<"__builtin_ia32_pslldi512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, + llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_q_128 : GCCBuiltin<"__builtin_ia32_psllq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_q_256 : GCCBuiltin<"__builtin_ia32_psllq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v2i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_qi_128 : GCCBuiltin<"__builtin_ia32_psllqi128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, - llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, + llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_qi_256 : GCCBuiltin<"__builtin_ia32_psllqi256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + llvm_i32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psll_qi_512 : GCCBuiltin<"__builtin_ia32_psllqi512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, + llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav16_hi : GCCBuiltin<"__builtin_ia32_psrav16hi_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav32_hi : GCCBuiltin<"__builtin_ia32_psrav32hi_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav4_si : GCCBuiltin<"__builtin_ia32_psrav4si_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, + Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav8_hi : GCCBuiltin<"__builtin_ia32_psrav8hi_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav8_si : GCCBuiltin<"__builtin_ia32_psrav8si_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav_q_128 : GCCBuiltin<"__builtin_ia32_psravq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrav_q_256 : GCCBuiltin<"__builtin_ia32_psravq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv16_hi : GCCBuiltin<"__builtin_ia32_psrlv16hi_mask">, @@ -2990,19 +2695,19 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv32hi : GCCBuiltin<"__builtin_ia32_psrlv32hi_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv4_di : GCCBuiltin<"__builtin_ia32_psrlv4di_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv4_si : GCCBuiltin<"__builtin_ia32_psrlv4si_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, + Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv8_hi : GCCBuiltin<"__builtin_ia32_psrlv8hi_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_psrlv8_si : GCCBuiltin<"__builtin_ia32_psrlv8si_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prorv_d_128 : GCCBuiltin<"__builtin_ia32_prorvd128_mask">, @@ -3026,22 +2731,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_prol_d_128 : GCCBuiltin<"__builtin_ia32_prold128_mask">, Intrinsic<[llvm_v4i32_ty] , [llvm_v4i32_ty, - llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prol_d_256 : GCCBuiltin<"__builtin_ia32_prold256_mask">, Intrinsic<[llvm_v8i32_ty] , [llvm_v8i32_ty, - llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prol_d_512 : GCCBuiltin<"__builtin_ia32_prold512_mask">, Intrinsic<[llvm_v16i32_ty] , [llvm_v16i32_ty, - llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_prol_q_128 : GCCBuiltin<"__builtin_ia32_prolq128_mask">, Intrinsic<[llvm_v2i64_ty] , [llvm_v2i64_ty, - llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prol_q_256 : GCCBuiltin<"__builtin_ia32_prolq256_mask">, Intrinsic<[llvm_v4i64_ty] , [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prol_q_512 : GCCBuiltin<"__builtin_ia32_prolq512_mask">, Intrinsic<[llvm_v8i64_ty] , [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_prolv_d_128 : GCCBuiltin<"__builtin_ia32_prolvd128_mask">, @@ -3064,22 +2769,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_d_128 : GCCBuiltin<"__builtin_ia32_prord128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, - llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_d_256 : GCCBuiltin<"__builtin_ia32_prord256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_d_512 : GCCBuiltin<"__builtin_ia32_prord512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_q_128 : GCCBuiltin<"__builtin_ia32_prorq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, - llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_q_256 : GCCBuiltin<"__builtin_ia32_prorq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + llvm_i32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pror_q_512 : GCCBuiltin<"__builtin_ia32_prorq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, + llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } @@ -3088,68 +2793,68 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_gather_d_pd : GCCBuiltin<"__builtin_ia32_gatherd_pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_pd_256 : GCCBuiltin<"__builtin_ia32_gatherd_pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_pd : GCCBuiltin<"__builtin_ia32_gatherq_pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_pd_256 : GCCBuiltin<"__builtin_ia32_gatherq_pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_ps : GCCBuiltin<"__builtin_ia32_gatherd_ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_ps_256 : GCCBuiltin<"__builtin_ia32_gatherd_ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_ps : GCCBuiltin<"__builtin_ia32_gatherq_ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_ps_256 : GCCBuiltin<"__builtin_ia32_gatherq_ps256">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_q : GCCBuiltin<"__builtin_ia32_gatherd_q">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_q_256 : GCCBuiltin<"__builtin_ia32_gatherd_q256">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_q : GCCBuiltin<"__builtin_ia32_gatherq_q">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_q_256 : GCCBuiltin<"__builtin_ia32_gatherq_q256">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_d : GCCBuiltin<"__builtin_ia32_gatherd_d">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_d_256 : GCCBuiltin<"__builtin_ia32_gatherd_d256">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_d : GCCBuiltin<"__builtin_ia32_gatherq_d">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_d_256 : GCCBuiltin<"__builtin_ia32_gatherq_d256">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; } // Misc. @@ -3520,6 +3225,43 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_vfmadd_sd : + GCCBuiltin<"__builtin_ia32_vfmaddsd3_mask">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask_vfmadd_ss : + GCCBuiltin<"__builtin_ia32_vfmaddss3_mask">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_maskz_vfmadd_sd : + GCCBuiltin<"__builtin_ia32_vfmaddsd3_maskz">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_maskz_vfmadd_ss : + GCCBuiltin<"__builtin_ia32_vfmaddss3_maskz">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask3_vfmadd_sd : + GCCBuiltin<"__builtin_ia32_vfmaddsd3_mask3">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + + def int_x86_avx512_mask3_vfmadd_ss : + GCCBuiltin<"__builtin_ia32_vfmaddss3_mask3">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask3_vfmsub_pd_128 : GCCBuiltin<"__builtin_ia32_vfmsubpd128_mask3">, Intrinsic<[llvm_v2f64_ty], @@ -3700,30 +3442,79 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52h_uq_128 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq128_mask">, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52h_uq_128 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq128_maskz">, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52l_uq_128 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq128_mask">, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52l_uq_128 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq128_maskz">, + Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52h_uq_256 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq256_mask">, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52h_uq_256 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq256_maskz">, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52l_uq_256 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq256_mask">, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52l_uq_256 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq256_maskz">, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52h_uq_512 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq512_mask">, + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, + llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52h_uq_512 : + GCCBuiltin<"__builtin_ia32_vpmadd52huq512_maskz">, + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, + llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_vpmadd52l_uq_512 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq512_mask">, + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, + llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_vpmadd52l_uq_512 : + GCCBuiltin<"__builtin_ia32_vpmadd52luq512_maskz">, + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, + llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } //===----------------------------------------------------------------------===// // XOP +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xop_vpermil2pd : GCCBuiltin<"__builtin_ia32_vpermil2pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2pd_256 : GCCBuiltin<"__builtin_ia32_vpermil2pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2ps : GCCBuiltin<"__builtin_ia32_vpermil2ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], + llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2ps_256 : GCCBuiltin<"__builtin_ia32_vpermil2ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], + llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vfrcz_pd : GCCBuiltin<"__builtin_ia32_vfrczpd">, @@ -3943,6 +3734,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". GCCBuiltin<"__builtin_ia32_vpshlw">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; +} //===----------------------------------------------------------------------===// // MMX @@ -4131,7 +3923,51 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; } - +// Permute +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_avx512_mask_permvar_df_256 : GCCBuiltin<"__builtin_ia32_permvardf256_mask">, + Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, + llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_df_512 : GCCBuiltin<"__builtin_ia32_permvardf512_mask">, + Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, + llvm_v8i64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_di_256 : GCCBuiltin<"__builtin_ia32_permvardi256_mask">, + Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, + llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_di_512 : GCCBuiltin<"__builtin_ia32_permvardi512_mask">, + Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, + llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_hi_128 : GCCBuiltin<"__builtin_ia32_permvarhi128_mask">, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, + llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_hi_256 : GCCBuiltin<"__builtin_ia32_permvarhi256_mask">, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, + llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_hi_512 : GCCBuiltin<"__builtin_ia32_permvarhi512_mask">, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, + llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_qi_128 : GCCBuiltin<"__builtin_ia32_permvarqi128_mask">, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, + llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_qi_256 : GCCBuiltin<"__builtin_ia32_permvarqi256_mask">, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, + llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_qi_512 : GCCBuiltin<"__builtin_ia32_permvarqi512_mask">, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, + llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_sf_256 : GCCBuiltin<"__builtin_ia32_permvarsf256_mask">, + Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, + llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_sf_512 : GCCBuiltin<"__builtin_ia32_permvarsf512_mask">, + Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, + llvm_v16i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_si_256 : GCCBuiltin<"__builtin_ia32_permvarsi256_mask">, + Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, + llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_avx512_mask_permvar_si_512 : GCCBuiltin<"__builtin_ia32_permvarsi512_mask">, + Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, + llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; +} // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_mmx_packsswb : GCCBuiltin<"__builtin_ia32_packsswb">, @@ -4301,6 +4137,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". } //===----------------------------------------------------------------------===// +// CLFLUSHOPT +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_clflushopt : GCCBuiltin<"__builtin_ia32_clflushopt">, + Intrinsic<[], [llvm_ptr_ty], []>; +} + +//===----------------------------------------------------------------------===// // Support protection key let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_rdpkru : GCCBuiltin <"__builtin_ia32_rdpkru">, @@ -4374,22 +4217,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_addcarryx_u32: GCCBuiltin<"__builtin_ia32_addcarryx_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarryx_u64: GCCBuiltin<"__builtin_ia32_addcarryx_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarry_u32: GCCBuiltin<"__builtin_ia32_addcarry_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarry_u64: GCCBuiltin<"__builtin_ia32_addcarry_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_subborrow_u32: GCCBuiltin<"__builtin_ia32_subborrow_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_subborrow_u64: GCCBuiltin<"__builtin_ia32_subborrow_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; } //===----------------------------------------------------------------------===// @@ -4401,7 +4244,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xend : GCCBuiltin<"__builtin_ia32_xend">, Intrinsic<[], [], []>; def int_x86_xabort : GCCBuiltin<"__builtin_ia32_xabort">, - Intrinsic<[], [llvm_i8_ty], [IntrNoReturn]>; + Intrinsic<[], [llvm_i8_ty], []>; def int_x86_xtest : GCCBuiltin<"__builtin_ia32_xtest">, Intrinsic<[llvm_i32_ty], [], []>; } @@ -4445,7 +4288,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_kortestc_w : GCCBuiltin<"__builtin_ia32_kortestchi">, Intrinsic<[llvm_i32_ty], [llvm_i16_ty, llvm_i16_ty], [IntrNoMem]>; - + def int_x86_avx512_mask_pmovsxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxbd128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; @@ -4504,10 +4347,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Conversion ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_cvtss2usi : GCCBuiltin<"__builtin_ia32_cvtss2usi">, - Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_avx512_cvtss2usi64 : GCCBuiltin<"__builtin_ia32_cvtss2usi64">, - Intrinsic<[llvm_i64_ty], [llvm_v4f32_ty], [IntrNoMem]>; def int_x86_avx512_cvttss2si : GCCBuiltin<"__builtin_ia32_vcvttss2si32">, Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_cvttss2si64 : GCCBuiltin<"__builtin_ia32_vcvttss2si64">, @@ -4522,11 +4361,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_cvtusi642ss : GCCBuiltin<"__builtin_ia32_cvtusi2ss64">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i64_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtsd2usi : GCCBuiltin<"__builtin_ia32_cvtsd2usi">, - Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_avx512_cvtsd2usi64 : GCCBuiltin<"__builtin_ia32_cvtsd2usi64">, - Intrinsic<[llvm_i64_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_avx512_cvttsd2si : GCCBuiltin<"__builtin_ia32_vcvttsd2si32">, Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_cvttsd2si64 : GCCBuiltin<"__builtin_ia32_vcvttsd2si64">, @@ -4541,7 +4375,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_cvtusi642sd : GCCBuiltin<"__builtin_ia32_cvtusi2sd64">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_i64_ty, llvm_i32_ty], [IntrNoMem]>; - + def int_x86_avx512_vcvtss2usi32 : GCCBuiltin<"__builtin_ia32_vcvtss2usi32">, + Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtss2usi64 : GCCBuiltin<"__builtin_ia32_vcvtss2usi64">, + Intrinsic<[llvm_i64_ty], [llvm_v4f32_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtss2si32 : GCCBuiltin<"__builtin_ia32_vcvtss2si32">, + Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtss2si64 : GCCBuiltin<"__builtin_ia32_vcvtss2si64">, + Intrinsic<[llvm_i64_ty], [llvm_v4f32_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtsd2usi32 : GCCBuiltin<"__builtin_ia32_vcvtsd2usi32">, + Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtsd2usi64 : GCCBuiltin<"__builtin_ia32_vcvtsd2usi64">, + Intrinsic<[llvm_i64_ty], [llvm_v2f64_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtsd2si32 : GCCBuiltin<"__builtin_ia32_vcvtsd2si32">, + Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_vcvtsd2si64 : GCCBuiltin<"__builtin_ia32_vcvtsd2si64">, + Intrinsic<[llvm_i64_ty], [llvm_v2f64_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtsi2ss32 : GCCBuiltin<"__builtin_ia32_cvtsi2ss32">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; @@ -4553,7 +4402,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtsi2sd64 : GCCBuiltin<"__builtin_ia32_cvtsi2sd64">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, - llvm_i64_ty, llvm_i32_ty], [IntrNoMem]>; + llvm_i64_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtb2mask_128 : GCCBuiltin<"__builtin_ia32_cvtb2mask128">, Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty], [IntrNoMem]>; @@ -4561,23 +4410,23 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty], [IntrNoMem]>; def int_x86_avx512_cvtb2mask_512 : GCCBuiltin<"__builtin_ia32_cvtb2mask512">, Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty], [IntrNoMem]>; - + def int_x86_avx512_cvtw2mask_128 : GCCBuiltin<"__builtin_ia32_cvtw2mask128">, Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty], [IntrNoMem]>; def int_x86_avx512_cvtw2mask_256 : GCCBuiltin<"__builtin_ia32_cvtw2mask256">, Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty], [IntrNoMem]>; def int_x86_avx512_cvtw2mask_512 : GCCBuiltin<"__builtin_ia32_cvtw2mask512">, Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty], [IntrNoMem]>; - + def int_x86_avx512_cvtd2mask_128 : GCCBuiltin<"__builtin_ia32_cvtd2mask128">, Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtd2mask_256 : GCCBuiltin<"__builtin_ia32_cvtd2mask256">, - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtd2mask_512 : GCCBuiltin<"__builtin_ia32_cvtd2mask512">, Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty], [IntrNoMem]>; def int_x86_avx512_cvtq2mask_128 : GCCBuiltin<"__builtin_ia32_cvtq2mask128">, - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty], [IntrNoMem]>; def int_x86_avx512_cvtq2mask_256 : GCCBuiltin<"__builtin_ia32_cvtq2mask256">, Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty], [IntrNoMem]>; def int_x86_avx512_cvtq2mask_512 : GCCBuiltin<"__builtin_ia32_cvtq2mask512">, @@ -4589,28 +4438,28 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 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]>; + 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]>; + 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. @@ -4622,7 +4471,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 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, + 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, @@ -4640,7 +4489,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 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, + 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, @@ -4653,702 +4502,483 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; } -// Unpack ops. -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_unpckh_pd_128 : - GCCBuiltin<"__builtin_ia32_unpckhpd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_pd_256 : - GCCBuiltin<"__builtin_ia32_unpckhpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_pd_512 : - GCCBuiltin<"__builtin_ia32_unpckhpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_128 : - GCCBuiltin<"__builtin_ia32_unpckhps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_256 : - GCCBuiltin<"__builtin_ia32_unpckhps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_512 : - GCCBuiltin<"__builtin_ia32_unpckhps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_128 : - GCCBuiltin<"__builtin_ia32_unpcklpd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_256 : - GCCBuiltin<"__builtin_ia32_unpcklpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_512 : - GCCBuiltin<"__builtin_ia32_unpcklpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_128 : - GCCBuiltin<"__builtin_ia32_unpcklps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_256 : - GCCBuiltin<"__builtin_ia32_unpcklps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_512 : - GCCBuiltin<"__builtin_ia32_unpcklps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_128 : - GCCBuiltin<"__builtin_ia32_punpckhbw128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_256 : - GCCBuiltin<"__builtin_ia32_punpckhbw256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_512 : - GCCBuiltin<"__builtin_ia32_punpckhbw512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_128 : - GCCBuiltin<"__builtin_ia32_punpckhdq128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_256 : - GCCBuiltin<"__builtin_ia32_punpckhdq256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_512 : - GCCBuiltin<"__builtin_ia32_punpckhdq512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_128 : - GCCBuiltin<"__builtin_ia32_punpckhqdq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_256 : - GCCBuiltin<"__builtin_ia32_punpckhqdq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_512 : - GCCBuiltin<"__builtin_ia32_punpckhqdq512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_128 : - GCCBuiltin<"__builtin_ia32_punpckhwd128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_256 : - GCCBuiltin<"__builtin_ia32_punpckhwd256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_512 : - GCCBuiltin<"__builtin_ia32_punpckhwd512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_128 : - GCCBuiltin<"__builtin_ia32_punpcklbw128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_256 : - GCCBuiltin<"__builtin_ia32_punpcklbw256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_512 : - GCCBuiltin<"__builtin_ia32_punpcklbw512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_128 : - GCCBuiltin<"__builtin_ia32_punpckldq128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_256 : - GCCBuiltin<"__builtin_ia32_punpckldq256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_512 : - GCCBuiltin<"__builtin_ia32_punpckldq512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_128 : - GCCBuiltin<"__builtin_ia32_punpcklqdq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_256 : - GCCBuiltin<"__builtin_ia32_punpcklqdq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_512 : - GCCBuiltin<"__builtin_ia32_punpcklqdq512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_128 : - GCCBuiltin<"__builtin_ia32_punpcklwd128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_256 : - GCCBuiltin<"__builtin_ia32_punpcklwd256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_512 : - GCCBuiltin<"__builtin_ia32_punpcklwd512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; -} - // Vector convert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_cvtdq2pd_128 : + def int_x86_avx512_mask_cvtdq2pd_128 : GCCBuiltin<"__builtin_ia32_cvtdq2pd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v4i32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtdq2pd_256 : + def int_x86_avx512_mask_cvtdq2pd_256 : GCCBuiltin<"__builtin_ia32_cvtdq2pd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i32_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtdq2pd_512 : + def int_x86_avx512_mask_cvtdq2pd_512 : GCCBuiltin<"__builtin_ia32_cvtdq2pd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8i32_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtdq2ps_128 : + def int_x86_avx512_mask_cvtdq2ps_128 : GCCBuiltin<"__builtin_ia32_cvtdq2ps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtdq2ps_256 : + def int_x86_avx512_mask_cvtdq2ps_256 : GCCBuiltin<"__builtin_ia32_cvtdq2ps256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtdq2ps_512 : + def int_x86_avx512_mask_cvtdq2ps_512 : GCCBuiltin<"__builtin_ia32_cvtdq2ps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16i32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2dq_128 : + def int_x86_avx512_mask_cvtpd2dq_128 : GCCBuiltin<"__builtin_ia32_cvtpd2dq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v2f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2dq_256 : + def int_x86_avx512_mask_cvtpd2dq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2dq256_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2dq_512 : + def int_x86_avx512_mask_cvtpd2dq_512 : GCCBuiltin<"__builtin_ia32_cvtpd2dq512_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f64_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2ps_256 : + def int_x86_avx512_mask_cvtpd2ps_256 : GCCBuiltin<"__builtin_ia32_cvtpd2ps256_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2ps_512 : + def int_x86_avx512_mask_cvtpd2ps_512 : GCCBuiltin<"__builtin_ia32_cvtpd2ps512_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f64_ty, llvm_v8f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtsd2ss_round : - GCCBuiltin<"__builtin_ia32_cvtsd2ss_round">, + def int_x86_avx512_mask_cvtsd2ss_round : + GCCBuiltin<"__builtin_ia32_cvtsd2ss_round_mask">, Intrinsic<[llvm_v4f32_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], + [llvm_v4f32_ty, llvm_v2f64_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtss2sd_round : - GCCBuiltin<"__builtin_ia32_cvtss2sd_round">, + def int_x86_avx512_mask_cvtss2sd_round : + GCCBuiltin<"__builtin_ia32_cvtss2sd_round_mask">, Intrinsic<[llvm_v2f64_ty], - [ llvm_v4f32_ty, llvm_v4f32_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], + [llvm_v2f64_ty, llvm_v4f32_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2ps : + def int_x86_avx512_mask_cvtpd2ps : GCCBuiltin<"__builtin_ia32_cvtpd2ps_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v2f64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2qq_128 : + def int_x86_avx512_mask_cvtpd2qq_128 : GCCBuiltin<"__builtin_ia32_cvtpd2qq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2f64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2qq_256 : + def int_x86_avx512_mask_cvtpd2qq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2qq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2qq_512 : + def int_x86_avx512_mask_cvtpd2qq_512 : GCCBuiltin<"__builtin_ia32_cvtpd2qq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f64_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2udq_128 : + def int_x86_avx512_mask_cvtpd2udq_128 : GCCBuiltin<"__builtin_ia32_cvtpd2udq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v2f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2udq_256 : + def int_x86_avx512_mask_cvtpd2udq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2udq256_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2udq_512 : + def int_x86_avx512_mask_cvtpd2udq_512 : GCCBuiltin<"__builtin_ia32_cvtpd2udq512_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f64_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2uqq_128 : + def int_x86_avx512_mask_cvtpd2uqq_128 : GCCBuiltin<"__builtin_ia32_cvtpd2uqq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2f64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2uqq_256 : + def int_x86_avx512_mask_cvtpd2uqq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2uqq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtpd2uqq_512 : + def int_x86_avx512_mask_cvtpd2uqq_512 : GCCBuiltin<"__builtin_ia32_cvtpd2uqq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f64_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2dq_128 : + def int_x86_avx512_mask_cvtps2dq_128 : GCCBuiltin<"__builtin_ia32_cvtps2dq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2dq_256 : + def int_x86_avx512_mask_cvtps2dq_256 : GCCBuiltin<"__builtin_ia32_cvtps2dq256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2dq_512 : + def int_x86_avx512_mask_cvtps2dq_512 : GCCBuiltin<"__builtin_ia32_cvtps2dq512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16f32_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2pd_128 : + def int_x86_avx512_mask_cvtps2pd_128 : GCCBuiltin<"__builtin_ia32_cvtps2pd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v4f32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2pd_256 : + def int_x86_avx512_mask_cvtps2pd_256 : GCCBuiltin<"__builtin_ia32_cvtps2pd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f32_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2pd_512 : + def int_x86_avx512_mask_cvtps2pd_512 : GCCBuiltin<"__builtin_ia32_cvtps2pd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f32_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2qq_128 : + def int_x86_avx512_mask_cvtps2qq_128 : GCCBuiltin<"__builtin_ia32_cvtps2qq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v4f32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2qq_256 : + def int_x86_avx512_mask_cvtps2qq_256 : GCCBuiltin<"__builtin_ia32_cvtps2qq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2qq_512 : + def int_x86_avx512_mask_cvtps2qq_512 : GCCBuiltin<"__builtin_ia32_cvtps2qq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f32_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2udq_128 : + def int_x86_avx512_mask_cvtps2udq_128 : GCCBuiltin<"__builtin_ia32_cvtps2udq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2udq_256 : + def int_x86_avx512_mask_cvtps2udq_256 : GCCBuiltin<"__builtin_ia32_cvtps2udq256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2udq_512 : + def int_x86_avx512_mask_cvtps2udq_512 : GCCBuiltin<"__builtin_ia32_cvtps2udq512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16f32_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2uqq_128 : + def int_x86_avx512_mask_cvtps2uqq_128 : GCCBuiltin<"__builtin_ia32_cvtps2uqq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v4f32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2uqq_256 : + def int_x86_avx512_mask_cvtps2uqq_256 : GCCBuiltin<"__builtin_ia32_cvtps2uqq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtps2uqq_512 : + def int_x86_avx512_mask_cvtps2uqq_512 : GCCBuiltin<"__builtin_ia32_cvtps2uqq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f32_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2pd_128 : + def int_x86_avx512_mask_cvtqq2pd_128 : GCCBuiltin<"__builtin_ia32_cvtqq2pd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2i64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2pd_256 : + def int_x86_avx512_mask_cvtqq2pd_256 : GCCBuiltin<"__builtin_ia32_cvtqq2pd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2pd_512 : + def int_x86_avx512_mask_cvtqq2pd_512 : GCCBuiltin<"__builtin_ia32_cvtqq2pd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8i64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2ps_128 : + def int_x86_avx512_mask_cvtqq2ps_128 : GCCBuiltin<"__builtin_ia32_cvtqq2ps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v2i64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2ps_256 : + def int_x86_avx512_mask_cvtqq2ps_256 : GCCBuiltin<"__builtin_ia32_cvtqq2ps256_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtqq2ps_512 : + def int_x86_avx512_mask_cvtqq2ps_512 : GCCBuiltin<"__builtin_ia32_cvtqq2ps512_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i64_ty, llvm_v8f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2dq_128 : + def int_x86_avx512_mask_cvttpd2dq_128 : GCCBuiltin<"__builtin_ia32_cvttpd2dq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v2f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2dq_256 : + def int_x86_avx512_mask_cvttpd2dq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2dq256_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2dq_512 : + def int_x86_avx512_mask_cvttpd2dq_512 : GCCBuiltin<"__builtin_ia32_cvttpd2dq512_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f64_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2qq_128 : + def int_x86_avx512_mask_cvttpd2qq_128 : GCCBuiltin<"__builtin_ia32_cvttpd2qq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2f64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2qq_256 : + def int_x86_avx512_mask_cvttpd2qq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2qq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2qq_512 : + def int_x86_avx512_mask_cvttpd2qq_512 : GCCBuiltin<"__builtin_ia32_cvttpd2qq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f64_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2udq_128 : + def int_x86_avx512_mask_cvttpd2udq_128 : GCCBuiltin<"__builtin_ia32_cvttpd2udq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v2f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2udq_256 : + def int_x86_avx512_mask_cvttpd2udq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2udq256_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2udq_512 : + def int_x86_avx512_mask_cvttpd2udq_512 : GCCBuiltin<"__builtin_ia32_cvttpd2udq512_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f64_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2uqq_128 : + def int_x86_avx512_mask_cvttpd2uqq_128 : GCCBuiltin<"__builtin_ia32_cvttpd2uqq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2f64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2uqq_256 : + def int_x86_avx512_mask_cvttpd2uqq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2uqq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttpd2uqq_512 : + def int_x86_avx512_mask_cvttpd2uqq_512 : GCCBuiltin<"__builtin_ia32_cvttpd2uqq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f64_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2dq_128 : + def int_x86_avx512_mask_cvttps2dq_128 : GCCBuiltin<"__builtin_ia32_cvttps2dq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2dq_256 : + def int_x86_avx512_mask_cvttps2dq_256 : GCCBuiltin<"__builtin_ia32_cvttps2dq256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2dq_512 : + def int_x86_avx512_mask_cvttps2dq_512 : GCCBuiltin<"__builtin_ia32_cvttps2dq512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16f32_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2qq_128 : + def int_x86_avx512_mask_cvttps2qq_128 : GCCBuiltin<"__builtin_ia32_cvttps2qq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v4f32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2qq_256 : + def int_x86_avx512_mask_cvttps2qq_256 : GCCBuiltin<"__builtin_ia32_cvttps2qq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2qq_512 : + def int_x86_avx512_mask_cvttps2qq_512 : GCCBuiltin<"__builtin_ia32_cvttps2qq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f32_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2udq_128 : + def int_x86_avx512_mask_cvttps2udq_128 : GCCBuiltin<"__builtin_ia32_cvttps2udq128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2udq_256 : + def int_x86_avx512_mask_cvttps2udq_256 : GCCBuiltin<"__builtin_ia32_cvttps2udq256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2udq_512 : + def int_x86_avx512_mask_cvttps2udq_512 : GCCBuiltin<"__builtin_ia32_cvttps2udq512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16f32_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2uqq_128 : + def int_x86_avx512_mask_cvttps2uqq_128 : GCCBuiltin<"__builtin_ia32_cvttps2uqq128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v4f32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2uqq_256 : + def int_x86_avx512_mask_cvttps2uqq_256 : GCCBuiltin<"__builtin_ia32_cvttps2uqq256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4f32_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvttps2uqq_512 : + def int_x86_avx512_mask_cvttps2uqq_512 : GCCBuiltin<"__builtin_ia32_cvttps2uqq512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8f32_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2pd_128 : + def int_x86_avx512_mask_cvtudq2pd_128 : GCCBuiltin<"__builtin_ia32_cvtudq2pd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v4i32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2pd_256 : + def int_x86_avx512_mask_cvtudq2pd_256 : GCCBuiltin<"__builtin_ia32_cvtudq2pd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i32_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2pd_512 : + def int_x86_avx512_mask_cvtudq2pd_512 : GCCBuiltin<"__builtin_ia32_cvtudq2pd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8i32_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2ps_128 : + def int_x86_avx512_mask_cvtudq2ps_128 : GCCBuiltin<"__builtin_ia32_cvtudq2ps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2ps_256 : + def int_x86_avx512_mask_cvtudq2ps_256 : GCCBuiltin<"__builtin_ia32_cvtudq2ps256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtudq2ps_512 : + def int_x86_avx512_mask_cvtudq2ps_512 : GCCBuiltin<"__builtin_ia32_cvtudq2ps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16i32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2pd_128 : + def int_x86_avx512_mask_cvtuqq2pd_128 : GCCBuiltin<"__builtin_ia32_cvtuqq2pd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2i64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2pd_256 : + def int_x86_avx512_mask_cvtuqq2pd_256 : GCCBuiltin<"__builtin_ia32_cvtuqq2pd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2pd_512 : + def int_x86_avx512_mask_cvtuqq2pd_512 : GCCBuiltin<"__builtin_ia32_cvtuqq2pd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8i64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2ps_128 : + def int_x86_avx512_mask_cvtuqq2ps_128 : GCCBuiltin<"__builtin_ia32_cvtuqq2ps128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v2i64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2ps_256 : + def int_x86_avx512_mask_cvtuqq2ps_256 : GCCBuiltin<"__builtin_ia32_cvtuqq2ps256_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i64_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cvtuqq2ps_512 : + def int_x86_avx512_mask_cvtuqq2ps_512 : GCCBuiltin<"__builtin_ia32_cvtuqq2ps512_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i64_ty, llvm_v8f32_ty, llvm_i8_ty, llvm_i32_ty], @@ -5358,7 +4988,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_rndscale_pd_256 : GCCBuiltin<"__builtin_ia32_rndscalepd_256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_i32_ty, + Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_i32_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_rndscale_pd_512 : GCCBuiltin<"__builtin_ia32_rndscalepd_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_i32_ty, llvm_v8f64_ty, @@ -5367,13 +4997,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_rndscale_ps_256 : GCCBuiltin<"__builtin_ia32_rndscaleps_256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_i32_ty, + Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_rndscale_ps_512 : GCCBuiltin<"__builtin_ia32_rndscaleps_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_reduce_pd_128 : GCCBuiltin<"__builtin_ia32_reducepd128_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_i32_ty, + Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_reduce_pd_256 : GCCBuiltin<"__builtin_ia32_reducepd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_i32_ty, @@ -5382,7 +5012,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_i32_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_reduce_ps_128 : GCCBuiltin<"__builtin_ia32_reduceps128_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i32_ty, + Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_reduce_ps_256 : GCCBuiltin<"__builtin_ia32_reduceps256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_i32_ty, @@ -5391,7 +5021,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_range_pd_128 : GCCBuiltin<"__builtin_ia32_rangepd128_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i32_ty, + Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_range_pd_256 : GCCBuiltin<"__builtin_ia32_rangepd256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i32_ty, @@ -5403,7 +5033,7 @@ def int_x86_avx512_mask_range_ps_128 : GCCBuiltin<"__builtin_ia32_rangeps128_mas Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_range_ps_256 : GCCBuiltin<"__builtin_ia32_rangeps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i32_ty, + Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_range_ps_512 : GCCBuiltin<"__builtin_ia32_rangeps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i32_ty, @@ -5414,75 +5044,11 @@ def int_x86_avx512_mask_range_ps_512 : GCCBuiltin<"__builtin_ia32_rangeps512_mas let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_vbroadcast_ss_512 : GCCBuiltin<"__builtin_ia32_vbroadcastss512">, - Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_512 : - GCCBuiltin<"__builtin_ia32_broadcastss512">, - Intrinsic<[llvm_v16f32_ty], [llvm_v4f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_256 : - GCCBuiltin<"__builtin_ia32_broadcastss256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v4f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_128 : - GCCBuiltin<"__builtin_ia32_broadcastss128_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_vbroadcast_sd_512 : GCCBuiltin<"__builtin_ia32_vbroadcastsd512">, - Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_broadcast_sd_pd_512 : - GCCBuiltin<"__builtin_ia32_broadcastsd512">, - Intrinsic<[llvm_v8f64_ty], [llvm_v2f64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_sd_pd_256 : - GCCBuiltin<"__builtin_ia32_broadcastsd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v2f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_pbroadcastb_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastb128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastb_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastb256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v16i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastb_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastb512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v16i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v8i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastd128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastd256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v4i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastd512">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v4i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v2i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastq512">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v2i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_broadcastf32x2_256 : GCCBuiltin<"__builtin_ia32_broadcastf32x2_256_mask">, @@ -5569,11 +5135,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i64_ty], [llvm_v4i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_i32_512 : - Intrinsic<[llvm_v16i32_ty], [llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_pbroadcastq_i64_512 : - Intrinsic<[llvm_v8i64_ty], [llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_broadcastmw_512 : GCCBuiltin<"__builtin_ia32_broadcastmw512">, Intrinsic<[llvm_v16i32_ty], [llvm_i16_ty], [IntrNoMem]>; @@ -5668,81 +5229,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } -//Bitwise Ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_pand_d_128 : GCCBuiltin<"__builtin_ia32_pandd128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_d_256 : GCCBuiltin<"__builtin_ia32_pandd256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_d_512 : GCCBuiltin<"__builtin_ia32_pandd512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_128 : GCCBuiltin<"__builtin_ia32_pandq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_256 : GCCBuiltin<"__builtin_ia32_pandq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_512 : GCCBuiltin<"__builtin_ia32_pandq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_128 : GCCBuiltin<"__builtin_ia32_pandnd128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_256 : GCCBuiltin<"__builtin_ia32_pandnd256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_512 : GCCBuiltin<"__builtin_ia32_pandnd512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_128 : GCCBuiltin<"__builtin_ia32_pandnq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_256 : GCCBuiltin<"__builtin_ia32_pandnq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_512 : GCCBuiltin<"__builtin_ia32_pandnq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_128 : GCCBuiltin<"__builtin_ia32_pord128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_256 : GCCBuiltin<"__builtin_ia32_pord256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_512 : GCCBuiltin<"__builtin_ia32_pord512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_128 : GCCBuiltin<"__builtin_ia32_porq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_256 : GCCBuiltin<"__builtin_ia32_porq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_512 : GCCBuiltin<"__builtin_ia32_porq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_128 : GCCBuiltin<"__builtin_ia32_pxord128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_256 : GCCBuiltin<"__builtin_ia32_pxord256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_512 : GCCBuiltin<"__builtin_ia32_pxord512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_128 : GCCBuiltin<"__builtin_ia32_pxorq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_256 : GCCBuiltin<"__builtin_ia32_pxorq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_512 : GCCBuiltin<"__builtin_ia32_pxorq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; -} + // Arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". @@ -5855,96 +5342,96 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 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_add_ss_round : GCCBuiltin<"__builtin_ia32_addss_round">, + def int_x86_avx512_mask_add_ss_round : GCCBuiltin<"__builtin_ia32_addss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_div_ss_round : GCCBuiltin<"__builtin_ia32_divss_round">, + def int_x86_avx512_mask_div_ss_round : GCCBuiltin<"__builtin_ia32_divss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mul_ss_round : GCCBuiltin<"__builtin_ia32_mulss_round">, + def int_x86_avx512_mask_mul_ss_round : GCCBuiltin<"__builtin_ia32_mulss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_sub_ss_round : GCCBuiltin<"__builtin_ia32_subss_round">, + def int_x86_avx512_mask_sub_ss_round : GCCBuiltin<"__builtin_ia32_subss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_ss_round : GCCBuiltin<"__builtin_ia32_maxss_round">, + def int_x86_avx512_mask_max_ss_round : GCCBuiltin<"__builtin_ia32_maxss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_ss_round : GCCBuiltin<"__builtin_ia32_minss_round">, + def int_x86_avx512_mask_min_ss_round : GCCBuiltin<"__builtin_ia32_minss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_add_sd_round : GCCBuiltin<"__builtin_ia32_addsd_round">, + def int_x86_avx512_mask_add_sd_round : GCCBuiltin<"__builtin_ia32_addsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_div_sd_round : GCCBuiltin<"__builtin_ia32_divsd_round">, + def int_x86_avx512_mask_div_sd_round : GCCBuiltin<"__builtin_ia32_divsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mul_sd_round : GCCBuiltin<"__builtin_ia32_mulsd_round">, + def int_x86_avx512_mask_mul_sd_round : GCCBuiltin<"__builtin_ia32_mulsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_sub_sd_round : GCCBuiltin<"__builtin_ia32_subsd_round">, + def int_x86_avx512_mask_sub_sd_round : GCCBuiltin<"__builtin_ia32_subsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_sd_round : GCCBuiltin<"__builtin_ia32_maxsd_round">, + def int_x86_avx512_mask_max_sd_round : GCCBuiltin<"__builtin_ia32_maxsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_sd_round : GCCBuiltin<"__builtin_ia32_minsd_round">, + def int_x86_avx512_mask_min_sd_round : GCCBuiltin<"__builtin_ia32_minsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_rndscale_ss : GCCBuiltin<"__builtin_ia32_rndscaless_round">, + def int_x86_avx512_mask_rndscale_ss : GCCBuiltin<"__builtin_ia32_rndscaless_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_rndscale_sd : GCCBuiltin<"__builtin_ia32_rndscalesd_round">, + def int_x86_avx512_mask_rndscale_sd : GCCBuiltin<"__builtin_ia32_rndscalesd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_range_ss : GCCBuiltin<"__builtin_ia32_rangess128_round">, + def int_x86_avx512_mask_range_ss : GCCBuiltin<"__builtin_ia32_rangess128_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_range_sd : GCCBuiltin<"__builtin_ia32_rangesd128_round">, + def int_x86_avx512_mask_range_sd : GCCBuiltin<"__builtin_ia32_rangesd128_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_reduce_ss : GCCBuiltin<"__builtin_ia32_reducess">, + def int_x86_avx512_mask_reduce_ss : GCCBuiltin<"__builtin_ia32_reducess_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_reduce_sd : GCCBuiltin<"__builtin_ia32_reducesd">, + def int_x86_avx512_mask_reduce_sd : GCCBuiltin<"__builtin_ia32_reducesd_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_scalef_sd : GCCBuiltin<"__builtin_ia32_scalefsd_round">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, + def int_x86_avx512_mask_scalef_sd : GCCBuiltin<"__builtin_ia32_scalefsd_round_mask">, + Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_scalef_ss : GCCBuiltin<"__builtin_ia32_scalefss_round">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, + def int_x86_avx512_mask_scalef_ss : GCCBuiltin<"__builtin_ia32_scalefss_round_mask">, + Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_scalef_pd_128 : GCCBuiltin<"__builtin_ia32_scalefpd128_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, + Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_scalef_pd_256 : GCCBuiltin<"__builtin_ia32_scalefpd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, + Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty],[IntrNoMem]>; def int_x86_avx512_mask_scalef_pd_512 : GCCBuiltin<"__builtin_ia32_scalefpd512_mask">, - Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, + 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_scalef_ps_128 : GCCBuiltin<"__builtin_ia32_scalefps128_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, + Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_scalef_ps_256 : GCCBuiltin<"__builtin_ia32_scalefps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, + Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_scalef_ps_512 : GCCBuiltin<"__builtin_ia32_scalefps512_mask">, - Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, + 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_sqrt_ss : GCCBuiltin<"__builtin_ia32_sqrtss_round">, + def int_x86_avx512_mask_sqrt_ss : GCCBuiltin<"__builtin_ia32_sqrtss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_sqrt_sd : GCCBuiltin<"__builtin_ia32_sqrtsd_round">, + def int_x86_avx512_mask_sqrt_sd : GCCBuiltin<"__builtin_ia32_sqrtsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -5966,6 +5453,86 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_sqrt_ps_512 : GCCBuiltin<"__builtin_ia32_sqrtps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_pd_128 : + GCCBuiltin<"__builtin_ia32_fixupimmpd128_mask">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_pd_128 : + GCCBuiltin<"__builtin_ia32_fixupimmpd128_maskz">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_pd_256 : + GCCBuiltin<"__builtin_ia32_fixupimmpd256_mask">, + Intrinsic<[llvm_v4f64_ty], + [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_pd_256 : + GCCBuiltin<"__builtin_ia32_fixupimmpd256_maskz">, + Intrinsic<[llvm_v4f64_ty], + [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_pd_512 : + GCCBuiltin<"__builtin_ia32_fixupimmpd512_mask">, + Intrinsic<[llvm_v8f64_ty], + [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_pd_512 : + GCCBuiltin<"__builtin_ia32_fixupimmpd512_maskz">, + Intrinsic<[llvm_v8f64_ty], + [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_ps_128 : + GCCBuiltin<"__builtin_ia32_fixupimmps128_mask">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_ps_128 : + GCCBuiltin<"__builtin_ia32_fixupimmps128_maskz">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_ps_256 : + GCCBuiltin<"__builtin_ia32_fixupimmps256_mask">, + Intrinsic<[llvm_v8f32_ty], + [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_ps_256 : + GCCBuiltin<"__builtin_ia32_fixupimmps256_maskz">, + Intrinsic<[llvm_v8f32_ty], + [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], + [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_ps_512 : + GCCBuiltin<"__builtin_ia32_fixupimmps512_mask">, + Intrinsic<[llvm_v16f32_ty], + [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16i32_ty, llvm_i32_ty, + llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_ps_512 : + GCCBuiltin<"__builtin_ia32_fixupimmps512_maskz">, + Intrinsic<[llvm_v16f32_ty], + [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16i32_ty, llvm_i32_ty, + llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_sd : + GCCBuiltin<"__builtin_ia32_fixupimmsd_mask">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_sd : + GCCBuiltin<"__builtin_ia32_fixupimmsd_maskz">, + Intrinsic<[llvm_v2f64_ty], + [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_mask_fixupimm_ss : + GCCBuiltin<"__builtin_ia32_fixupimmss_mask">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_maskz_fixupimm_ss : + GCCBuiltin<"__builtin_ia32_fixupimmss_maskz">, + Intrinsic<[llvm_v4f32_ty], + [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty, + llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_getexp_pd_128 : GCCBuiltin<"__builtin_ia32_getexppd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; @@ -5985,10 +5552,10 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_getexp_ss : GCCBuiltin<"__builtin_ia32_getexpss_mask">, + def int_x86_avx512_mask_getexp_ss : GCCBuiltin<"__builtin_ia32_getexpss128_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_getexp_sd : GCCBuiltin<"__builtin_ia32_getexpsd_mask">, + def int_x86_avx512_mask_getexp_sd : GCCBuiltin<"__builtin_ia32_getexpsd128_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -6029,21 +5596,21 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_getmant_ss : - GCCBuiltin<"__builtin_ia32_getmantss_round">, + GCCBuiltin<"__builtin_ia32_getmantss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_getmant_sd : - GCCBuiltin<"__builtin_ia32_getmantsd_round">, + GCCBuiltin<"__builtin_ia32_getmantsd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_rsqrt14_ss : GCCBuiltin<"__builtin_ia32_rsqrt14ss">, + def int_x86_avx512_rsqrt14_ss : GCCBuiltin<"__builtin_ia32_rsqrt14ss_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_rsqrt14_sd : GCCBuiltin<"__builtin_ia32_rsqrt14sd">, + def int_x86_avx512_rsqrt14_sd : GCCBuiltin<"__builtin_ia32_rsqrt14sd_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; @@ -6065,10 +5632,10 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_rsqrt14_ps_512 : GCCBuiltin<"__builtin_ia32_rsqrt14ps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_rcp14_ss : GCCBuiltin<"__builtin_ia32_rcp14ss">, + def int_x86_avx512_rcp14_ss : GCCBuiltin<"__builtin_ia32_rcp14ss_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_rcp14_sd : GCCBuiltin<"__builtin_ia32_rcp14sd">, + def int_x86_avx512_rcp14_sd : GCCBuiltin<"__builtin_ia32_rcp14sd_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; @@ -6104,11 +5671,11 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_rcp28_ss : GCCBuiltin<"__builtin_ia32_rcp28ss_round">, + def int_x86_avx512_rcp28_ss : GCCBuiltin<"__builtin_ia32_rcp28ss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_rcp28_sd : GCCBuiltin<"__builtin_ia32_rcp28sd_round">, + def int_x86_avx512_rcp28_sd : GCCBuiltin<"__builtin_ia32_rcp28sd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -6120,11 +5687,11 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_rsqrt28_ss : GCCBuiltin<"__builtin_ia32_rsqrt28ss_round">, + def int_x86_avx512_rsqrt28_ss : GCCBuiltin<"__builtin_ia32_rsqrt28ss_round_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_rsqrt28_sd : GCCBuiltin<"__builtin_ia32_rsqrt28sd_round">, + def int_x86_avx512_rsqrt28_sd : GCCBuiltin<"__builtin_ia32_rsqrt28sd_round_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -6188,7 +5755,7 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_or_ps_512 : GCCBuiltin<"__builtin_ia32_orps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - + def int_x86_avx512_mask_xor_pd_128 : GCCBuiltin<"__builtin_ia32_xorpd128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; @@ -6206,7 +5773,7 @@ let TargetPrefix = "x86" in { llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_xor_ps_512 : GCCBuiltin<"__builtin_ia32_xorps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, - llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; + llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; } // Integer arithmetic ops let TargetPrefix = "x86" in { @@ -6406,34 +5973,34 @@ let TargetPrefix = "x86" in { Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmulhu_w_128 : GCCBuiltin<"__builtin_ia32_pmulhuw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmulhu_w_256 : GCCBuiltin<"__builtin_ia32_pmulhuw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmulh_w_128 : GCCBuiltin<"__builtin_ia32_pmulhw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmulh_w_256 : GCCBuiltin<"__builtin_ia32_pmulhw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_b_512 : GCCBuiltin<"__builtin_ia32_pavgb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, + Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_w_512 : GCCBuiltin<"__builtin_ia32_pavgw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, + Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_b_128 : GCCBuiltin<"__builtin_ia32_pavgb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, + Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_b_256 : GCCBuiltin<"__builtin_ia32_pavgb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, + Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_w_128 : GCCBuiltin<"__builtin_ia32_pavgw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, + Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_pavg_w_256 : GCCBuiltin<"__builtin_ia32_pavgw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, + Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_pmaddw_d_128 : GCCBuiltin<"__builtin_ia32_pmaddwd128_mask">, @@ -6490,293 +6057,293 @@ let TargetPrefix = "x86" in { def int_x86_avx512_gather_dpd_512 : GCCBuiltin<"__builtin_ia32_gathersiv8df">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dps_512 : GCCBuiltin<"__builtin_ia32_gathersiv16sf">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpd_512 : GCCBuiltin<"__builtin_ia32_gatherdiv8df">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qps_512 : GCCBuiltin<"__builtin_ia32_gatherdiv16sf">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dpq_512 : GCCBuiltin<"__builtin_ia32_gathersiv8di">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dpi_512 : GCCBuiltin<"__builtin_ia32_gathersiv16si">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpq_512 : GCCBuiltin<"__builtin_ia32_gatherdiv8di">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpi_512 : GCCBuiltin<"__builtin_ia32_gatherdiv16si">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div2_df : + def int_x86_avx512_gather3div2_df : GCCBuiltin<"__builtin_ia32_gather3div2df">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div2_di : + def int_x86_avx512_gather3div2_di : GCCBuiltin<"__builtin_ia32_gather3div2di">, Intrinsic<[llvm_v4i32_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div4_df : + def int_x86_avx512_gather3div4_df : GCCBuiltin<"__builtin_ia32_gather3div4df">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div4_di : + def int_x86_avx512_gather3div4_di : GCCBuiltin<"__builtin_ia32_gather3div4di">, Intrinsic<[llvm_v8i32_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div4_sf : + def int_x86_avx512_gather3div4_sf : GCCBuiltin<"__builtin_ia32_gather3div4sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div4_si : + def int_x86_avx512_gather3div4_si : GCCBuiltin<"__builtin_ia32_gather3div4si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div8_sf : + def int_x86_avx512_gather3div8_sf : GCCBuiltin<"__builtin_ia32_gather3div8sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3div8_si : + def int_x86_avx512_gather3div8_si : GCCBuiltin<"__builtin_ia32_gather3div8si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv2_df : + def int_x86_avx512_gather3siv2_df : GCCBuiltin<"__builtin_ia32_gather3siv2df">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv2_di : + def int_x86_avx512_gather3siv2_di : GCCBuiltin<"__builtin_ia32_gather3siv2di">, Intrinsic<[llvm_v4i32_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv4_df : + def int_x86_avx512_gather3siv4_df : GCCBuiltin<"__builtin_ia32_gather3siv4df">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv4_di : + def int_x86_avx512_gather3siv4_di : GCCBuiltin<"__builtin_ia32_gather3siv4di">, Intrinsic<[llvm_v8i32_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv4_sf : + def int_x86_avx512_gather3siv4_sf : GCCBuiltin<"__builtin_ia32_gather3siv4sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv4_si : + def int_x86_avx512_gather3siv4_si : GCCBuiltin<"__builtin_ia32_gather3siv4si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv8_sf : + def int_x86_avx512_gather3siv8_sf : GCCBuiltin<"__builtin_ia32_gather3siv8sf">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; - def int_x86_avx512_gather3siv8_si : + def int_x86_avx512_gather3siv8_si : GCCBuiltin<"__builtin_ia32_gather3siv8si">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; // scatter def int_x86_avx512_scatter_dpd_512 : GCCBuiltin<"__builtin_ia32_scattersiv8df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dps_512 : GCCBuiltin<"__builtin_ia32_scattersiv16sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_v16f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpd_512 : GCCBuiltin<"__builtin_ia32_scatterdiv8df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qps_512 : GCCBuiltin<"__builtin_ia32_scatterdiv16sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dpq_512 : GCCBuiltin<"__builtin_ia32_scattersiv8di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dpi_512 : GCCBuiltin<"__builtin_ia32_scattersiv16si">, Intrinsic<[], [llvm_ptr_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpq_512 : GCCBuiltin<"__builtin_ia32_scatterdiv8di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty,llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpi_512 : GCCBuiltin<"__builtin_ia32_scatterdiv16si">, - Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8i32_ty, + Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv2_df : + def int_x86_avx512_scatterdiv2_df : GCCBuiltin<"__builtin_ia32_scatterdiv2df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v2f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv2_di : + def int_x86_avx512_scatterdiv2_di : GCCBuiltin<"__builtin_ia32_scatterdiv2di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv4_df : + def int_x86_avx512_scatterdiv4_df : GCCBuiltin<"__builtin_ia32_scatterdiv4df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv4_di : + def int_x86_avx512_scatterdiv4_di : GCCBuiltin<"__builtin_ia32_scatterdiv4di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv4_sf : + def int_x86_avx512_scatterdiv4_sf : GCCBuiltin<"__builtin_ia32_scatterdiv4sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv4_si : + def int_x86_avx512_scatterdiv4_si : GCCBuiltin<"__builtin_ia32_scatterdiv4si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv8_sf : + def int_x86_avx512_scatterdiv8_sf : GCCBuiltin<"__builtin_ia32_scatterdiv8sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scatterdiv8_si : + def int_x86_avx512_scatterdiv8_si : GCCBuiltin<"__builtin_ia32_scatterdiv8si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv2_df : + def int_x86_avx512_scattersiv2_df : GCCBuiltin<"__builtin_ia32_scattersiv2df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v2f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv2_di : + def int_x86_avx512_scattersiv2_di : GCCBuiltin<"__builtin_ia32_scattersiv2di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v2i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv4_df : + def int_x86_avx512_scattersiv4_df : GCCBuiltin<"__builtin_ia32_scattersiv4df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv4_di : + def int_x86_avx512_scattersiv4_di : GCCBuiltin<"__builtin_ia32_scattersiv4di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv4_sf : + def int_x86_avx512_scattersiv4_sf : GCCBuiltin<"__builtin_ia32_scattersiv4sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv4_si : + def int_x86_avx512_scattersiv4_si : GCCBuiltin<"__builtin_ia32_scattersiv4si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv8_sf : + def int_x86_avx512_scattersiv8_sf : GCCBuiltin<"__builtin_ia32_scattersiv8sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; - def int_x86_avx512_scattersiv8_si : + def int_x86_avx512_scattersiv8_si : GCCBuiltin<"__builtin_ia32_scattersiv8si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // gather prefetch def int_x86_avx512_gatherpf_dpd_512 : GCCBuiltin<"__builtin_ia32_gatherpfdpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_dps_512 : GCCBuiltin<"__builtin_ia32_gatherpfdps">, Intrinsic<[], [llvm_i16_ty, llvm_v16i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_qpd_512 : GCCBuiltin<"__builtin_ia32_gatherpfqpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_qps_512 : GCCBuiltin<"__builtin_ia32_gatherpfqps">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; // scatter prefetch def int_x86_avx512_scatterpf_dpd_512 : GCCBuiltin<"__builtin_ia32_scatterpfdpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_dps_512 : GCCBuiltin<"__builtin_ia32_scatterpfdps">, Intrinsic<[], [llvm_i16_ty, llvm_v16i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_qpd_512 : GCCBuiltin<"__builtin_ia32_scatterpfqpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_qps_512 : GCCBuiltin<"__builtin_ia32_scatterpfqps">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; } // AVX-512 conflict detection instruction @@ -6815,117 +6382,32 @@ let TargetPrefix = "x86" in { [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_128 : - GCCBuiltin<"__builtin_ia32_vplzcntd_128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_256 : - GCCBuiltin<"__builtin_ia32_vplzcntd_256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_512 : - GCCBuiltin<"__builtin_ia32_vplzcntd_512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_128 : - GCCBuiltin<"__builtin_ia32_vplzcntq_128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_256 : - GCCBuiltin<"__builtin_ia32_vplzcntq_256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_512 : - GCCBuiltin<"__builtin_ia32_vplzcntq_512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } -// Vector blend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_blend_ps_512 : GCCBuiltin<"__builtin_ia32_blendmps_512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_ps_256 : GCCBuiltin<"__builtin_ia32_blendmps_256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_ps_128 : GCCBuiltin<"__builtin_ia32_blendmps_128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_512 : GCCBuiltin<"__builtin_ia32_blendmpd_512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_256 : GCCBuiltin<"__builtin_ia32_blendmpd_256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_128 : GCCBuiltin<"__builtin_ia32_blendmpd_128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_blend_d_512 : GCCBuiltin<"__builtin_ia32_blendmd_512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_512 : GCCBuiltin<"__builtin_ia32_blendmq_512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_d_256 : GCCBuiltin<"__builtin_ia32_blendmd_256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_256 : GCCBuiltin<"__builtin_ia32_blendmq_256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_d_128 : GCCBuiltin<"__builtin_ia32_blendmd_128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_128 : GCCBuiltin<"__builtin_ia32_blendmq_128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_blend_w_512 : GCCBuiltin<"__builtin_ia32_blendmw_512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_w_256 : GCCBuiltin<"__builtin_ia32_blendmw_256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_w_128 : GCCBuiltin<"__builtin_ia32_blendmw_128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_512 : GCCBuiltin<"__builtin_ia32_blendmb_512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_256 : GCCBuiltin<"__builtin_ia32_blendmb_256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_128 : GCCBuiltin<"__builtin_ia32_blendmb_128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - -} - let TargetPrefix = "x86" in { def int_x86_avx512_mask_valign_q_512 : GCCBuiltin<"__builtin_ia32_alignq512_mask">, @@ -6948,13 +6430,13 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_valign_d_256 : GCCBuiltin<"__builtin_ia32_alignd256_mask">, Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_v8i32_ty, + [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_valign_q_128 : GCCBuiltin<"__builtin_ia32_alignq128_mask">, Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_v2i64_ty, + [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_valign_d_128 : @@ -6962,24 +6444,6 @@ let TargetPrefix = "x86" in { Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_128 : - GCCBuiltin<"__builtin_ia32_palignr128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_v16i8_ty, - llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_256 : - GCCBuiltin<"__builtin_ia32_palignr256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_v32i8_ty, - llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_512 : - GCCBuiltin<"__builtin_ia32_palignr512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_v64i8_ty, - llvm_i64_ty], [IntrNoMem]>; } // Compares @@ -6991,161 +6455,84 @@ let TargetPrefix = "x86" in { def int_x86_avx512_vcomi_ss : GCCBuiltin<"__builtin_ia32_vcomiss">, Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_b_512 : GCCBuiltin<"__builtin_ia32_pcmpeqb512_mask">, - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_512 : GCCBuiltin<"__builtin_ia32_pcmpeqw512_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_512 : GCCBuiltin<"__builtin_ia32_pcmpeqd512_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_512 : GCCBuiltin<"__builtin_ia32_pcmpeqq512_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_b_512: GCCBuiltin<"__builtin_ia32_pcmpgtb512_mask">, - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_512: GCCBuiltin<"__builtin_ia32_pcmpgtw512_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_512: GCCBuiltin<"__builtin_ia32_pcmpgtd512_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_512: GCCBuiltin<"__builtin_ia32_pcmpgtq512_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_512: GCCBuiltin<"__builtin_ia32_cmpb512_mask">, + def int_x86_avx512_mask_cmp_b_512: Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_512: GCCBuiltin<"__builtin_ia32_cmpw512_mask">, + def int_x86_avx512_mask_cmp_w_512: Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_512: GCCBuiltin<"__builtin_ia32_cmpd512_mask">, + def int_x86_avx512_mask_cmp_d_512: Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem ]>; - def int_x86_avx512_mask_cmp_q_512: GCCBuiltin<"__builtin_ia32_cmpq512_mask">, + def int_x86_avx512_mask_cmp_q_512: Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_512: GCCBuiltin<"__builtin_ia32_ucmpb512_mask">, + def int_x86_avx512_mask_ucmp_b_512: Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_512: GCCBuiltin<"__builtin_ia32_ucmpw512_mask">, + def int_x86_avx512_mask_ucmp_w_512: Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_512: GCCBuiltin<"__builtin_ia32_ucmpd512_mask">, + def int_x86_avx512_mask_ucmp_d_512: Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_512: GCCBuiltin<"__builtin_ia32_ucmpq512_mask">, + def int_x86_avx512_mask_ucmp_q_512: Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; // 256-bit - def int_x86_avx512_mask_pcmpeq_b_256 : GCCBuiltin<"__builtin_ia32_pcmpeqb256_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_256 : GCCBuiltin<"__builtin_ia32_pcmpeqw256_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_256 : GCCBuiltin<"__builtin_ia32_pcmpeqd256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_256 : GCCBuiltin<"__builtin_ia32_pcmpeqq256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pcmpgt_b_256: GCCBuiltin<"__builtin_ia32_pcmpgtb256_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_256: GCCBuiltin<"__builtin_ia32_pcmpgtw256_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_256: GCCBuiltin<"__builtin_ia32_pcmpgtd256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_256: GCCBuiltin<"__builtin_ia32_pcmpgtq256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_256: GCCBuiltin<"__builtin_ia32_cmpb256_mask">, + def int_x86_avx512_mask_cmp_b_256: Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_256: GCCBuiltin<"__builtin_ia32_cmpw256_mask">, + def int_x86_avx512_mask_cmp_w_256: Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_256: GCCBuiltin<"__builtin_ia32_cmpd256_mask">, + def int_x86_avx512_mask_cmp_d_256: Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_256: GCCBuiltin<"__builtin_ia32_cmpq256_mask">, + def int_x86_avx512_mask_cmp_q_256: Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_256: GCCBuiltin<"__builtin_ia32_ucmpb256_mask">, + def int_x86_avx512_mask_ucmp_b_256: Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_256: GCCBuiltin<"__builtin_ia32_ucmpw256_mask">, + def int_x86_avx512_mask_ucmp_w_256: Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_256: GCCBuiltin<"__builtin_ia32_ucmpd256_mask">, + def int_x86_avx512_mask_ucmp_d_256: Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_256: GCCBuiltin<"__builtin_ia32_ucmpq256_mask">, + def int_x86_avx512_mask_ucmp_q_256: Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; // 128-bit - def int_x86_avx512_mask_pcmpeq_b_128 : GCCBuiltin<"__builtin_ia32_pcmpeqb128_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_128 : GCCBuiltin<"__builtin_ia32_pcmpeqw128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_128 : GCCBuiltin<"__builtin_ia32_pcmpeqd128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_128 : GCCBuiltin<"__builtin_ia32_pcmpeqq128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pcmpgt_b_128: GCCBuiltin<"__builtin_ia32_pcmpgtb128_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_128: GCCBuiltin<"__builtin_ia32_pcmpgtw128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_128: GCCBuiltin<"__builtin_ia32_pcmpgtd128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_128: GCCBuiltin<"__builtin_ia32_pcmpgtq128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_128: GCCBuiltin<"__builtin_ia32_cmpb128_mask">, + def int_x86_avx512_mask_cmp_b_128: Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_128: GCCBuiltin<"__builtin_ia32_cmpw128_mask">, + def int_x86_avx512_mask_cmp_w_128: Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_128: GCCBuiltin<"__builtin_ia32_cmpd128_mask">, + def int_x86_avx512_mask_cmp_d_128: Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_128: GCCBuiltin<"__builtin_ia32_cmpq128_mask">, + def int_x86_avx512_mask_cmp_q_128: Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_128: GCCBuiltin<"__builtin_ia32_ucmpb128_mask">, + def int_x86_avx512_mask_ucmp_b_128: Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_128: GCCBuiltin<"__builtin_ia32_ucmpw128_mask">, + def int_x86_avx512_mask_ucmp_w_128: Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_128: GCCBuiltin<"__builtin_ia32_ucmpd128_mask">, + def int_x86_avx512_mask_ucmp_d_128: Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_128: GCCBuiltin<"__builtin_ia32_ucmpq128_mask">, + def int_x86_avx512_mask_ucmp_q_128: Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; } @@ -7180,27 +6567,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_compress_store_ps_512 : GCCBuiltin<"__builtin_ia32_compressstoresf512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, - llvm_i16_ty], [IntrReadWriteArgMem]>; + llvm_i16_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_512 : GCCBuiltin<"__builtin_ia32_compressstoredf512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_ps_256 : GCCBuiltin<"__builtin_ia32_compressstoresf256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_256 : GCCBuiltin<"__builtin_ia32_compressstoredf256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_ps_128 : GCCBuiltin<"__builtin_ia32_compressstoresf128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_128 : GCCBuiltin<"__builtin_ia32_compressstoredf128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_d_512 : GCCBuiltin<"__builtin_ia32_compresssi512_mask">, @@ -7230,27 +6617,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_compress_store_d_512 : GCCBuiltin<"__builtin_ia32_compressstoresi512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, - llvm_i16_ty], [IntrReadWriteArgMem]>; + llvm_i16_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_512 : GCCBuiltin<"__builtin_ia32_compressstoredi512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_d_256 : GCCBuiltin<"__builtin_ia32_compressstoresi256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_256 : GCCBuiltin<"__builtin_ia32_compressstoredi256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_d_128 : GCCBuiltin<"__builtin_ia32_compressstoresi128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_128 : GCCBuiltin<"__builtin_ia32_compressstoredi128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; // expand def int_x86_avx512_mask_expand_ps_512 : @@ -7281,27 +6668,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_expand_load_ps_512 : GCCBuiltin<"__builtin_ia32_expandloadsf512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, - llvm_i16_ty], [IntrReadArgMem]>; + llvm_i16_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_512 : GCCBuiltin<"__builtin_ia32_expandloaddf512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_ps_256 : GCCBuiltin<"__builtin_ia32_expandloadsf256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8f32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_256 : GCCBuiltin<"__builtin_ia32_expandloaddf256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty, llvm_v4f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_ps_128 : GCCBuiltin<"__builtin_ia32_expandloadsf128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_ptr_ty, llvm_v4f32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_128 : GCCBuiltin<"__builtin_ia32_expandloaddf128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty, llvm_v2f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_d_512 : GCCBuiltin<"__builtin_ia32_expandsi512_mask">, @@ -7331,27 +6718,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_expand_load_d_512 : GCCBuiltin<"__builtin_ia32_expandloadsi512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_ptr_ty, llvm_v16i32_ty, - llvm_i16_ty], [IntrReadArgMem]>; + llvm_i16_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_512 : GCCBuiltin<"__builtin_ia32_expandloaddi512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_ptr_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_d_256 : GCCBuiltin<"__builtin_ia32_expandloadsi256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_ptr_ty, llvm_v8i32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_256 : GCCBuiltin<"__builtin_ia32_expandloaddi256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty, llvm_v4i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_d_128 : GCCBuiltin<"__builtin_ia32_expandloadsi128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_v4i32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_128 : GCCBuiltin<"__builtin_ia32_expandloaddi128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_v2i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; } @@ -7366,7 +6753,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_128 : GCCBuiltin<"__builtin_ia32_pmovsqb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7376,7 +6763,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_128 : GCCBuiltin<"__builtin_ia32_pmovusqb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7386,7 +6773,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qb_256 : GCCBuiltin<"__builtin_ia32_pmovqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7396,7 +6783,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_256 : GCCBuiltin<"__builtin_ia32_pmovsqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7406,7 +6793,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_256 : GCCBuiltin<"__builtin_ia32_pmovusqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7416,7 +6803,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qb_512 : GCCBuiltin<"__builtin_ia32_pmovqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7426,7 +6813,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_512 : GCCBuiltin<"__builtin_ia32_pmovsqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7436,7 +6823,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_512 : GCCBuiltin<"__builtin_ia32_pmovusqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7446,7 +6833,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_128 : GCCBuiltin<"__builtin_ia32_pmovqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7456,7 +6843,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_128 : GCCBuiltin<"__builtin_ia32_pmovsqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7466,7 +6853,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_128 : GCCBuiltin<"__builtin_ia32_pmovusqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7476,7 +6863,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_256 : GCCBuiltin<"__builtin_ia32_pmovqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7486,7 +6873,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_256 : GCCBuiltin<"__builtin_ia32_pmovsqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7496,7 +6883,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_256 : GCCBuiltin<"__builtin_ia32_pmovusqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7506,7 +6893,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_512 : GCCBuiltin<"__builtin_ia32_pmovqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7516,7 +6903,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_512 : GCCBuiltin<"__builtin_ia32_pmovsqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7526,7 +6913,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_512 : GCCBuiltin<"__builtin_ia32_pmovusqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7536,7 +6923,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_128 : GCCBuiltin<"__builtin_ia32_pmovqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7546,7 +6933,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_128 : GCCBuiltin<"__builtin_ia32_pmovsqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7556,7 +6943,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_128 : GCCBuiltin<"__builtin_ia32_pmovusqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7566,7 +6953,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_256 : GCCBuiltin<"__builtin_ia32_pmovqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7576,7 +6963,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_256 : GCCBuiltin<"__builtin_ia32_pmovsqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7586,7 +6973,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_256 : GCCBuiltin<"__builtin_ia32_pmovusqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -7596,7 +6983,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_512 : GCCBuiltin<"__builtin_ia32_pmovqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -7606,7 +6993,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_512 : GCCBuiltin<"__builtin_ia32_pmovsqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -7616,7 +7003,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_512 : GCCBuiltin<"__builtin_ia32_pmovusqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -7626,7 +7013,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_128 : GCCBuiltin<"__builtin_ia32_pmovdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7636,7 +7023,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_128 : GCCBuiltin<"__builtin_ia32_pmovsdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7646,7 +7033,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_128 : GCCBuiltin<"__builtin_ia32_pmovusdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7656,7 +7043,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_256 : GCCBuiltin<"__builtin_ia32_pmovdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7666,7 +7053,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_256 : GCCBuiltin<"__builtin_ia32_pmovsdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7676,7 +7063,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_256 : GCCBuiltin<"__builtin_ia32_pmovusdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7686,7 +7073,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_512 : GCCBuiltin<"__builtin_ia32_pmovdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7696,7 +7083,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_512 : GCCBuiltin<"__builtin_ia32_pmovsdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7706,7 +7093,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_512 : GCCBuiltin<"__builtin_ia32_pmovusdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7716,7 +7103,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_128 : GCCBuiltin<"__builtin_ia32_pmovdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7726,7 +7113,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_128 : GCCBuiltin<"__builtin_ia32_pmovsdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7736,7 +7123,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_128 : GCCBuiltin<"__builtin_ia32_pmovusdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7746,7 +7133,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_256 : GCCBuiltin<"__builtin_ia32_pmovdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7756,7 +7143,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_256 : GCCBuiltin<"__builtin_ia32_pmovsdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7766,7 +7153,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_256 : GCCBuiltin<"__builtin_ia32_pmovusdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -7776,7 +7163,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_512 : GCCBuiltin<"__builtin_ia32_pmovdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -7786,7 +7173,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_512 : GCCBuiltin<"__builtin_ia32_pmovsdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -7796,7 +7183,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_512 : GCCBuiltin<"__builtin_ia32_pmovusdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -7806,7 +7193,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_128 : GCCBuiltin<"__builtin_ia32_pmovwb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7816,7 +7203,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_128 : GCCBuiltin<"__builtin_ia32_pmovswb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7826,7 +7213,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_128 : GCCBuiltin<"__builtin_ia32_pmovuswb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7836,7 +7223,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_256 : GCCBuiltin<"__builtin_ia32_pmovwb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7846,7 +7233,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_256 : GCCBuiltin<"__builtin_ia32_pmovswb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7856,7 +7243,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_256 : GCCBuiltin<"__builtin_ia32_pmovuswb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -7866,7 +7253,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_512 : GCCBuiltin<"__builtin_ia32_pmovwb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -7876,7 +7263,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_512 : GCCBuiltin<"__builtin_ia32_pmovswb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -7886,7 +7273,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_512 : GCCBuiltin<"__builtin_ia32_pmovuswb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -7896,7 +7283,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } // Bitwise ternary logic @@ -8034,3 +7421,14 @@ let TargetPrefix = "x86" in { def int_x86_sha256msg2 : GCCBuiltin<"__builtin_ia32_sha256msg2">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; } + +//===----------------------------------------------------------------------===// +// Thread synchronization ops with timer. +let TargetPrefix = "x86" in { + def int_x86_monitorx + : GCCBuiltin<"__builtin_ia32_monitorx">, + Intrinsic<[], [ llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty ], []>; + def int_x86_mwaitx + : GCCBuiltin<"__builtin_ia32_mwaitx">, + Intrinsic<[], [ llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], []>; +} diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 56aa3010d925..dbf2b4562332 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -16,7 +16,6 @@ #define LLVM_IR_LLVMCONTEXT_H #include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Options.h" namespace llvm { @@ -26,11 +25,15 @@ class StringRef; class Twine; class Instruction; class Module; +class MDString; +class DICompositeType; class SMDiagnostic; class DiagnosticInfo; +enum DiagnosticSeverity : char; template <typename T> class SmallVectorImpl; class Function; class DebugLoc; +class OptBisect; /// This is an important class for using LLVM in a threaded context. It /// (opaquely) owns and manages the core "global" data of LLVM's core @@ -46,24 +49,26 @@ public: // Pinned metadata names, which always have the same value. This is a // compile-time performance optimization, not a correctness optimization. enum { - MD_dbg = 0, // "dbg" - MD_tbaa = 1, // "tbaa" - MD_prof = 2, // "prof" - MD_fpmath = 3, // "fpmath" - MD_range = 4, // "range" - MD_tbaa_struct = 5, // "tbaa.struct" - MD_invariant_load = 6, // "invariant.load" - MD_alias_scope = 7, // "alias.scope" - MD_noalias = 8, // "noalias", - MD_nontemporal = 9, // "nontemporal" + MD_dbg = 0, // "dbg" + MD_tbaa = 1, // "tbaa" + MD_prof = 2, // "prof" + MD_fpmath = 3, // "fpmath" + MD_range = 4, // "range" + MD_tbaa_struct = 5, // "tbaa.struct" + MD_invariant_load = 6, // "invariant.load" + MD_alias_scope = 7, // "alias.scope" + MD_noalias = 8, // "noalias", + MD_nontemporal = 9, // "nontemporal" MD_mem_parallel_loop_access = 10, // "llvm.mem.parallel_loop_access" - MD_nonnull = 11, // "nonnull" - MD_dereferenceable = 12, // "dereferenceable" - MD_dereferenceable_or_null = 13, // "dereferenceable_or_null" - MD_make_implicit = 14, // "make.implicit" - MD_unpredictable = 15, // "unpredictable" - MD_invariant_group = 16, // "invariant.group" - MD_align = 17 // "align" + MD_nonnull = 11, // "nonnull" + MD_dereferenceable = 12, // "dereferenceable" + MD_dereferenceable_or_null = 13, // "dereferenceable_or_null" + MD_make_implicit = 14, // "make.implicit" + MD_unpredictable = 15, // "unpredictable" + MD_invariant_group = 16, // "invariant.group" + MD_align = 17, // "align" + MD_loop = 18, // "llvm.loop" + MD_type = 19, // "type" }; /// Known operand bundle tag IDs, which always have the same value. All @@ -71,8 +76,9 @@ public: /// Additionally, this scheme allows LLVM to efficiently check for specific /// operand bundle tags without comparing strings. enum { - OB_deopt = 0, // "deopt" - OB_funclet = 1, // "funclet" + OB_deopt = 0, // "deopt" + OB_funclet = 1, // "funclet" + OB_gc_transition = 2, // "gc-transition" }; /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. @@ -93,7 +99,6 @@ public: /// tag registered with an LLVMContext has an unique ID. uint32_t getOperandBundleTagID(StringRef Tag) const; - /// Define the GC for a function void setGC(const Function &Fn, std::string GCName); @@ -103,6 +108,21 @@ public: /// Remove the GC for a function void deleteGC(const Function &Fn); + /// Return true if the Context runtime configuration is set to discard all + /// value names. When true, only GlobalValue names will be available in the + /// IR. + bool shouldDiscardValueNames() const; + + /// Set the Context runtime configuration to discard all value name (but + /// GlobalValue). Clients can use this flag to save memory and runtime, + /// especially in release mode. + void setDiscardValueNames(bool Discard); + + /// Whether there is a string map for uniquing debug info + /// identifiers across the context. Off by default. + bool isODRUniquingDebugTypes() const; + void enableDebugTypeODRUniquing(); + void disableDebugTypeODRUniquing(); typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, unsigned LocCookie); @@ -154,6 +174,17 @@ public: /// setDiagnosticContext. void *getDiagnosticContext() const; + /// \brief Return if a code hotness metric should be included in optimization + /// diagnostics. + bool getDiagnosticHotnessRequested() const; + /// \brief Set if a code hotness metric should be included in optimization + /// diagnostics. + void setDiagnosticHotnessRequested(bool Requested); + + /// \brief Get the prefix that should be printed in front of a diagnostic of + /// the given \p Severity + static const char *getDiagnosticMessagePrefix(DiagnosticSeverity Severity); + /// \brief Report a message to the currently installed diagnostic handler. /// /// This function returns, in particular in the case of error reporting @@ -209,6 +240,9 @@ public: return OptionRegistry::instance().template get<ValT, Base, Mem>(); } + /// \brief Access the object which manages optimization bisection for failure + /// analysis. + OptBisect &getOptBisect(); private: LLVMContext(LLVMContext&) = delete; void operator=(LLVMContext&) = delete; @@ -224,10 +258,6 @@ private: friend class Module; }; -/// getGlobalContext - Returns a global context. This is for LLVM clients that -/// only care about operating on a single thread. -extern LLVMContext &getGlobalContext(); - // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef) diff --git a/include/llvm/IR/LegacyPassManagers.h b/include/llvm/IR/LegacyPassManagers.h index b8e33478d6a9..530fd7166498 100644 --- a/include/llvm/IR/LegacyPassManagers.h +++ b/include/llvm/IR/LegacyPassManagers.h @@ -14,13 +14,11 @@ #ifndef LLVM_IR_LEGACYPASSMANAGERS_H #define LLVM_IR_LEGACYPASSMANAGERS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Pass.h" -#include <map> #include <vector> //===----------------------------------------------------------------------===// @@ -93,12 +91,13 @@ #include "llvm/Support/PrettyStackTrace.h" namespace llvm { - class Module; - class Pass; - class StringRef; - class Value; - class Timer; - class PMDataManager; +template <typename T> class ArrayRef; +class Module; +class Pass; +class StringRef; +class Value; +class Timer; +class PMDataManager; // enums for debugging strings enum PassDebuggingString { diff --git a/include/llvm/IR/Mangler.h b/include/llvm/IR/Mangler.h index ea2f0c3f09f3..349218e33817 100644 --- a/include/llvm/IR/Mangler.h +++ b/include/llvm/IR/Mangler.h @@ -16,13 +16,13 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/IR/GlobalValue.h" -#include "llvm/Support/raw_ostream.h" namespace llvm { class DataLayout; template <typename T> class SmallVectorImpl; class Twine; +class raw_ostream; class Mangler { /// We need to give global values the same name every time they are mangled. diff --git a/include/llvm/IR/Metadata.def b/include/llvm/IR/Metadata.def index b1d22178e262..607f5ef125c9 100644 --- a/include/llvm/IR/Metadata.def +++ b/include/llvm/IR/Metadata.def @@ -77,6 +77,7 @@ HANDLE_METADATA_LEAF(MDString) HANDLE_METADATA_BRANCH(ValueAsMetadata) HANDLE_METADATA_LEAF(ConstantAsMetadata) HANDLE_METADATA_LEAF(LocalAsMetadata) +HANDLE_METADATA_LEAF(DistinctMDOperandPlaceholder) HANDLE_MDNODE_BRANCH(MDNode) HANDLE_MDNODE_LEAF_UNIQUABLE(MDTuple) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocation) diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index df8ce354bb7f..91f43d342d27 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Constant.h" @@ -51,7 +52,7 @@ protected: enum StorageType { Uniqued, Distinct, Temporary }; /// \brief Storage flag for non-uniqued, otherwise unowned, metadata. - unsigned Storage : 2; + unsigned char Storage; // TODO: expose remaining bits to subclasses. unsigned short SubclassData16; @@ -59,39 +60,14 @@ protected: public: enum MetadataKind { - MDTupleKind, - DILocationKind, - GenericDINodeKind, - DISubrangeKind, - DIEnumeratorKind, - DIBasicTypeKind, - DIDerivedTypeKind, - DICompositeTypeKind, - DISubroutineTypeKind, - DIFileKind, - DICompileUnitKind, - DISubprogramKind, - DILexicalBlockKind, - DILexicalBlockFileKind, - DINamespaceKind, - DIModuleKind, - DITemplateTypeParameterKind, - DITemplateValueParameterKind, - DIGlobalVariableKind, - DILocalVariableKind, - DIExpressionKind, - DIObjCPropertyKind, - DIImportedEntityKind, - ConstantAsMetadataKind, - LocalAsMetadataKind, - MDStringKind, - DIMacroKind, - DIMacroFileKind +#define HANDLE_METADATA_LEAF(CLASS) CLASS##Kind, +#include "llvm/IR/Metadata.def" }; protected: Metadata(unsigned ID, StorageType Storage) : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) { + static_assert(sizeof(*this) == 8, "Metdata fields poorly packed"); } ~Metadata() = default; @@ -283,20 +259,14 @@ private: LLVMContext &Context; uint64_t NextIndex; SmallDenseMap<void *, std::pair<OwnerTy, uint64_t>, 4> UseMap; - /// Flag that can be set to false if this metadata should not be - /// RAUW'ed, e.g. if it is used as the key of a map. - bool CanReplace; public: ReplaceableMetadataImpl(LLVMContext &Context) - : Context(Context), NextIndex(0), CanReplace(true) {} + : Context(Context), NextIndex(0) {} ~ReplaceableMetadataImpl() { assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata"); } - /// Set the CanReplace flag to the given value. - void setCanReplace(bool Replaceable) { CanReplace = Replaceable; } - LLVMContext &getContext() const { return Context; } /// \brief Replace all uses of this with MD. @@ -316,7 +286,19 @@ private: void dropRef(void *Ref); void moveRef(void *Ref, void *New, const Metadata &MD); - static ReplaceableMetadataImpl *get(Metadata &MD); + /// Lazily construct RAUW support on MD. + /// + /// If this is an unresolved MDNode, RAUW support will be created on-demand. + /// ValueAsMetadata always has RAUW support. + static ReplaceableMetadataImpl *getOrCreate(Metadata &MD); + + /// Get RAUW support on MD, if it exists. + static ReplaceableMetadataImpl *getIfExists(Metadata &MD); + + /// Check whether this node will support RAUW. + /// + /// Returns \c true unless getOrCreate() would return null. + static bool isReplaceable(const Metadata &MD); }; /// \brief Value wrapper in the Metadata hierarchy. @@ -592,7 +574,6 @@ class MDString : public Metadata { StringMapEntry<MDString> *Entry; MDString() : Metadata(MDStringKind, Uniqued), Entry(nullptr) {} - MDString(MDString &&) : Metadata(MDStringKind, Uniqued) {} public: static MDString *get(LLVMContext &Context, StringRef Str); @@ -767,6 +748,13 @@ public: return nullptr; } + /// Ensure that this has RAUW support, and then return it. + ReplaceableMetadataImpl *getOrCreateReplaceableUses() { + if (!hasReplaceableUses()) + makeReplaceable(llvm::make_unique<ReplaceableMetadataImpl>(getContext())); + return getReplaceableUses(); + } + /// \brief Assign RAUW support to this. /// /// Make this replaceable, taking ownership of \c ReplaceableUses (which must @@ -828,9 +816,9 @@ class MDNode : public Metadata { unsigned NumOperands; unsigned NumUnresolved; -protected: ContextAndReplaceableUses Context; +protected: void *operator new(size_t Size, unsigned NumOps); void operator delete(void *Mem); @@ -892,7 +880,7 @@ public: /// As forward declarations are resolved, their containers should get /// resolved automatically. However, if this (or one of its operands) is /// involved in a cycle, \a resolveCycles() needs to be called explicitly. - bool isResolved() const { return !Context.hasReplaceableUses(); } + bool isResolved() const { return !isTemporary() && !NumUnresolved; } bool isUniqued() const { return Storage == Uniqued; } bool isDistinct() const { return Storage == Distinct; } @@ -903,33 +891,17 @@ public: /// \pre \a isTemporary() must be \c true. void replaceAllUsesWith(Metadata *MD) { assert(isTemporary() && "Expected temporary node"); - assert(!isResolved() && "Expected RAUW support"); - Context.getReplaceableUses()->replaceAllUsesWith(MD); - } - - /// Set the CanReplace flag to the given value. - void setCanReplace(bool Replaceable) { - Context.getReplaceableUses()->setCanReplace(Replaceable); + if (Context.hasReplaceableUses()) + Context.getReplaceableUses()->replaceAllUsesWith(MD); } /// \brief Resolve cycles. /// /// Once all forward declarations have been resolved, force cycles to be - /// resolved. This interface is used when there are no more temporaries, - /// and thus unresolved nodes are part of cycles and no longer need RAUW - /// support. + /// resolved. /// /// \pre No operands (or operands' operands, etc.) have \a isTemporary(). - void resolveCycles() { resolveRecursivelyImpl(/* AllowTemps */ false); } - - /// \brief Resolve cycles while ignoring temporaries. - /// - /// This drops RAUW support for any temporaries, which can no longer - /// be uniqued. - /// - void resolveNonTemporaries() { - resolveRecursivelyImpl(/* AllowTemps */ true); - } + void resolveCycles(); /// \brief Replace a temporary node with a permanent one. /// @@ -982,15 +954,15 @@ protected: private: void handleChangedOperand(void *Ref, Metadata *New); + /// Resolve a unique, unresolved node. void resolve(); + + /// Drop RAUW support, if any. + void dropReplaceableUses(); + void resolveAfterOperandChange(Metadata *Old, Metadata *New); void decrementUnresolvedOperandCount(); - unsigned countUnresolvedOperands(); - - /// Resolve cycles recursively. If \p AllowTemps is true, then any temporary - /// metadata is ignored, otherwise it asserts when encountering temporary - /// metadata. - void resolveRecursivelyImpl(bool AllowTemps); + void countUnresolvedOperands(); /// \brief Mutate this to be "uniqued". /// @@ -1221,6 +1193,52 @@ public: typedef MDTupleTypedArrayWrapper<CLASS> CLASS##Array; #include "llvm/IR/Metadata.def" +/// Placeholder metadata for operands of distinct MDNodes. +/// +/// This is a lightweight placeholder for an operand of a distinct node. It's +/// purpose is to help track forward references when creating a distinct node. +/// This allows distinct nodes involved in a cycle to be constructed before +/// their operands without requiring a heavyweight temporary node with +/// full-blown RAUW support. +/// +/// Each placeholder supports only a single MDNode user. Clients should pass +/// an ID, retrieved via \a getID(), to indicate the "real" operand that this +/// should be replaced with. +/// +/// While it would be possible to implement move operators, they would be +/// fairly expensive. Leave them unimplemented to discourage their use +/// (clients can use std::deque, std::list, BumpPtrAllocator, etc.). +class DistinctMDOperandPlaceholder : public Metadata { + friend class MetadataTracking; + + Metadata **Use = nullptr; + + DistinctMDOperandPlaceholder() = delete; + DistinctMDOperandPlaceholder(DistinctMDOperandPlaceholder &&) = delete; + DistinctMDOperandPlaceholder(const DistinctMDOperandPlaceholder &) = delete; + +public: + explicit DistinctMDOperandPlaceholder(unsigned ID) + : Metadata(DistinctMDOperandPlaceholderKind, Distinct) { + SubclassData32 = ID; + } + + ~DistinctMDOperandPlaceholder() { + if (Use) + *Use = nullptr; + } + + unsigned getID() const { return SubclassData32; } + + /// Replace the use of this with MD. + void replaceUseWith(Metadata *MD) { + if (!Use) + return; + *Use = MD; + Use = nullptr; + } +}; + //===----------------------------------------------------------------------===// /// \brief A tuple of MDNodes. /// @@ -1297,6 +1315,8 @@ public: void setOperand(unsigned I, MDNode *New); StringRef getName() const; void print(raw_ostream &ROS, bool IsForDebug = false) const; + void print(raw_ostream &ROS, ModuleSlotTracker &MST, + bool IsForDebug = false) const; void dump() const; // --------------------------------------------------------------------------- diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 942f68543cb6..632b27e2d0dd 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -15,12 +15,12 @@ #ifndef LLVM_IR_MODULE_H #define LLVM_IR_MODULE_H -#include "llvm/ADT/Optional.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/CBindingWrapping.h" @@ -29,11 +29,13 @@ #include <system_error> namespace llvm { +template <typename T> class Optional; class FunctionType; class GVMaterializer; class LLVMContext; class RandomNumberGenerator; class StructType; +template <class PtrType> class SmallPtrSetImpl; template<> struct ilist_traits<NamedMDNode> : public ilist_default_traits<NamedMDNode> { @@ -75,6 +77,8 @@ public: typedef SymbolTableList<Function> FunctionListType; /// The type for the list of aliases. typedef SymbolTableList<GlobalAlias> AliasListType; + /// The type for the list of ifuncs. + typedef SymbolTableList<GlobalIFunc> IFuncListType; /// The type for the list of named metadata. typedef ilist<NamedMDNode> NamedMDListType; /// The type of the comdat "symbol" table. @@ -100,6 +104,11 @@ public: /// The Global Alias constant iterator typedef AliasListType::const_iterator const_alias_iterator; + /// The Global IFunc iterators. + typedef IFuncListType::iterator ifunc_iterator; + /// The Global IFunc constant iterator + typedef IFuncListType::const_iterator const_ifunc_iterator; + /// The named metadata iterators. typedef NamedMDListType::iterator named_metadata_iterator; /// The named metadata constant iterators. @@ -163,6 +172,7 @@ private: GlobalListType GlobalList; ///< The Global Variables in the module FunctionListType FunctionList; ///< The Functions in the module AliasListType AliasList; ///< The Aliases in the module + IFuncListType IFuncList; ///< The IFuncs in the module NamedMDListType NamedMDList; ///< The named metadata in the module std::string GlobalScopeAsm; ///< Inline Asm at global scope. ValueSymbolTable *ValSymTab; ///< Symbol table for values @@ -170,6 +180,8 @@ private: std::unique_ptr<GVMaterializer> Materializer; ///< Used to materialize GlobalValues std::string ModuleID; ///< Human readable identifier for the module + std::string SourceFileName; ///< Original source file name for module, + ///< recorded in bitcode. std::string TargetTriple; ///< Platform target triple Module compiled on ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) void *NamedMDSymTab; ///< NamedMDNode names. @@ -195,6 +207,12 @@ public: /// @returns the module identifier as a string const std::string &getModuleIdentifier() const { return ModuleID; } + /// Get the module's original source file name. When compiling from + /// bitcode, this is taken from a bitcode record where it was recorded. + /// For other compiles it is the same as the ModuleID, which would + /// contain the source file name. + const std::string &getSourceFileName() const { return SourceFileName; } + /// \brief Get a short "name" for the module. /// /// This is useful for debugging or logging. It is essentially a convenience @@ -240,6 +258,9 @@ public: /// Set the module identifier. void setModuleIdentifier(StringRef ID) { ModuleID = ID; } + /// Set the module's original source file name. + void setSourceFileName(StringRef Name) { SourceFileName = Name; } + /// Set the data layout void setDataLayout(StringRef Desc); void setDataLayout(const DataLayout &Other); @@ -251,8 +272,7 @@ public: /// A trailing newline is added if the input doesn't have one. void setModuleInlineAsm(StringRef Asm) { GlobalScopeAsm = Asm; - if (!GlobalScopeAsm.empty() && - GlobalScopeAsm[GlobalScopeAsm.size()-1] != '\n') + if (!GlobalScopeAsm.empty() && GlobalScopeAsm.back() != '\n') GlobalScopeAsm += '\n'; } @@ -260,8 +280,7 @@ public: /// A trailing newline is added if the input doesn't have one. void appendModuleInlineAsm(StringRef Asm) { GlobalScopeAsm += Asm; - if (!GlobalScopeAsm.empty() && - GlobalScopeAsm[GlobalScopeAsm.size()-1] != '\n') + if (!GlobalScopeAsm.empty() && GlobalScopeAsm.back() != '\n') GlobalScopeAsm += '\n'; } @@ -375,6 +394,15 @@ public: GlobalAlias *getNamedAlias(StringRef Name) const; /// @} +/// @name Global IFunc Accessors +/// @{ + + /// Return the global ifunc in the module with the specified name, of + /// arbitrary type. This method returns null if a global with the specified + /// name is not found. + GlobalIFunc *getNamedIFunc(StringRef Name) const; + +/// @} /// @name Named Metadata Accessors /// @{ @@ -477,6 +505,13 @@ public: static AliasListType Module::*getSublistAccess(GlobalAlias*) { return &Module::AliasList; } + /// Get the Module's list of ifuncs (constant). + const IFuncListType &getIFuncList() const { return IFuncList; } + /// Get the Module's list of ifuncs. + IFuncListType &getIFuncList() { return IFuncList; } + static IFuncListType Module::*getSublistAccess(GlobalIFunc*) { + return &Module::IFuncList; + } /// Get the Module's list of named metadata (constant). const NamedMDListType &getNamedMDList() const { return NamedMDList; } /// Get the Module's list of named metadata. @@ -551,9 +586,96 @@ public: } /// @} -/// @name Named Metadata Iteration +/// @name IFunc Iteration /// @{ + ifunc_iterator ifunc_begin() { return IFuncList.begin(); } + const_ifunc_iterator ifunc_begin() const { return IFuncList.begin(); } + ifunc_iterator ifunc_end () { return IFuncList.end(); } + const_ifunc_iterator ifunc_end () const { return IFuncList.end(); } + size_t ifunc_size () const { return IFuncList.size(); } + bool ifunc_empty() const { return IFuncList.empty(); } + + iterator_range<ifunc_iterator> ifuncs() { + return make_range(ifunc_begin(), ifunc_end()); + } + iterator_range<const_ifunc_iterator> ifuncs() const { + return make_range(ifunc_begin(), ifunc_end()); + } + +/// @} +/// @name Convenience iterators +/// @{ + + template <bool IsConst> class global_object_iterator_t { + friend Module; + + typename std::conditional<IsConst, const_iterator, iterator>::type + function_i, + function_e; + typename std::conditional<IsConst, const_global_iterator, + global_iterator>::type global_i; + + typedef + typename std::conditional<IsConst, const Module, Module>::type ModuleTy; + + global_object_iterator_t(ModuleTy &M) + : function_i(M.begin()), function_e(M.end()), + global_i(M.global_begin()) {} + global_object_iterator_t(ModuleTy &M, int) + : function_i(M.end()), function_e(M.end()), global_i(M.global_end()) {} + + public: + global_object_iterator_t &operator++() { + if (function_i != function_e) + ++function_i; + else + ++global_i; + return *this; + } + + typename std::conditional<IsConst, const GlobalObject, GlobalObject>::type & + operator*() const { + if (function_i != function_e) + return *function_i; + else + return *global_i; + } + + bool operator!=(const global_object_iterator_t &other) const { + return function_i != other.function_i || global_i != other.global_i; + } + }; + + typedef global_object_iterator_t</*IsConst=*/false> global_object_iterator; + typedef global_object_iterator_t</*IsConst=*/true> + const_global_object_iterator; + + global_object_iterator global_object_begin() { + return global_object_iterator(*this); + } + global_object_iterator global_object_end() { + return global_object_iterator(*this, 0); + } + + const_global_object_iterator global_object_begin() const { + return const_global_object_iterator(*this); + } + const_global_object_iterator global_object_end() const { + return const_global_object_iterator(*this, 0); + } + + iterator_range<global_object_iterator> global_objects() { + return make_range(global_object_begin(), global_object_end()); + } + iterator_range<const_global_object_iterator> global_objects() const { + return make_range(global_object_begin(), global_object_end()); + } + + /// @} + /// @name Named Metadata Iteration + /// @{ + named_metadata_iterator named_metadata_begin() { return NamedMDList.begin(); } const_named_metadata_iterator named_metadata_begin() const { return NamedMDList.begin(); @@ -574,6 +696,58 @@ public: return make_range(named_metadata_begin(), named_metadata_end()); } + /// An iterator for DICompileUnits that skips those marked NoDebug. + class debug_compile_units_iterator + : public std::iterator<std::input_iterator_tag, DICompileUnit *> { + NamedMDNode *CUs; + unsigned Idx; + void SkipNoDebugCUs(); + public: + explicit debug_compile_units_iterator(NamedMDNode *CUs, unsigned Idx) + : CUs(CUs), Idx(Idx) { + SkipNoDebugCUs(); + } + debug_compile_units_iterator &operator++() { + ++Idx; + SkipNoDebugCUs(); + return *this; + } + debug_compile_units_iterator operator++(int) { + debug_compile_units_iterator T(*this); + ++Idx; + return T; + } + bool operator==(const debug_compile_units_iterator &I) const { + return Idx == I.Idx; + } + bool operator!=(const debug_compile_units_iterator &I) const { + return Idx != I.Idx; + } + DICompileUnit *operator*() const; + DICompileUnit *operator->() const; + }; + + debug_compile_units_iterator debug_compile_units_begin() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return debug_compile_units_iterator(CUs, 0); + } + + debug_compile_units_iterator debug_compile_units_end() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0); + } + + /// Return an iterator for all DICompileUnits listed in this Module's + /// llvm.dbg.cu named metadata node and aren't explicitly marked as + /// NoDebug. + iterator_range<debug_compile_units_iterator> debug_compile_units() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return make_range( + debug_compile_units_iterator(CUs, 0), + debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0)); + } +/// @} + /// Destroy ConstantArrays in LLVMContext if they are not used. /// ConstantArrays constructed during linking can cause quadratic memory /// explosion. Releasing all unused constants can cause a 20% LTO compile-time @@ -583,7 +757,6 @@ public: /// be called where all uses of the LLVMContext are understood. void dropTriviallyDeadConstantArrays(); -/// @} /// @name Utility functions for printing and dumping Module objects /// @{ @@ -628,17 +801,34 @@ public: void setPICLevel(PICLevel::Level PL); /// @} - /// @name Utility functions for querying and setting PGO counts +/// @} +/// @name Utility functions for querying and setting PIE level +/// @{ + + /// \brief Returns the PIE level (small or large model) + PIELevel::Level getPIELevel() const; + + /// \brief Set the PIE level (small or large model) + void setPIELevel(PIELevel::Level PL); +/// @} + + /// @name Utility functions for querying and setting PGO summary /// @{ - /// \brief Set maximum function count in PGO mode - void setMaximumFunctionCount(uint64_t); + /// \brief Attach profile summary metadata to this module. + void setProfileSummary(Metadata *M); - /// \brief Returns maximum function count in PGO mode - Optional<uint64_t> getMaximumFunctionCount(); + /// \brief Returns profile summary metadata + Metadata *getProfileSummary(); /// @} }; +/// \brief Given "llvm.used" or "llvm.compiler.used" as a global name, collect +/// the initializer elements of that global in Set and return the global itself. +GlobalVariable *collectUsedGlobalVariables(const Module &M, + SmallPtrSetImpl<GlobalValue *> &Set, + bool CompilerUsed); + /// An raw_ostream inserter for modules. inline raw_ostream &operator<<(raw_ostream &O, const Module &M) { M.print(O, nullptr); diff --git a/include/llvm/IR/ModuleSlotTracker.h b/include/llvm/IR/ModuleSlotTracker.h index 49730a66bdf6..eb26fba906ea 100644 --- a/include/llvm/IR/ModuleSlotTracker.h +++ b/include/llvm/IR/ModuleSlotTracker.h @@ -30,6 +30,8 @@ class Value; class ModuleSlotTracker { /// Storage for a slot tracker. std::unique_ptr<SlotTracker> MachineStorage; + bool ShouldCreateStorage = false; + bool ShouldInitializeAllMetadata = false; const Module *M = nullptr; const Function *F = nullptr; @@ -53,7 +55,9 @@ public: /// Destructor to clean up storage. ~ModuleSlotTracker(); - SlotTracker *getMachine() const { return Machine; } + /// Lazily creates a slot tracker. + SlotTracker *getMachine(); + const Module *getModule() const { return M; } const Function *getCurrentFunction() const { return F; } diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h new file mode 100644 index 000000000000..45d9bf7af706 --- /dev/null +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -0,0 +1,508 @@ +//===-- llvm/ModuleSummaryIndex.h - Module Summary Index --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// @file +/// ModuleSummaryIndex.h This file contains the declarations the classes that +/// hold the module index and summary for function importing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_MODULESUMMARYINDEX_H +#define LLVM_IR_MODULESUMMARYINDEX_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/Module.h" + +#include <array> + +namespace llvm { + +/// \brief Class to accumulate and hold information about a callee. +struct CalleeInfo { + /// The static number of callsites calling corresponding function. + unsigned CallsiteCount; + /// The cumulative profile count of calls to corresponding function + /// (if using PGO, otherwise 0). + uint64_t ProfileCount; + CalleeInfo() : CallsiteCount(0), ProfileCount(0) {} + CalleeInfo(unsigned CallsiteCount, uint64_t ProfileCount) + : CallsiteCount(CallsiteCount), ProfileCount(ProfileCount) {} + CalleeInfo &operator+=(uint64_t RHSProfileCount) { + CallsiteCount++; + ProfileCount += RHSProfileCount; + return *this; + } +}; + +/// Struct to hold value either by GUID or Value*, depending on whether this +/// is a combined or per-module index, respectively. +struct ValueInfo { + /// The value representation used in this instance. + enum ValueInfoKind { + VI_GUID, + VI_Value, + }; + + /// Union of the two possible value types. + union ValueUnion { + GlobalValue::GUID Id; + const Value *V; + ValueUnion(GlobalValue::GUID Id) : Id(Id) {} + ValueUnion(const Value *V) : V(V) {} + }; + + /// The value being represented. + ValueUnion TheValue; + /// The value representation. + ValueInfoKind Kind; + /// Constructor for a GUID value + ValueInfo(GlobalValue::GUID Id = 0) : TheValue(Id), Kind(VI_GUID) {} + /// Constructor for a Value* value + ValueInfo(const Value *V) : TheValue(V), Kind(VI_Value) {} + /// Accessor for GUID value + GlobalValue::GUID getGUID() const { + assert(Kind == VI_GUID && "Not a GUID type"); + return TheValue.Id; + } + /// Accessor for Value* value + const Value *getValue() const { + assert(Kind == VI_Value && "Not a Value type"); + return TheValue.V; + } + bool isGUID() const { return Kind == VI_GUID; } +}; + +/// \brief Function and variable summary information to aid decisions and +/// implementation of importing. +class GlobalValueSummary { +public: + /// \brief Sububclass discriminator (for dyn_cast<> et al.) + enum SummaryKind { AliasKind, FunctionKind, GlobalVarKind }; + + /// Group flags (Linkage, hasSection, isOptSize, etc.) as a bitfield. + struct GVFlags { + /// \brief The linkage type of the associated global value. + /// + /// One use is to flag values that have local linkage types and need to + /// have module identifier appended before placing into the combined + /// index, to disambiguate from other values with the same name. + /// In the future this will be used to update and optimize linkage + /// types based on global summary-based analysis. + unsigned Linkage : 4; + + /// Indicate if the global value is located in a specific section. + unsigned HasSection : 1; + + /// Convenience Constructors + explicit GVFlags(GlobalValue::LinkageTypes Linkage, bool HasSection) + : Linkage(Linkage), HasSection(HasSection) {} + GVFlags(const GlobalValue &GV) + : Linkage(GV.getLinkage()), HasSection(GV.hasSection()) {} + }; + +private: + /// Kind of summary for use in dyn_cast<> et al. + SummaryKind Kind; + + /// This is the hash of the name of the symbol in the original file. It is + /// identical to the GUID for global symbols, but differs for local since the + /// GUID includes the module level id in the hash. + GlobalValue::GUID OriginalName; + + /// \brief Path of module IR containing value's definition, used to locate + /// module during importing. + /// + /// This is only used during parsing of the combined index, or when + /// parsing the per-module index for creation of the combined summary index, + /// not during writing of the per-module index which doesn't contain a + /// module path string table. + StringRef ModulePath; + + GVFlags Flags; + + /// List of values referenced by this global value's definition + /// (either by the initializer of a global variable, or referenced + /// from within a function). This does not include functions called, which + /// are listed in the derived FunctionSummary object. + std::vector<ValueInfo> RefEdgeList; + +protected: + /// GlobalValueSummary constructor. + GlobalValueSummary(SummaryKind K, GVFlags Flags) : Kind(K), Flags(Flags) {} + +public: + virtual ~GlobalValueSummary() = default; + + /// Returns the hash of the original name, it is identical to the GUID for + /// externally visible symbols, but not for local ones. + GlobalValue::GUID getOriginalName() { return OriginalName; } + + /// Initialize the original name hash in this summary. + void setOriginalName(GlobalValue::GUID Name) { OriginalName = Name; } + + /// Which kind of summary subclass this is. + SummaryKind getSummaryKind() const { return Kind; } + + /// Set the path to the module containing this function, for use in + /// the combined index. + void setModulePath(StringRef ModPath) { ModulePath = ModPath; } + + /// Get the path to the module containing this function. + StringRef modulePath() const { return ModulePath; } + + /// Get the flags for this GlobalValue (see \p struct GVFlags). + GVFlags flags() { return Flags; } + + /// Return linkage type recorded for this global value. + GlobalValue::LinkageTypes linkage() const { + return static_cast<GlobalValue::LinkageTypes>(Flags.Linkage); + } + + /// Sets the linkage to the value determined by global summary-based + /// optimization. Will be applied in the ThinLTO backends. + void setLinkage(GlobalValue::LinkageTypes Linkage) { + Flags.Linkage = Linkage; + } + + /// Return true if this summary is for a GlobalValue that needs promotion + /// to be referenced from another module. + bool needsRenaming() const { return GlobalValue::isLocalLinkage(linkage()); } + + /// Return true if this global value is located in a specific section. + bool hasSection() const { return Flags.HasSection; } + + /// Record a reference from this global value to the global value identified + /// by \p RefGUID. + void addRefEdge(GlobalValue::GUID RefGUID) { RefEdgeList.push_back(RefGUID); } + + /// Record a reference from this global value to the global value identified + /// by \p RefV. + void addRefEdge(const Value *RefV) { RefEdgeList.push_back(RefV); } + + /// Record a reference from this global value to each global value identified + /// in \p RefEdges. + void addRefEdges(DenseSet<const Value *> &RefEdges) { + for (auto &RI : RefEdges) + addRefEdge(RI); + } + + /// Return the list of values referenced by this global value definition. + std::vector<ValueInfo> &refs() { return RefEdgeList; } + const std::vector<ValueInfo> &refs() const { return RefEdgeList; } +}; + +/// \brief Alias summary information. +class AliasSummary : public GlobalValueSummary { + GlobalValueSummary *AliaseeSummary; + +public: + /// Summary constructors. + AliasSummary(GVFlags Flags) : GlobalValueSummary(AliasKind, Flags) {} + + /// Check if this is an alias summary. + static bool classof(const GlobalValueSummary *GVS) { + return GVS->getSummaryKind() == AliasKind; + } + + void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } + + const GlobalValueSummary &getAliasee() const { + return const_cast<AliasSummary *>(this)->getAliasee(); + } + + GlobalValueSummary &getAliasee() { + assert(AliaseeSummary && "Unexpected missing aliasee summary"); + return *AliaseeSummary; + } +}; + +/// \brief Function summary information to aid decisions and implementation of +/// importing. +class FunctionSummary : public GlobalValueSummary { +public: + /// <CalleeValueInfo, CalleeInfo> call edge pair. + typedef std::pair<ValueInfo, CalleeInfo> EdgeTy; + +private: + /// Number of instructions (ignoring debug instructions, e.g.) computed + /// during the initial compile step when the summary index is first built. + unsigned InstCount; + + /// List of <CalleeValueInfo, CalleeInfo> call edge pairs from this function. + std::vector<EdgeTy> CallGraphEdgeList; + +public: + /// Summary constructors. + FunctionSummary(GVFlags Flags, unsigned NumInsts) + : GlobalValueSummary(FunctionKind, Flags), InstCount(NumInsts) {} + + /// Check if this is a function summary. + static bool classof(const GlobalValueSummary *GVS) { + return GVS->getSummaryKind() == FunctionKind; + } + + /// Get the instruction count recorded for this function. + unsigned instCount() const { return InstCount; } + + /// Record a call graph edge from this function to the function identified + /// by \p CalleeGUID, with \p CalleeInfo including the cumulative profile + /// count (across all calls from this function) or 0 if no PGO. + void addCallGraphEdge(GlobalValue::GUID CalleeGUID, CalleeInfo Info) { + CallGraphEdgeList.push_back(std::make_pair(CalleeGUID, Info)); + } + + /// Record a call graph edge from this function to each function GUID recorded + /// in \p CallGraphEdges. + void + addCallGraphEdges(DenseMap<GlobalValue::GUID, CalleeInfo> &CallGraphEdges) { + for (auto &EI : CallGraphEdges) + addCallGraphEdge(EI.first, EI.second); + } + + /// Record a call graph edge from this function to the function identified + /// by \p CalleeV, with \p CalleeInfo including the cumulative profile + /// count (across all calls from this function) or 0 if no PGO. + void addCallGraphEdge(const Value *CalleeV, CalleeInfo Info) { + CallGraphEdgeList.push_back(std::make_pair(CalleeV, Info)); + } + + /// Record a call graph edge from this function to each function recorded + /// in \p CallGraphEdges. + void addCallGraphEdges(DenseMap<const Value *, CalleeInfo> &CallGraphEdges) { + for (auto &EI : CallGraphEdges) + addCallGraphEdge(EI.first, EI.second); + } + + /// Return the list of <CalleeValueInfo, CalleeInfo> pairs. + std::vector<EdgeTy> &calls() { return CallGraphEdgeList; } + const std::vector<EdgeTy> &calls() const { return CallGraphEdgeList; } +}; + +/// \brief Global variable summary information to aid decisions and +/// implementation of importing. +/// +/// Currently this doesn't add anything to the base \p GlobalValueSummary, +/// but is a placeholder as additional info may be added to the summary +/// for variables. +class GlobalVarSummary : public GlobalValueSummary { + +public: + /// Summary constructors. + GlobalVarSummary(GVFlags Flags) : GlobalValueSummary(GlobalVarKind, Flags) {} + + /// Check if this is a global variable summary. + static bool classof(const GlobalValueSummary *GVS) { + return GVS->getSummaryKind() == GlobalVarKind; + } +}; + +/// 160 bits SHA1 +typedef std::array<uint32_t, 5> ModuleHash; + +/// List of global value summary structures for a particular value held +/// in the GlobalValueMap. Requires a vector in the case of multiple +/// COMDAT values of the same name. +typedef std::vector<std::unique_ptr<GlobalValueSummary>> GlobalValueSummaryList; + +/// Map from global value GUID to corresponding summary structures. +/// Use a std::map rather than a DenseMap since it will likely incur +/// less overhead, as the value type is not very small and the size +/// of the map is unknown, resulting in inefficiencies due to repeated +/// insertions and resizing. +typedef std::map<GlobalValue::GUID, GlobalValueSummaryList> + GlobalValueSummaryMapTy; + +/// Type used for iterating through the global value summary map. +typedef GlobalValueSummaryMapTy::const_iterator const_gvsummary_iterator; +typedef GlobalValueSummaryMapTy::iterator gvsummary_iterator; + +/// String table to hold/own module path strings, which additionally holds the +/// module ID assigned to each module during the plugin step, as well as a hash +/// of the module. The StringMap makes a copy of and owns inserted strings. +typedef StringMap<std::pair<uint64_t, ModuleHash>> ModulePathStringTableTy; + +/// Map of global value GUID to its summary, used to identify values defined in +/// a particular module, and provide efficient access to their summary. +typedef std::map<GlobalValue::GUID, GlobalValueSummary *> GVSummaryMapTy; + +/// Class to hold module path string table and global value map, +/// and encapsulate methods for operating on them. +class ModuleSummaryIndex { +private: + /// Map from value name to list of summary instances for values of that + /// name (may be duplicates in the COMDAT case, e.g.). + GlobalValueSummaryMapTy GlobalValueMap; + + /// Holds strings for combined index, mapping to the corresponding module ID. + ModulePathStringTableTy ModulePathStringTable; + +public: + ModuleSummaryIndex() = default; + + // Disable the copy constructor and assignment operators, so + // no unexpected copying/moving occurs. + ModuleSummaryIndex(const ModuleSummaryIndex &) = delete; + void operator=(const ModuleSummaryIndex &) = delete; + + gvsummary_iterator begin() { return GlobalValueMap.begin(); } + const_gvsummary_iterator begin() const { return GlobalValueMap.begin(); } + gvsummary_iterator end() { return GlobalValueMap.end(); } + const_gvsummary_iterator end() const { return GlobalValueMap.end(); } + + /// Get the list of global value summary objects for a given value name. + const GlobalValueSummaryList &getGlobalValueSummaryList(StringRef ValueName) { + return GlobalValueMap[GlobalValue::getGUID(ValueName)]; + } + + /// Get the list of global value summary objects for a given value name. + const const_gvsummary_iterator + findGlobalValueSummaryList(StringRef ValueName) const { + return GlobalValueMap.find(GlobalValue::getGUID(ValueName)); + } + + /// Get the list of global value summary objects for a given value GUID. + const const_gvsummary_iterator + findGlobalValueSummaryList(GlobalValue::GUID ValueGUID) const { + return GlobalValueMap.find(ValueGUID); + } + + /// Add a global value summary for a value of the given name. + void addGlobalValueSummary(StringRef ValueName, + std::unique_ptr<GlobalValueSummary> Summary) { + GlobalValueMap[GlobalValue::getGUID(ValueName)].push_back( + std::move(Summary)); + } + + /// Add a global value summary for a value of the given GUID. + void addGlobalValueSummary(GlobalValue::GUID ValueGUID, + std::unique_ptr<GlobalValueSummary> Summary) { + GlobalValueMap[ValueGUID].push_back(std::move(Summary)); + } + + /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if + /// not found. + GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, + StringRef ModuleId) const { + auto CalleeInfoList = findGlobalValueSummaryList(ValueGUID); + if (CalleeInfoList == end()) { + return nullptr; // This function does not have a summary + } + auto Summary = + llvm::find_if(CalleeInfoList->second, + [&](const std::unique_ptr<GlobalValueSummary> &Summary) { + return Summary->modulePath() == ModuleId; + }); + if (Summary == CalleeInfoList->second.end()) + return nullptr; + return Summary->get(); + } + + /// Returns the first GlobalValueSummary for \p GV, asserting that there + /// is only one if \p PerModuleIndex. + GlobalValueSummary *getGlobalValueSummary(const GlobalValue &GV, + bool PerModuleIndex = true) const { + assert(GV.hasName() && "Can't get GlobalValueSummary for GV with no name"); + return getGlobalValueSummary(GlobalValue::getGUID(GV.getName()), + PerModuleIndex); + } + + /// Returns the first GlobalValueSummary for \p ValueGUID, asserting that + /// there + /// is only one if \p PerModuleIndex. + GlobalValueSummary *getGlobalValueSummary(GlobalValue::GUID ValueGUID, + bool PerModuleIndex = true) const; + + /// Table of modules, containing module hash and id. + const StringMap<std::pair<uint64_t, ModuleHash>> &modulePaths() const { + return ModulePathStringTable; + } + + /// Table of modules, containing hash and id. + StringMap<std::pair<uint64_t, ModuleHash>> &modulePaths() { + return ModulePathStringTable; + } + + /// Get the module ID recorded for the given module path. + uint64_t getModuleId(const StringRef ModPath) const { + return ModulePathStringTable.lookup(ModPath).first; + } + + /// Get the module SHA1 hash recorded for the given module path. + const ModuleHash &getModuleHash(const StringRef ModPath) const { + auto It = ModulePathStringTable.find(ModPath); + assert(It != ModulePathStringTable.end() && "Module not registered"); + return It->second.second; + } + + /// Add the given per-module index into this module index/summary, + /// assigning it the given module ID. Each module merged in should have + /// a unique ID, necessary for consistent renaming of promoted + /// static (local) variables. + void mergeFrom(std::unique_ptr<ModuleSummaryIndex> Other, + uint64_t NextModuleId); + + /// Convenience method for creating a promoted global name + /// for the given value name of a local, and its original module's ID. + static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash) { + SmallString<256> NewName(Name); + NewName += ".llvm."; + NewName += utohexstr(ModHash[0]); // Take the first 32 bits + return NewName.str(); + } + + /// Helper to obtain the unpromoted name for a global value (or the original + /// name if not promoted). + static StringRef getOriginalNameBeforePromote(StringRef Name) { + std::pair<StringRef, StringRef> Pair = Name.split(".llvm."); + return Pair.first; + } + + /// Add a new module path with the given \p Hash, mapped to the given \p + /// ModID, and return an iterator to the entry in the index. + ModulePathStringTableTy::iterator + addModulePath(StringRef ModPath, uint64_t ModId, + ModuleHash Hash = ModuleHash{{0}}) { + return ModulePathStringTable.insert(std::make_pair( + ModPath, + std::make_pair(ModId, Hash))).first; + } + + /// Check if the given Module has any functions available for exporting + /// in the index. We consider any module present in the ModulePathStringTable + /// to have exported functions. + bool hasExportedFunctions(const Module &M) const { + return ModulePathStringTable.count(M.getModuleIdentifier()); + } + + /// 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(), + /// but if there was only one module or this was the first module we might + /// not invoke mergeFrom. + void removeEmptySummaryEntries(); + + /// Collect for the given module the list of function it defines + /// (GUID -> Summary). + void collectDefinedFunctionsForModule(StringRef ModulePath, + GVSummaryMapTy &GVSummaryMap) const; + + /// Collect for each module the list of Summaries it defines (GUID -> + /// Summary). + void collectDefinedGVSummariesPerModule( + StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const; +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 372b254ab183..5880290f3d99 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -79,7 +79,7 @@ public: }; private: - friend class BinaryOperator; + friend class Instruction; friend class ConstantExpr; void setHasNoUnsignedWrap(bool B) { SubclassOptionalData = @@ -130,7 +130,7 @@ public: }; private: - friend class BinaryOperator; + friend class Instruction; friend class ConstantExpr; void setIsExact(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact); @@ -401,6 +401,7 @@ public: } Type *getSourceElementType() const; + Type *getResultElementType() const; /// Method to return the address space of the pointer operand. unsigned getPointerAddressSpace() const { diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h new file mode 100644 index 000000000000..9eee65e93e52 --- /dev/null +++ b/include/llvm/IR/OptBisect.h @@ -0,0 +1,81 @@ +//===----------- llvm/IR/OptBisect.h - LLVM Bisect support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the interface for bisecting optimizations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_OPTBISECT_H +#define LLVM_IR_OPTBISECT_H + +namespace llvm { + +class Pass; +class StringRef; +class Twine; + +/// This class implements a mechanism to disable passes and individual +/// optimizations at compile time based on a command line option +/// (-opt-bisect-limit) in order to perform a bisecting search for +/// optimization-related problems. +class OptBisect { +public: + /// \brief Default constructor, initializes the OptBisect state based on the + /// -opt-bisect-limit command line argument. + /// + /// By default, bisection is disabled. + /// + /// Clients should not instantiate this class directly. All access should go + /// through LLVMContext. + OptBisect(); + + /// Checks the bisect limit to determine if the specified pass 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 describing + /// the pass and the bisect number assigned to it and return true. Otherwise, + /// the function will print a message with the bisect number assigned to the + /// pass 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. + /// + /// Most passes should not call this routine directly. Instead, it is called + /// through a helper routine provided by the pass base class. For instance, + /// function passes should call FunctionPass::skipFunction(). + 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); + + bool BisectEnabled = false; + unsigned LastBisectNum = 0; +}; + +} // end namespace llvm + +#endif // LLVM_IR_OPTBISECT_H diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 2ceb53d21b7a..402d04a54a41 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -44,8 +44,8 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManagerInternal.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/TypeName.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/type_traits.h" #include <list> @@ -54,9 +54,6 @@ namespace llvm { -class Module; -class Function; - /// \brief An abstract set of preserved analyses following a transformation pass /// run. /// @@ -147,6 +144,16 @@ public: PreservedPassIDs.count(PassID); } + /// \brief Query whether all of the analyses in the set are preserved. + bool preserved(PreservedAnalyses Arg) { + if (Arg.areAllPreserved()) + return areAllPreserved(); + for (void *P : Arg.PreservedPassIDs) + if (!preserved(P)) + return false; + return true; + } + /// \brief Test whether all passes are preserved. /// /// This is used primarily to optimize for the case of no changes which will @@ -166,6 +173,44 @@ private: // Forward declare the analysis manager template. template <typename IRUnitT> class AnalysisManager; +/// A CRTP mix-in to automatically provide informational APIs needed for +/// passes. +/// +/// This provides some boiler plate for types that are passes. +template <typename DerivedT> struct PassInfoMixin { + /// Returns the name of the derived pass type. + static StringRef name() { + StringRef Name = getTypeName<DerivedT>(); + if (Name.startswith("llvm::")) + Name = Name.drop_front(strlen("llvm::")); + return Name; + } +}; + +/// A CRTP mix-in to automatically provide informational APIs needed for +/// analysis passes. +/// +/// This provides some boiler plate for types that are analysis passes. It +/// automatically mixes in \c PassInfoMixin and adds informational APIs +/// specifically used for analyses. +template <typename DerivedT> +struct AnalysisInfoMixin : PassInfoMixin<DerivedT> { + /// Returns an opaque, unique ID for this pass type. + /// + /// Note that this requires the derived type provide a static member whose + /// address can be converted to a void pointer. + /// + /// FIXME: The only reason the derived type needs to provide this rather than + /// this mixin providing it is due to broken implementations which cannot + /// correctly unique a templated static so that they have the same addresses + /// for each instantiation and are definitively emitted once for each + /// instantiation. The only currently known platform with this limitation are + /// Windows DLL builds, specifically building each part of LLVM as a DLL. If + /// we ever remove that build configuration, this mixin can provide the + /// static PassID as well. + static void *ID() { return (void *)&DerivedT::PassID; } +}; + /// \brief Manages a sequence of passes over units of IR. /// /// A pass manager contains a sequence of passes to run over units of IR. It is @@ -177,7 +222,8 @@ template <typename IRUnitT> class AnalysisManager; /// that analysis manager to each pass it runs, as well as calling the analysis /// manager's invalidation routine with the PreservedAnalyses of each pass it /// runs. -template <typename IRUnitT> class PassManager { +template <typename IRUnitT> +class PassManager : public PassInfoMixin<PassManager<IRUnitT>> { public: /// \brief Construct a pass manager. /// @@ -195,11 +241,11 @@ public: } /// \brief Run all of the passes in this manager over the IR. - PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM = nullptr) { + PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) { PreservedAnalyses PA = PreservedAnalyses::all(); if (DebugLogging) - dbgs() << "Starting pass manager run.\n"; + dbgs() << "Starting " << getTypeName<IRUnitT>() << " pass manager run.\n"; for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { if (DebugLogging) @@ -208,13 +254,11 @@ public: PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM); - // If we have an active analysis manager at this level we want to ensure - // we update it as each pass runs and potentially invalidates analyses. - // We also update the preserved set of analyses based on what analyses we - // have already handled the invalidation for here and don't need to - // invalidate when finished. - if (AM) - PassPA = AM->invalidate(IR, std::move(PassPA)); + // Update the analysis manager as each pass runs and potentially + // invalidates analyses. We also update the preserved set of analyses + // based on what analyses we have already handled the invalidation for + // here and don't need to invalidate when finished. + PassPA = AM.invalidate(IR, std::move(PassPA)); // Finally, we intersect the final preserved analyses to compute the // aggregate preserved set for this pass manager. @@ -228,7 +272,7 @@ public: } if (DebugLogging) - dbgs() << "Finished pass manager run.\n"; + dbgs() << "Finished " << getTypeName<IRUnitT>() << " pass manager run.\n"; return PA; } @@ -238,8 +282,6 @@ public: Passes.emplace_back(new PassModelT(std::move(Pass))); } - static StringRef name() { return "PassManager"; } - private: typedef detail::PassConcept<IRUnitT> PassConceptT; @@ -252,9 +294,11 @@ private: bool DebugLogging; }; +extern template class PassManager<Module>; /// \brief Convenience typedef for a pass manager over modules. typedef PassManager<Module> ModulePassManager; +extern template class PassManager<Function>; /// \brief Convenience typedef for a pass manager over functions. typedef PassManager<Function> FunctionPassManager; @@ -284,8 +328,7 @@ template <typename DerivedT, typename IRUnitT> class AnalysisManagerBase { } AnalysisManagerBase(const AnalysisManagerBase &) = delete; - AnalysisManagerBase & - operator=(const AnalysisManagerBase &) = delete; + AnalysisManagerBase &operator=(const AnalysisManagerBase &) = delete; protected: typedef detail::AnalysisResultConcept<IRUnitT> ResultConceptT; @@ -342,14 +385,34 @@ public: /// \brief Register an analysis pass with the manager. /// - /// This provides an initialized and set-up analysis pass to the analysis - /// manager. Whomever is setting up analysis passes must use this to populate - /// the manager with all of the analysis passes available. - template <typename PassT> void registerPass(PassT Pass) { - assert(!AnalysisPasses.count(PassT::ID()) && - "Registered the same analysis pass twice!"); + /// The argument is a callable whose result is a pass. This allows passing in + /// a lambda to construct the pass. + /// + /// The pass type registered is the result type of calling the argument. If + /// that pass has already been registered, then the argument will not be + /// called and this function will return false. Otherwise, the pass type + /// becomes registered, with the instance provided by calling the argument + /// once, and this function returns true. + /// + /// While this returns whether or not the pass type was already registered, + /// there in't an independent way to query that as that would be prone to + /// risky use when *querying* the analysis manager. Instead, the only + /// supported use case is avoiding duplicate registry of an analysis. This + /// interface also lends itself to minimizing the number of times we have to + /// do lookups for analyses or construct complex passes only to throw them + /// away. + template <typename PassBuilderT> bool registerPass(PassBuilderT PassBuilder) { + typedef decltype(PassBuilder()) PassT; typedef detail::AnalysisPassModel<IRUnitT, PassT> PassModelT; - AnalysisPasses[PassT::ID()].reset(new PassModelT(std::move(Pass))); + + auto &PassPtr = AnalysisPasses[PassT::ID()]; + if (PassPtr) + // Already registered this pass type! + return false; + + // Construct a new model around the instance returned by the builder. + PassPtr.reset(new PassModelT(PassBuilder())); + return true; } /// \brief Invalidate a specific analysis pass for an IR module. @@ -472,7 +535,7 @@ private: if (DebugLogging) dbgs() << "Running analysis: " << P.name() << "\n"; AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; - ResultList.emplace_back(PassID, P.run(IR, this)); + ResultList.emplace_back(PassID, P.run(IR, *this)); // P.run may have inserted elements into AnalysisResults and invalidated // RI. @@ -513,8 +576,8 @@ private: return PA; if (DebugLogging) - dbgs() << "Invalidating all non-preserved analyses for: " - << IR.getName() << "\n"; + dbgs() << "Invalidating all non-preserved analyses for: " << IR.getName() + << "\n"; // Clear all the invalidated results associated specifically with this // function. @@ -574,7 +637,8 @@ private: /// \brief Map type from a pair of analysis ID and function pointer to an /// iterator into a particular result list. typedef DenseMap<std::pair<void *, IRUnitT *>, - typename AnalysisResultListT::iterator> AnalysisResultMapT; + typename AnalysisResultListT::iterator> + AnalysisResultMapT; /// \brief Map from an analysis ID and function to a particular cached /// analysis result. @@ -584,9 +648,11 @@ private: bool DebugLogging; }; +extern template class AnalysisManager<Module>; /// \brief Convenience typedef for the Module analysis manager. typedef AnalysisManager<Module> ModuleAnalysisManager; +extern template class AnalysisManager<Function>; /// \brief Convenience typedef for the Function analysis manager. typedef AnalysisManager<Function> FunctionAnalysisManager; @@ -598,26 +664,80 @@ typedef AnalysisManager<Function> FunctionAnalysisManager; /// never use a function analysis manager from within (transitively) a module /// pass manager unless your parent module pass has received a proxy result /// object for it. -class FunctionAnalysisManagerModuleProxy { +/// +/// Note that the proxy's result is a move-only object and represents ownership +/// of the validity of the analyses in the \c FunctionAnalysisManager it +/// provides. +template <typename AnalysisManagerT, typename IRUnitT> +class InnerAnalysisManagerProxy + : public AnalysisInfoMixin< + InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>> { public: - class Result; + class Result { + public: + explicit Result(AnalysisManagerT &AM) : AM(&AM) {} + Result(Result &&Arg) : AM(std::move(Arg.AM)) { + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + Arg.AM = nullptr; + } + Result &operator=(Result &&RHS) { + AM = RHS.AM; + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + RHS.AM = nullptr; + return *this; + } + ~Result() { + // AM is cleared in a moved from state where there is nothing to do. + if (!AM) + return; + + // Clear out the analysis manager if we're being destroyed -- it means we + // didn't even see an invalidate call when we got invalidated. + AM->clear(); + } - static void *ID() { return (void *)&PassID; } + /// \brief Accessor for the analysis manager. + AnalysisManagerT &getManager() { return *AM; } + + /// \brief Handler for invalidation of the module. + /// + /// If this analysis itself is preserved, then we assume that the set of \c + /// Function objects in the \c Module hasn't changed and thus we don't need + /// to invalidate *all* cached data associated with a \c Function* in the \c + /// FunctionAnalysisManager. + /// + /// Regardless of whether this analysis is marked as preserved, all of the + /// analyses in the \c FunctionAnalysisManager are potentially invalidated + /// based on the set of preserved analyses. + bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA) { + // If this proxy isn't marked as preserved, then we can't even invalidate + // individual function analyses, there may be an invalid set of Function + // objects in the cache making it impossible to incrementally preserve + // them. Just clear the entire manager. + if (!PA.preserved(InnerAnalysisManagerProxy::ID())) + AM->clear(); + + // Return false to indicate that this result is still a valid proxy. + return false; + } - static StringRef name() { return "FunctionAnalysisManagerModuleProxy"; } + private: + AnalysisManagerT *AM; + }; - explicit FunctionAnalysisManagerModuleProxy(FunctionAnalysisManager &FAM) - : FAM(&FAM) {} + explicit InnerAnalysisManagerProxy(AnalysisManagerT &AM) : AM(&AM) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. - FunctionAnalysisManagerModuleProxy( - const FunctionAnalysisManagerModuleProxy &Arg) - : FAM(Arg.FAM) {} - FunctionAnalysisManagerModuleProxy(FunctionAnalysisManagerModuleProxy &&Arg) - : FAM(std::move(Arg.FAM)) {} - FunctionAnalysisManagerModuleProxy & - operator=(FunctionAnalysisManagerModuleProxy RHS) { - std::swap(FAM, RHS.FAM); + InnerAnalysisManagerProxy(const InnerAnalysisManagerProxy &Arg) + : AM(Arg.AM) {} + InnerAnalysisManagerProxy(InnerAnalysisManagerProxy &&Arg) + : AM(std::move(Arg.AM)) {} + InnerAnalysisManagerProxy &operator=(InnerAnalysisManagerProxy RHS) { + std::swap(AM, RHS.AM); return *this; } @@ -630,49 +750,24 @@ public: /// In debug builds, it will also assert that the analysis manager is empty /// as no queries should arrive at the function analysis manager prior to /// this analysis being requested. - Result run(Module &M); + Result run(IRUnitT &IR, AnalysisManager<IRUnitT> &) { return Result(*AM); } private: + friend AnalysisInfoMixin< + InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>>; static char PassID; - FunctionAnalysisManager *FAM; + AnalysisManagerT *AM; }; -/// \brief The result proxy object for the -/// \c FunctionAnalysisManagerModuleProxy. -/// -/// See its documentation for more information. -class FunctionAnalysisManagerModuleProxy::Result { -public: - explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - Result(const Result &Arg) : FAM(Arg.FAM) {} - Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {} - Result &operator=(Result RHS) { - std::swap(FAM, RHS.FAM); - return *this; - } - ~Result(); - - /// \brief Accessor for the \c FunctionAnalysisManager. - FunctionAnalysisManager &getManager() { return *FAM; } - - /// \brief Handler for invalidation of the module. - /// - /// If this analysis itself is preserved, then we assume that the set of \c - /// Function objects in the \c Module hasn't changed and thus we don't need - /// to invalidate *all* cached data associated with a \c Function* in the \c - /// FunctionAnalysisManager. - /// - /// Regardless of whether this analysis is marked as preserved, all of the - /// analyses in the \c FunctionAnalysisManager are potentially invalidated - /// based on the set of preserved analyses. - bool invalidate(Module &M, const PreservedAnalyses &PA); +template <typename AnalysisManagerT, typename IRUnitT> +char InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>::PassID; -private: - FunctionAnalysisManager *FAM; -}; +extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager, + Module>; +/// Provide the \c FunctionAnalysisManager to \c Module proxy. +typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, Module> + FunctionAnalysisManagerModuleProxy; /// \brief A function analysis which acts as a proxy for a module analysis /// manager. @@ -686,60 +781,67 @@ private: /// This proxy *doesn't* manage the invalidation in any way. That is handled by /// the recursive return path of each layer of the pass manager and the /// returned PreservedAnalysis set. -class ModuleAnalysisManagerFunctionProxy { +template <typename AnalysisManagerT, typename IRUnitT> +class OuterAnalysisManagerProxy + : public AnalysisInfoMixin< + OuterAnalysisManagerProxy<AnalysisManagerT, IRUnitT>> { public: - /// \brief Result proxy object for \c ModuleAnalysisManagerFunctionProxy. + /// \brief Result proxy object for \c OuterAnalysisManagerProxy. class Result { public: - explicit Result(const ModuleAnalysisManager &MAM) : MAM(&MAM) {} + explicit Result(const AnalysisManagerT &AM) : AM(&AM) {} // We have to explicitly define all the special member functions because // MSVC refuses to generate them. - Result(const Result &Arg) : MAM(Arg.MAM) {} - Result(Result &&Arg) : MAM(std::move(Arg.MAM)) {} + Result(const Result &Arg) : AM(Arg.AM) {} + Result(Result &&Arg) : AM(std::move(Arg.AM)) {} Result &operator=(Result RHS) { - std::swap(MAM, RHS.MAM); + std::swap(AM, RHS.AM); return *this; } - const ModuleAnalysisManager &getManager() const { return *MAM; } + const AnalysisManagerT &getManager() const { return *AM; } /// \brief Handle invalidation by ignoring it, this pass is immutable. - bool invalidate(Function &) { return false; } + bool invalidate(IRUnitT &) { return false; } private: - const ModuleAnalysisManager *MAM; + const AnalysisManagerT *AM; }; - static void *ID() { return (void *)&PassID; } - - static StringRef name() { return "ModuleAnalysisManagerFunctionProxy"; } - - ModuleAnalysisManagerFunctionProxy(const ModuleAnalysisManager &MAM) - : MAM(&MAM) {} + OuterAnalysisManagerProxy(const AnalysisManagerT &AM) : AM(&AM) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. - ModuleAnalysisManagerFunctionProxy( - const ModuleAnalysisManagerFunctionProxy &Arg) - : MAM(Arg.MAM) {} - ModuleAnalysisManagerFunctionProxy(ModuleAnalysisManagerFunctionProxy &&Arg) - : MAM(std::move(Arg.MAM)) {} - ModuleAnalysisManagerFunctionProxy & - operator=(ModuleAnalysisManagerFunctionProxy RHS) { - std::swap(MAM, RHS.MAM); + OuterAnalysisManagerProxy(const OuterAnalysisManagerProxy &Arg) + : AM(Arg.AM) {} + OuterAnalysisManagerProxy(OuterAnalysisManagerProxy &&Arg) + : AM(std::move(Arg.AM)) {} + OuterAnalysisManagerProxy &operator=(OuterAnalysisManagerProxy RHS) { + std::swap(AM, RHS.AM); return *this; } /// \brief Run the analysis pass and create our proxy result object. - /// Nothing to see here, it just forwards the \c MAM reference into the + /// Nothing to see here, it just forwards the \c AM reference into the /// result. - Result run(Function &) { return Result(*MAM); } + Result run(IRUnitT &, AnalysisManager<IRUnitT> &) { return Result(*AM); } private: + friend AnalysisInfoMixin< + OuterAnalysisManagerProxy<AnalysisManagerT, IRUnitT>>; static char PassID; - const ModuleAnalysisManager *MAM; + const AnalysisManagerT *AM; }; +template <typename AnalysisManagerT, typename IRUnitT> +char OuterAnalysisManagerProxy<AnalysisManagerT, IRUnitT>::PassID; + +extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager, + Function>; +/// Provide the \c ModuleAnalysisManager to \c Fucntion proxy. +typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, Function> + ModuleAnalysisManagerFunctionProxy; + /// \brief Trivial adaptor that maps from a module to its functions. /// /// Designed to allow composition of a FunctionPass(Manager) and @@ -762,7 +864,9 @@ private: /// module. /// FIXME: Make the above true for all of LLVM's actual passes, some still /// violate this principle. -template <typename FunctionPassT> class ModuleToFunctionPassAdaptor { +template <typename FunctionPassT> +class ModuleToFunctionPassAdaptor + : public PassInfoMixin<ModuleToFunctionPassAdaptor<FunctionPassT>> { public: explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass) : Pass(std::move(Pass)) {} @@ -783,11 +887,10 @@ public: } /// \brief Runs the function pass across every function in the module. - PreservedAnalyses run(Module &M, ModuleAnalysisManager *AM) { - FunctionAnalysisManager *FAM = nullptr; - if (AM) - // Setup the function analysis manager from its proxy. - FAM = &AM->getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { + // Setup the function analysis manager from its proxy. + FunctionAnalysisManager &FAM = + AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); PreservedAnalyses PA = PreservedAnalyses::all(); for (Function &F : M) { @@ -801,8 +904,7 @@ public: // directly handle the function analysis manager's invalidation here and // update our preserved set to reflect that these have already been // handled. - if (FAM) - PassPA = FAM->invalidate(F, std::move(PassPA)); + PassPA = FAM.invalidate(F, std::move(PassPA)); // Then intersect the preserved set so that invalidation of module // analyses will eventually occur when the module pass completes. @@ -817,8 +919,6 @@ public: return PA; } - static StringRef name() { return "ModuleToFunctionPassAdaptor"; } - private: FunctionPassT Pass; }; @@ -835,7 +935,8 @@ createModuleToFunctionPassAdaptor(FunctionPassT Pass) { /// /// This is a no-op pass which simply forces a specific analysis pass's result /// to be available when it is run. -template <typename AnalysisT> struct RequireAnalysisPass { +template <typename AnalysisT> +struct RequireAnalysisPass : PassInfoMixin<RequireAnalysisPass<AnalysisT>> { /// \brief Run this pass over some unit of IR. /// /// This pass can be run over any unit of IR and use any analysis manager @@ -843,14 +944,11 @@ template <typename AnalysisT> struct RequireAnalysisPass { /// created, these methods can be instantiated to satisfy whatever the /// context requires. template <typename IRUnitT> - PreservedAnalyses run(IRUnitT &Arg, AnalysisManager<IRUnitT> *AM) { - if (AM) - (void)AM->template getResult<AnalysisT>(Arg); + PreservedAnalyses run(IRUnitT &Arg, AnalysisManager<IRUnitT> &AM) { + (void)AM.template getResult<AnalysisT>(Arg); return PreservedAnalyses::all(); } - - static StringRef name() { return "RequireAnalysisPass"; } }; /// \brief A template utility pass to force an analysis result to be @@ -858,7 +956,9 @@ template <typename AnalysisT> struct RequireAnalysisPass { /// /// This is a no-op pass which simply forces a specific analysis result to be /// invalidated when it is run. -template <typename AnalysisT> struct InvalidateAnalysisPass { +template <typename AnalysisT> +struct InvalidateAnalysisPass + : PassInfoMixin<InvalidateAnalysisPass<AnalysisT>> { /// \brief Run this pass over some unit of IR. /// /// This pass can be run over any unit of IR and use any analysis manager @@ -866,29 +966,25 @@ template <typename AnalysisT> struct InvalidateAnalysisPass { /// created, these methods can be instantiated to satisfy whatever the /// context requires. template <typename IRUnitT> - PreservedAnalyses run(IRUnitT &Arg, AnalysisManager<IRUnitT> *AM) { - if (AM) - // We have to directly invalidate the analysis result as we can't - // enumerate all other analyses and use the preserved set to control it. - (void)AM->template invalidate<AnalysisT>(Arg); + PreservedAnalyses run(IRUnitT &Arg, AnalysisManager<IRUnitT> &AM) { + // We have to directly invalidate the analysis result as we can't + // enumerate all other analyses and use the preserved set to control it. + AM.template invalidate<AnalysisT>(Arg); return PreservedAnalyses::all(); } - - static StringRef name() { return "InvalidateAnalysisPass"; } }; /// \brief A utility pass that does nothing but preserves no analyses. /// /// As a consequence fo not preserving any analyses, this pass will force all /// analysis passes to be re-run to produce fresh results if any are needed. -struct InvalidateAllAnalysesPass { +struct InvalidateAllAnalysesPass : PassInfoMixin<InvalidateAllAnalysesPass> { /// \brief Run this pass over some unit of IR. - template <typename IRUnitT> PreservedAnalyses run(IRUnitT &Arg) { + template <typename IRUnitT> + PreservedAnalyses run(IRUnitT &, AnalysisManager<IRUnitT> &) { return PreservedAnalyses::none(); } - - static StringRef name() { return "InvalidateAllAnalysesPass"; } }; } diff --git a/include/llvm/IR/PassManagerInternal.h b/include/llvm/IR/PassManagerInternal.h index 92de10bcd75b..4351b5888283 100644 --- a/include/llvm/IR/PassManagerInternal.h +++ b/include/llvm/IR/PassManagerInternal.h @@ -18,8 +18,8 @@ #ifndef LLVM_IR_PASSMANAGERINTERNAL_H #define LLVM_IR_PASSMANAGERINTERNAL_H -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" namespace llvm { @@ -40,48 +40,20 @@ template <typename IRUnitT> struct PassConcept { /// Note that actual pass object can omit the analysis manager argument if /// desired. Also that the analysis manager may be null if there is no /// analysis manager in the pass pipeline. - virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0; + virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) = 0; /// \brief Polymorphic method to access the name of a pass. virtual StringRef name() = 0; }; -/// \brief SFINAE metafunction for computing whether \c PassT has a run method -/// accepting an \c AnalysisManager<IRUnitT>. -template <typename IRUnitT, typename PassT, typename ResultT> -class PassRunAcceptsAnalysisManager { - typedef char SmallType; - struct BigType { - char a, b; - }; - - template <typename T, ResultT (T::*)(IRUnitT &, AnalysisManager<IRUnitT> *)> - struct Checker; - - template <typename T> static SmallType f(Checker<T, &T::run> *); - template <typename T> static BigType f(...); - -public: - enum { Value = sizeof(f<PassT>(nullptr)) == sizeof(SmallType) }; -}; - /// \brief A template wrapper used to implement the polymorphic API. /// /// Can be instantiated for any object which provides a \c run method accepting -/// an \c IRUnitT. It requires the pass to be a copyable object. When the -/// \c run method also accepts an \c AnalysisManager<IRUnitT>*, we pass it -/// along. +/// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to +/// be a copyable object. When the template <typename IRUnitT, typename PassT, - typename PreservedAnalysesT = PreservedAnalyses, - bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager< - IRUnitT, PassT, PreservedAnalysesT>::Value> -struct PassModel; - -/// \brief Specialization of \c PassModel for passes that accept an analyis -/// manager. -template <typename IRUnitT, typename PassT, typename PreservedAnalysesT> -struct PassModel<IRUnitT, PassT, PreservedAnalysesT, true> - : PassConcept<IRUnitT> { + typename PreservedAnalysesT = PreservedAnalyses> +struct PassModel : PassConcept<IRUnitT> { explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -96,39 +68,13 @@ struct PassModel<IRUnitT, PassT, PreservedAnalysesT, true> return *this; } - PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override { + PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) override { return Pass.run(IR, AM); } StringRef name() override { return PassT::name(); } PassT Pass; }; -/// \brief Specialization of \c PassModel for passes that accept an analyis -/// manager. -template <typename IRUnitT, typename PassT, typename PreservedAnalysesT> -struct PassModel<IRUnitT, PassT, PreservedAnalysesT, false> - : PassConcept<IRUnitT> { - explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} - PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} - friend void swap(PassModel &LHS, PassModel &RHS) { - using std::swap; - swap(LHS.Pass, RHS.Pass); - } - PassModel &operator=(PassModel RHS) { - swap(*this, RHS); - return *this; - } - - PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override { - return Pass.run(IR); - } - StringRef name() override { return PassT::name(); } - PassT Pass; -}; - /// \brief Abstract concept of an analysis result. /// /// This concept is parameterized over the IR unit that this result pertains @@ -252,7 +198,7 @@ template <typename IRUnitT> struct AnalysisPassConcept { /// \returns A unique_ptr to the analysis result object to be queried by /// users. virtual std::unique_ptr<AnalysisResultConcept<IRUnitT>> - run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0; + run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) = 0; /// \brief Polymorphic method to access the name of a pass. virtual StringRef name() = 0; @@ -261,17 +207,10 @@ template <typename IRUnitT> struct AnalysisPassConcept { /// \brief Wrapper to model the analysis pass concept. /// /// Can wrap any type which implements a suitable \c run method. The method -/// must accept the IRUnitT as an argument and produce an object which can be -/// wrapped in a \c AnalysisResultModel. -template <typename IRUnitT, typename PassT, - bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager< - IRUnitT, PassT, typename PassT::Result>::Value> -struct AnalysisPassModel; - -/// \brief Specialization of \c AnalysisPassModel which passes an -/// \c AnalysisManager to PassT's run method. +/// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments +/// and produce an object which can be wrapped in a \c AnalysisResultModel. template <typename IRUnitT, typename PassT> -struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> { +struct AnalysisPassModel : AnalysisPassConcept<IRUnitT> { explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -294,7 +233,7 @@ struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> { /// /// The return is wrapped in an \c AnalysisResultModel. std::unique_ptr<AnalysisResultConcept<IRUnitT>> - run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override { + run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) override { return make_unique<ResultModelT>(Pass.run(IR, AM)); } @@ -306,44 +245,6 @@ struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> { PassT Pass; }; -/// \brief Specialization of \c AnalysisPassModel which does not pass an -/// \c AnalysisManager to PassT's run method. -template <typename IRUnitT, typename PassT> -struct AnalysisPassModel<IRUnitT, PassT, false> : AnalysisPassConcept<IRUnitT> { - explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} - AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} - friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { - using std::swap; - swap(LHS.Pass, RHS.Pass); - } - AnalysisPassModel &operator=(AnalysisPassModel RHS) { - swap(*this, RHS); - return *this; - } - - // FIXME: Replace PassT::Result with type traits when we use C++11. - typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result> - ResultModelT; - - /// \brief The model delegates to the \c PassT::run method. - /// - /// The return is wrapped in an \c AnalysisResultModel. - std::unique_ptr<AnalysisResultConcept<IRUnitT>> - run(IRUnitT &IR, AnalysisManager<IRUnitT> *) override { - return make_unique<ResultModelT>(Pass.run(IR)); - } - - /// \brief The model delegates to a static \c PassT::name method. - /// - /// The returned string ref must point to constant immutable data! - StringRef name() override { return PassT::name(); } - - PassT Pass; -}; - } // End namespace detail } diff --git a/include/llvm/IR/PatternMatch.h b/include/llvm/IR/PatternMatch.h index f4d7d8c44416..7da9afcf9463 100644 --- a/include/llvm/IR/PatternMatch.h +++ b/include/llvm/IR/PatternMatch.h @@ -1312,6 +1312,43 @@ template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) { return Signum_match<Val_t>(V); } +//===----------------------------------------------------------------------===// +// Matchers for two-operands operators with the operators in either order +// + +/// \brief Matches an ICmp with a predicate over LHS and RHS in either order. +/// Does not swap the predicate. +template<typename LHS, typename RHS> +inline match_combine_or<CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>, + CmpClass_match<RHS, LHS, ICmpInst, ICmpInst::Predicate>> +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 an And with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::And>, + BinaryOp_match<RHS, LHS, Instruction::And>> +m_c_And(const LHS &L, const RHS &R) { + return m_CombineOr(m_And(L, R), m_And(R, L)); +} + +/// \brief Matches an Or with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Or>, + BinaryOp_match<RHS, LHS, Instruction::Or>> +m_c_Or(const LHS &L, const RHS &R) { + return m_CombineOr(m_Or(L, R), m_Or(R, L)); +} + +/// \brief Matches an Xor with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Xor>, + BinaryOp_match<RHS, LHS, Instruction::Xor>> +m_c_Xor(const LHS &L, const RHS &R) { + return m_CombineOr(m_Xor(L, R), m_Xor(R, L)); +} + } // end namespace PatternMatch } // end namespace llvm diff --git a/include/llvm/IR/ProfileSummary.h b/include/llvm/IR/ProfileSummary.h new file mode 100644 index 000000000000..f4248014c6e1 --- /dev/null +++ b/include/llvm/IR/ProfileSummary.h @@ -0,0 +1,85 @@ +//===-- ProfileSummary.h - Profile summary data structure. ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the profile summary data structure. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PROFILE_SUMMARY_H +#define LLVM_SUPPORT_PROFILE_SUMMARY_H + +#include <cstdint> +#include <utility> +#include <vector> + +#include "llvm/Support/Casting.h" + +namespace llvm { + +class LLVMContext; +class Metadata; +class MDTuple; +class MDNode; + +// The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. +// The semantics of counts depend on the type of profile. For instrumentation +// profile, counts are block counts and for sample profile, counts are +// per-line samples. Given a target counts percentile, we compute the minimum +// number of counts needed to reach this target and the minimum among these +// counts. +struct ProfileSummaryEntry { + uint32_t Cutoff; ///< The required percentile of counts. + uint64_t MinCount; ///< The minimum count for this percentile. + uint64_t NumCounts; ///< Number of counts >= the minimum count. + ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinCount, + uint64_t TheNumCounts) + : Cutoff(TheCutoff), MinCount(TheMinCount), NumCounts(TheNumCounts) {} +}; + +typedef std::vector<ProfileSummaryEntry> SummaryEntryVector; + +class ProfileSummary { +public: + enum Kind { PSK_Instr, PSK_Sample }; + +private: + const Kind PSK; + static const char *KindStr[2]; + SummaryEntryVector DetailedSummary; + uint64_t TotalCount, MaxCount, MaxInternalCount, MaxFunctionCount; + uint32_t NumCounts, NumFunctions; + /// \brief Return detailed summary as metadata. + Metadata *getDetailedSummaryMD(LLVMContext &Context); + +public: + static const int Scale = 1000000; + ProfileSummary(Kind K, SummaryEntryVector DetailedSummary, + uint64_t TotalCount, uint64_t MaxCount, + uint64_t MaxInternalCount, uint64_t MaxFunctionCount, + uint32_t NumCounts, uint32_t NumFunctions) + : PSK(K), DetailedSummary(std::move(DetailedSummary)), + TotalCount(TotalCount), MaxCount(MaxCount), + MaxInternalCount(MaxInternalCount), MaxFunctionCount(MaxFunctionCount), + NumCounts(NumCounts), NumFunctions(NumFunctions) {} + Kind getKind() const { return PSK; } + /// \brief Return summary information as metadata. + Metadata *getMD(LLVMContext &Context); + /// \brief Construct profile summary from metdata. + static ProfileSummary *getFromMD(Metadata *MD); + SummaryEntryVector &getDetailedSummary() { return DetailedSummary; } + uint32_t getNumFunctions() { return NumFunctions; } + uint64_t getMaxFunctionCount() { return MaxFunctionCount; } + uint32_t getNumCounts() { return NumCounts; } + uint64_t getTotalCount() { return TotalCount; } + uint64_t getMaxCount() { return MaxCount; } + uint64_t getMaxInternalCount() { return MaxInternalCount; } +}; + +} // end namespace llvm +#endif diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h index 51a0951a9798..5cd7fe1b576c 100644 --- a/include/llvm/IR/Statepoint.h +++ b/include/llvm/IR/Statepoint.h @@ -8,8 +8,9 @@ //===----------------------------------------------------------------------===// // // This file contains utility functions and a wrapper class analogous to -// CallSite for accessing the fields of gc.statepoint, gc.relocate, and -// gc.result intrinsics +// CallSite for accessing the fields of gc.statepoint, gc.relocate, +// gc.result intrinsics; and some general utilities helpful when dealing with +// gc.statepoint. // //===----------------------------------------------------------------------===// @@ -17,6 +18,7 @@ #define LLVM_IR_STATEPOINT_H #include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/Optional.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" @@ -24,7 +26,6 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" -#include "llvm/Support/Compiler.h" namespace llvm { /// The statepoint intrinsic accepts a set of flags as its third argument. @@ -38,23 +39,22 @@ enum class StatepointFlags { }; class GCRelocateInst; +class GCResultInst; class ImmutableStatepoint; -bool isStatepoint(const ImmutableCallSite &CS); +bool isStatepoint(ImmutableCallSite CS); bool isStatepoint(const Value *V); bool isStatepoint(const Value &V); -bool isGCRelocate(const ImmutableCallSite &CS); - -bool isGCResult(const Value *V); -bool isGCResult(const ImmutableCallSite &CS); +bool isGCRelocate(ImmutableCallSite CS); +bool isGCResult(ImmutableCallSite CS); /// Analogous to CallSiteBase, this provides most of the actual /// functionality for Statepoint and ImmutableStatepoint. It is /// templatized to allow easily specializing of const and non-const /// concrete subtypes. This is structured analogous to CallSite -/// rather than the IntrinsicInst.h helpers since we want to support -/// invokable statepoints in the near future. +/// rather than the IntrinsicInst.h helpers since we need to support +/// invokable statepoints. template <typename FunTy, typename InstructionTy, typename ValueTy, typename CallSiteTy> class StatepointBase { @@ -252,11 +252,10 @@ public: /// Get the experimental_gc_result call tied to this statepoint. Can be /// nullptr if there isn't a gc_result tied to this statepoint. Guaranteed to /// be a CallInst if non-null. - InstructionTy *getGCResult() const { + const GCResultInst *getGCResult() const { for (auto *U : getInstruction()->users()) - if (isGCResult(U)) - return cast<CallInst>(U); - + if (auto *GRI = dyn_cast<GCResultInst>(U)) + return GRI; return nullptr; } @@ -305,11 +304,13 @@ public: explicit Statepoint(CallSite CS) : Base(CS) {} }; -/// This represents the gc.relocate intrinsic. -class GCRelocateInst : public IntrinsicInst { +/// Common base class for representing values projected from a statepoint. +/// Currently, the only projections available are gc.result and gc.relocate. +class GCProjectionInst : public IntrinsicInst { public: static inline bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate; + return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate || + I->getIntrinsicID() == Intrinsic::experimental_gc_result; } static inline bool classof(const Value *V) { return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); @@ -330,6 +331,7 @@ public: // This takes care both of relocates for call statepoints and relocates // on normal path of invoke statepoint. if (!isa<LandingPadInst>(Token)) { + assert(isStatepoint(Token)); return cast<Instruction>(Token); } @@ -344,6 +346,17 @@ public: return InvokeBB->getTerminator(); } +}; + +/// Represents calls to the gc.relocate intrinsic. +class GCRelocateInst : public GCProjectionInst { +public: + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate; + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } /// The index into the associate statepoint's argument list /// which contains the base pointer of the pointer whose @@ -369,6 +382,17 @@ public: } }; +/// Represents calls to the gc.result intrinsic. +class GCResultInst : public GCProjectionInst { +public: + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::experimental_gc_result; + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } +}; + template <typename FunTy, typename InstructionTy, typename ValueTy, typename CallSiteTy> std::vector<const GCRelocateInst *> @@ -400,6 +424,26 @@ StatepointBase<FunTy, InstructionTy, ValueTy, CallSiteTy>::getRelocates() } return Result; } + +/// Call sites that get wrapped by a gc.statepoint (currently only in +/// RewriteStatepointsForGC and potentially in other passes in the future) can +/// have attributes that describe properties of gc.statepoint call they will be +/// eventually be wrapped in. This struct is used represent such directives. +struct StatepointDirectives { + Optional<uint32_t> NumPatchBytes; + Optional<uint64_t> StatepointID; + + static const uint64_t DefaultStatepointID = 0xABCDEF00; + static const uint64_t DeoptBundleStatepointID = 0xABCDEF0F; +}; + +/// Parse out statepoint directives from the function attributes present in \p +/// AS. +StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeSet AS); + +/// Return \c true if the the \p Attr is an attribute that is a statepoint +/// directive. +bool isStatepointDirectiveAttr(Attribute Attr); } #endif diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index 5fc48d10d63f..60e04e2f9eca 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -49,6 +49,7 @@ class Function; class Instruction; class GlobalVariable; class GlobalAlias; +class GlobalIFunc; class Module; #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \ template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; }; @@ -58,6 +59,7 @@ DEFINE_SYMBOL_TABLE_PARENT_TYPE(Argument, Function) DEFINE_SYMBOL_TABLE_PARENT_TYPE(Function, Module) DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalVariable, Module) DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalAlias, Module) +DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalIFunc, Module) #undef DEFINE_SYMBOL_TABLE_PARENT_TYPE template <typename NodeTy> class SymbolTableList; diff --git a/include/llvm/IR/TrackingMDRef.h b/include/llvm/IR/TrackingMDRef.h index 97efaff7a377..fe513a8f9795 100644 --- a/include/llvm/IR/TrackingMDRef.h +++ b/include/llvm/IR/TrackingMDRef.h @@ -15,7 +15,6 @@ #define LLVM_IR_TRACKINGMDREF_H #include "llvm/IR/Metadata.h" -#include "llvm/Support/Casting.h" namespace llvm { diff --git a/include/llvm/IR/Type.h b/include/llvm/IR/Type.h index b2920dd3de63..ef7ad733f47a 100644 --- a/include/llvm/IR/Type.h +++ b/include/llvm/IR/Type.h @@ -16,6 +16,7 @@ #define LLVM_IR_TYPE_H #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" @@ -75,7 +76,7 @@ public: }; private: - /// Context - This refers to the LLVMContext in which this type was uniqued. + /// This refers to the LLVMContext in which this type was uniqued. LLVMContext &Context; TypeID ID : 8; // The current base type of this type. @@ -96,56 +97,64 @@ protected: assert(getSubclassData() == val && "Subclass data too large for field"); } - /// NumContainedTys - Keeps track of how many Type*'s there are in the - /// ContainedTys list. + /// Keeps track of how many Type*'s there are in the ContainedTys list. unsigned NumContainedTys; - /// ContainedTys - A pointer to the array of Types contained by this Type. - /// For example, this includes the arguments of a function type, the elements - /// of a structure, the pointee of a pointer, the element type of an array, - /// etc. This pointer may be 0 for types that don't contain other types - /// (Integer, Double, Float). + /// A pointer to the array of Types contained by this Type. For example, this + /// includes the arguments of a function type, the elements of a structure, + /// the pointee of a pointer, the element type of an array, etc. This pointer + /// may be 0 for types that don't contain other types (Integer, Double, + /// Float). Type * const *ContainedTys; + static bool isSequentialType(TypeID TyID) { + return TyID == ArrayTyID || TyID == PointerTyID || TyID == VectorTyID; + } + public: - void print(raw_ostream &O, bool IsForDebug = false) const; + /// Print the current type. + /// Omit the type details if \p NoDetails == true. + /// E.g., let %st = type { i32, i16 } + /// When \p NoDetails is true, we only print %st. + /// Put differently, \p NoDetails prints the type as if + /// inlined with the operands when printing an instruction. + void print(raw_ostream &O, bool IsForDebug = false, + bool NoDetails = false) const; void dump() const; - /// getContext - Return the LLVMContext in which this type was uniqued. + /// Return the LLVMContext in which this type was uniqued. LLVMContext &getContext() const { return Context; } //===--------------------------------------------------------------------===// // Accessors for working with types. // - /// getTypeID - Return the type id for the type. This will return one - /// of the TypeID enum elements defined above. - /// + /// Return the type id for the type. This will return one of the TypeID enum + /// elements defined above. TypeID getTypeID() const { return ID; } - /// isVoidTy - Return true if this is 'void'. + /// Return true if this is 'void'. bool isVoidTy() const { return getTypeID() == VoidTyID; } - /// isHalfTy - Return true if this is 'half', a 16-bit IEEE fp type. + /// Return true if this is 'half', a 16-bit IEEE fp type. bool isHalfTy() const { return getTypeID() == HalfTyID; } - /// isFloatTy - Return true if this is 'float', a 32-bit IEEE fp type. + /// Return true if this is 'float', a 32-bit IEEE fp type. bool isFloatTy() const { return getTypeID() == FloatTyID; } - /// isDoubleTy - Return true if this is 'double', a 64-bit IEEE fp type. + /// Return true if this is 'double', a 64-bit IEEE fp type. bool isDoubleTy() const { return getTypeID() == DoubleTyID; } - /// isX86_FP80Ty - Return true if this is x86 long double. + /// Return true if this is x86 long double. bool isX86_FP80Ty() const { return getTypeID() == X86_FP80TyID; } - /// isFP128Ty - Return true if this is 'fp128'. + /// Return true if this is 'fp128'. bool isFP128Ty() const { return getTypeID() == FP128TyID; } - /// isPPC_FP128Ty - Return true if this is powerpc long double. + /// Return true if this is powerpc long double. bool isPPC_FP128Ty() const { return getTypeID() == PPC_FP128TyID; } - /// isFloatingPointTy - Return true if this is one of the six floating point - /// types + /// Return true if this is one of the six floating-point types bool isFloatingPointTy() const { return getTypeID() == HalfTyID || getTypeID() == FloatTyID || getTypeID() == DoubleTyID || @@ -165,99 +174,81 @@ public: } } - /// isX86_MMXTy - Return true if this is X86 MMX. + /// Return true if this is X86 MMX. bool isX86_MMXTy() const { return getTypeID() == X86_MMXTyID; } - /// isFPOrFPVectorTy - Return true if this is a FP type or a vector of FP. - /// + /// Return true if this is a FP type or a vector of FP. bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); } - /// isLabelTy - Return true if this is 'label'. + /// Return true if this is 'label'. bool isLabelTy() const { return getTypeID() == LabelTyID; } - /// isMetadataTy - Return true if this is 'metadata'. + /// Return true if this is 'metadata'. bool isMetadataTy() const { return getTypeID() == MetadataTyID; } - /// isTokenTy - Return true if this is 'token'. + /// Return true if this is 'token'. bool isTokenTy() const { return getTypeID() == TokenTyID; } - /// isIntegerTy - True if this is an instance of IntegerType. - /// + /// True if this is an instance of IntegerType. bool isIntegerTy() const { return getTypeID() == IntegerTyID; } - /// isIntegerTy - Return true if this is an IntegerType of the given width. + /// Return true if this is an IntegerType of the given width. bool isIntegerTy(unsigned Bitwidth) const; - /// isIntOrIntVectorTy - Return true if this is an integer type or a vector of - /// integer types. - /// + /// Return true if this is an integer type or a vector of integer types. bool isIntOrIntVectorTy() const { return getScalarType()->isIntegerTy(); } - /// isFunctionTy - True if this is an instance of FunctionType. - /// + /// True if this is an instance of FunctionType. bool isFunctionTy() const { return getTypeID() == FunctionTyID; } - /// isStructTy - True if this is an instance of StructType. - /// + /// True if this is an instance of StructType. bool isStructTy() const { return getTypeID() == StructTyID; } - /// isArrayTy - True if this is an instance of ArrayType. - /// + /// True if this is an instance of ArrayType. bool isArrayTy() const { return getTypeID() == ArrayTyID; } - /// isPointerTy - True if this is an instance of PointerType. - /// + /// True if this is an instance of PointerType. bool isPointerTy() const { return getTypeID() == PointerTyID; } - /// isPtrOrPtrVectorTy - Return true if this is a pointer type or a vector of - /// pointer types. - /// + /// Return true if this is a pointer type or a vector of pointer types. bool isPtrOrPtrVectorTy() const { return getScalarType()->isPointerTy(); } - /// isVectorTy - True if this is an instance of VectorType. - /// + /// True if this is an instance of VectorType. bool isVectorTy() const { return getTypeID() == VectorTyID; } - /// canLosslesslyBitCastTo - Return true if this type could be converted - /// with a lossless BitCast to type 'Ty'. For example, i8* to i32*. BitCasts - /// are valid for types of the same size only where no re-interpretation of - /// the bits is done. + /// Return true if this type could be converted with a lossless BitCast to + /// type 'Ty'. For example, i8* to i32*. BitCasts are valid for types of the + /// same size only where no re-interpretation of the bits is done. /// @brief Determine if this type could be losslessly bitcast to Ty bool canLosslesslyBitCastTo(Type *Ty) const; - /// isEmptyTy - Return true if this type is empty, that is, it has no - /// elements or all its elements are empty. + /// Return true if this type is empty, that is, it has no elements or all of + /// its elements are empty. bool isEmptyTy() const; - /// isFirstClassType - Return true if the type is "first class", meaning it - /// is a valid type for a Value. - /// + /// Return true if the type is "first class", meaning it is a valid type for a + /// Value. bool isFirstClassType() const { return getTypeID() != FunctionTyID && getTypeID() != VoidTyID; } - /// isSingleValueType - Return true if the type is a valid type for a - /// register in codegen. This includes all first-class types except struct - /// and array types. - /// + /// Return true if the type is a valid type for a register in codegen. This + /// includes all first-class types except struct and array types. bool isSingleValueType() const { return isFloatingPointTy() || isX86_MMXTy() || isIntegerTy() || isPointerTy() || isVectorTy(); } - /// isAggregateType - Return true if the type is an aggregate type. This - /// means it is valid as the first operand of an insertvalue or - /// extractvalue instruction. This includes struct and array types, but - /// does not include vector types. - /// + /// Return true if the type is an aggregate type. This means it is valid as + /// the first operand of an insertvalue or extractvalue instruction. This + /// includes struct and array types, but does not include vector types. bool isAggregateType() const { return getTypeID() == StructTyID || getTypeID() == ArrayTyID; } - /// isSized - Return true if it makes sense to take the size of this type. To - /// get the actual size for a particular target, it is reasonable to use the + /// Return true if it makes sense to take the size of this type. To get the + /// actual size for a particular target, it is reasonable to use the /// DataLayout subsystem to do this. - /// bool isSized(SmallPtrSetImpl<Type*> *Visited = nullptr) const { // If it's a primitive, it is always sized. if (getTypeID() == IntegerTyID || isFloatingPointTy() || @@ -273,8 +264,8 @@ public: return isSizedDerivedType(Visited); } - /// getPrimitiveSizeInBits - Return the basic size of this type if it is a - /// primitive type. These are fixed by LLVM and are not target dependent. + /// Return the basic size of this type if it is a primitive type. These are + /// fixed by LLVM and are not target-dependent. /// This will return zero if the type does not have a size or is not a /// primitive type. /// @@ -285,18 +276,18 @@ public: /// unsigned getPrimitiveSizeInBits() const LLVM_READONLY; - /// getScalarSizeInBits - If this is a vector type, return the - /// getPrimitiveSizeInBits value for the element type. Otherwise return the - /// getPrimitiveSizeInBits value for this type. + /// If this is a vector type, return the getPrimitiveSizeInBits value for the + /// element type. Otherwise return the getPrimitiveSizeInBits value for this + /// type. unsigned getScalarSizeInBits() const LLVM_READONLY; - /// getFPMantissaWidth - Return the width of the mantissa of this type. This - /// is only valid on floating point types. If the FP type does not - /// have a stable mantissa (e.g. ppc long double), this method returns -1. + /// Return the width of the mantissa of this type. This is only valid on + /// floating-point types. If the FP type does not have a stable mantissa (e.g. + /// ppc long double), this method returns -1. int getFPMantissaWidth() const; - /// getScalarType - If this is a vector type, return the element type, - /// otherwise return 'this'. + /// If this is a vector type, return the element type, otherwise return + /// 'this'. Type *getScalarType() const LLVM_READONLY; //===--------------------------------------------------------------------===// @@ -317,17 +308,15 @@ public: return subtype_reverse_iterator(subtype_begin()); } - /// getContainedType - This method is used to implement the type iterator - /// (defined at the end of the file). For derived types, this returns the - /// types 'contained' in the derived type. - /// + /// This method is used to implement the type iterator (defined at the end of + /// the file). For derived types, this returns the types 'contained' in the + /// derived type. Type *getContainedType(unsigned i) const { assert(i < NumContainedTys && "Index out of range!"); return ContainedTys[i]; } - /// getNumContainedTypes - Return the number of types in the derived type. - /// + /// Return the number of types in the derived type. unsigned getNumContainedTypes() const { return NumContainedTys; } //===--------------------------------------------------------------------===// @@ -347,7 +336,10 @@ public: inline unsigned getStructNumElements() const; inline Type *getStructElementType(unsigned N) const; - inline Type *getSequentialElementType() const; + inline Type *getSequentialElementType() const { + assert(isSequentialType(getTypeID()) && "Not a sequential type!"); + return ContainedTys[0]; + } inline uint64_t getArrayNumElements() const; Type *getArrayElementType() const { return getSequentialElementType(); } @@ -357,7 +349,7 @@ public: Type *getPointerElementType() const { return getSequentialElementType(); } - /// \brief Get the address space of this pointer or pointer vector type. + /// Get the address space of this pointer or pointer vector type. inline unsigned getPointerAddressSpace() const; //===--------------------------------------------------------------------===// @@ -365,7 +357,7 @@ public: // instances of Type. // - /// getPrimitiveType - Return a type based on an identifier. + /// Return a type based on an identifier. static Type *getPrimitiveType(LLVMContext &C, TypeID IDNumber); //===--------------------------------------------------------------------===// @@ -408,14 +400,14 @@ public: static PointerType *getInt32PtrTy(LLVMContext &C, unsigned AS = 0); static PointerType *getInt64PtrTy(LLVMContext &C, unsigned AS = 0); - /// getPointerTo - Return a pointer to the current type. This is equivalent - /// to PointerType::get(Foo, AddrSpace). + /// Return a pointer to the current type. This is equivalent to + /// PointerType::get(Foo, AddrSpace). PointerType *getPointerTo(unsigned AddrSpace = 0) const; private: - /// isSizedDerivedType - Derived types like structures and arrays are sized - /// iff all of the members of the type are sized as well. Since asking for - /// their size is relatively uncommon, move this operation out of line. + /// Derived types like structures and arrays are sized iff all of the members + /// of the type are sized as well. Since asking for their size is relatively + /// uncommon, move this operation out-of-line. bool isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited = nullptr) const; }; diff --git a/include/llvm/IR/TypeFinder.h b/include/llvm/IR/TypeFinder.h index 5f3854377c16..d5baf7ab0b9e 100644 --- a/include/llvm/IR/TypeFinder.h +++ b/include/llvm/IR/TypeFinder.h @@ -15,6 +15,8 @@ #define LLVM_IR_TYPEFINDER_H #include "llvm/ADT/DenseSet.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Type.h" #include <vector> namespace llvm { @@ -22,7 +24,6 @@ namespace llvm { class MDNode; class Module; class StructType; -class Type; class Value; /// TypeFinder - Walk over a module, identifying all of the types that are diff --git a/include/llvm/IR/Use.h b/include/llvm/IR/Use.h index a738677f8e5b..e62eab56b1f1 100644 --- a/include/llvm/IR/Use.h +++ b/include/llvm/IR/Use.h @@ -27,9 +27,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/Compiler.h" #include <cstddef> -#include <iterator> namespace llvm { @@ -101,14 +99,8 @@ public: inline void set(Value *Val); - Value *operator=(Value *RHS) { - set(RHS); - return RHS; - } - const Use &operator=(const Use &RHS) { - set(RHS.Val); - return *this; - } + inline Value *operator=(Value *RHS); + inline const Use &operator=(const Use &RHS); Value *operator->() { return Val; } const Value *operator->() const { return Val; } diff --git a/include/llvm/IR/UseListOrder.h b/include/llvm/IR/UseListOrder.h index 1cabf03d1b00..b86425b6a697 100644 --- a/include/llvm/IR/UseListOrder.h +++ b/include/llvm/IR/UseListOrder.h @@ -15,8 +15,7 @@ #ifndef LLVM_IR_USELISTORDER_H #define LLVM_IR_USELISTORDER_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" +#include <cstddef> #include <vector> namespace llvm { diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index 885ae197d228..4d6b30cd1124 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -19,7 +19,6 @@ #ifndef LLVM_IR_USER_H #define LLVM_IR_USER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Value.h" @@ -28,6 +27,9 @@ namespace llvm { +template <typename T> class ArrayRef; +template <typename T> class MutableArrayRef; + /// \brief Compile-time customization of User operands. /// /// Customizes operand-related allocators and accessors. diff --git a/include/llvm/IR/Value.def b/include/llvm/IR/Value.def index 4c5d452fc3c3..48842d7f9cd5 100644 --- a/include/llvm/IR/Value.def +++ b/include/llvm/IR/Value.def @@ -54,21 +54,29 @@ HANDLE_VALUE(Argument) HANDLE_VALUE(BasicBlock) +HANDLE_VALUE(MemoryUse) +HANDLE_VALUE(MemoryDef) +HANDLE_VALUE(MemoryPhi) HANDLE_GLOBAL_VALUE(Function) HANDLE_GLOBAL_VALUE(GlobalAlias) +HANDLE_GLOBAL_VALUE(GlobalIFunc) HANDLE_GLOBAL_VALUE(GlobalVariable) -HANDLE_CONSTANT(UndefValue) HANDLE_CONSTANT(BlockAddress) HANDLE_CONSTANT(ConstantExpr) + +// ConstantAggregate. +HANDLE_CONSTANT(ConstantArray) +HANDLE_CONSTANT(ConstantStruct) +HANDLE_CONSTANT(ConstantVector) + +// ConstantData. +HANDLE_CONSTANT(UndefValue) HANDLE_CONSTANT(ConstantAggregateZero) HANDLE_CONSTANT(ConstantDataArray) HANDLE_CONSTANT(ConstantDataVector) HANDLE_CONSTANT(ConstantInt) HANDLE_CONSTANT(ConstantFP) -HANDLE_CONSTANT(ConstantArray) -HANDLE_CONSTANT(ConstantStruct) -HANDLE_CONSTANT(ConstantVector) HANDLE_CONSTANT(ConstantPointerNull) HANDLE_CONSTANT(ConstantTokenNone) @@ -81,6 +89,10 @@ HANDLE_INSTRUCTION(Instruction) HANDLE_CONSTANT_MARKER(ConstantFirstVal, Function) HANDLE_CONSTANT_MARKER(ConstantLastVal, ConstantTokenNone) +HANDLE_CONSTANT_MARKER(ConstantDataFirstVal, UndefValue) +HANDLE_CONSTANT_MARKER(ConstantDataLastVal, ConstantTokenNone) +HANDLE_CONSTANT_MARKER(ConstantAggregateFirstVal, ConstantArray) +HANDLE_CONSTANT_MARKER(ConstantAggregateLastVal, ConstantVector) #undef HANDLE_GLOBAL_VALUE #undef HANDLE_CONSTANT diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index 8918dcd38c93..f3a342dadf73 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -18,7 +18,6 @@ #include "llvm/IR/Use.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" namespace llvm { @@ -27,9 +26,13 @@ class Argument; class AssemblyAnnotationWriter; class BasicBlock; class Constant; +class ConstantData; +class ConstantAggregate; class DataLayout; class Function; class GlobalAlias; +class GlobalIFunc; +class GlobalIndirectSymbol; class GlobalObject; class GlobalValue; class GlobalVariable; @@ -106,10 +109,11 @@ protected: enum : unsigned { NumUserOperandsBits = 28 }; unsigned NumUserOperands : NumUserOperandsBits; - bool IsUsedByMD : 1; - bool HasName : 1; - bool HasHungOffUses : 1; - bool HasDescriptor : 1; + // Use the same type as the bitfield above so that MSVC will pack them. + unsigned IsUsedByMD : 1; + unsigned HasName : 1; + unsigned HasHungOffUses : 1; + unsigned HasDescriptor : 1; private: template <typename UseT> // UseT == 'Use' or 'const Use' @@ -347,13 +351,19 @@ public: assertModuleIsMaterialized(); return *materialized_user_begin(); } + iterator_range<user_iterator> materialized_users() { + return make_range(materialized_user_begin(), user_end()); + } + iterator_range<const_user_iterator> materialized_users() const { + return make_range(materialized_user_begin(), user_end()); + } iterator_range<user_iterator> users() { assertModuleIsMaterialized(); - return make_range(materialized_user_begin(), user_end()); + return materialized_users(); } iterator_range<const_user_iterator> users() const { assertModuleIsMaterialized(); - return make_range(materialized_user_begin(), user_end()); + return materialized_users(); } /// \brief Return true if there is exactly one user of this value. @@ -494,6 +504,20 @@ public: return const_cast<Value*>(this)->stripInBoundsOffsets(); } + /// \brief Returns the number of bytes known to be dereferenceable for the + /// pointer value. + /// + /// If CanBeNull is set by this function the pointer can either be null or be + /// dereferenceable up to the returned number of bytes. + unsigned getPointerDereferenceableBytes(const DataLayout &DL, + bool &CanBeNull) const; + + /// \brief Returns an alignment of the pointer value. + /// + /// Returns an alignment which is either specified explicitly, e.g. via + /// align attribute of a function argument, or guaranteed by DataLayout. + unsigned getPointerAlignment(const DataLayout &DL) const; + /// \brief Translate PHI node to its predecessor from the given basic block. /// /// If this value is a PHI node with CurBB as its parent, return the value in @@ -592,6 +616,16 @@ void Use::set(Value *V) { if (V) V->addUse(*this); } +Value *Use::operator=(Value *RHS) { + set(RHS); + return RHS; +} + +const Use &Use::operator=(const Use &RHS) { + set(RHS.Val); + return *this; +} + template <class Compare> void Value::sortUseList(Compare Cmp) { if (!UseList || !UseList->Next) // No need to sort 0 or 1 uses. @@ -669,6 +703,20 @@ template <> struct isa_impl<Constant, Value> { } }; +template <> struct isa_impl<ConstantData, Value> { + static inline bool doit(const Value &Val) { + return Val.getValueID() >= Value::ConstantDataFirstVal && + Val.getValueID() <= Value::ConstantDataLastVal; + } +}; + +template <> struct isa_impl<ConstantAggregate, Value> { + static inline bool doit(const Value &Val) { + return Val.getValueID() >= Value::ConstantAggregateFirstVal && + Val.getValueID() <= Value::ConstantAggregateLastVal; + } +}; + template <> struct isa_impl<Argument, Value> { static inline bool doit (const Value &Val) { return Val.getValueID() == Value::ArgumentVal; @@ -711,9 +759,21 @@ template <> struct isa_impl<GlobalAlias, Value> { } }; +template <> struct isa_impl<GlobalIFunc, Value> { + static inline bool doit(const Value &Val) { + return Val.getValueID() == Value::GlobalIFuncVal; + } +}; + +template <> struct isa_impl<GlobalIndirectSymbol, Value> { + static inline bool doit(const Value &Val) { + return isa<GlobalAlias>(Val) || isa<GlobalIFunc>(Val); + } +}; + template <> struct isa_impl<GlobalValue, Value> { static inline bool doit(const Value &Val) { - return isa<GlobalObject>(Val) || isa<GlobalAlias>(Val); + return isa<GlobalObject>(Val) || isa<GlobalIndirectSymbol>(Val); } }; @@ -738,8 +798,7 @@ public: // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_ISA_CONVERSION_FUNCTIONS(Value, LLVMValueRef) -/* Specialized opaque value conversions. - */ +// Specialized opaque value conversions. inline Value **unwrap(LLVMValueRef *Vals) { return reinterpret_cast<Value**>(Vals); } diff --git a/include/llvm/IR/ValueMap.h b/include/llvm/IR/ValueMap.h index ad518ac053b2..85379ad468c4 100644 --- a/include/llvm/IR/ValueMap.h +++ b/include/llvm/IR/ValueMap.h @@ -27,6 +27,7 @@ #define LLVM_IR_VALUEMAP_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Mutex.h" @@ -84,8 +85,11 @@ class ValueMap { typedef DenseMap<const Metadata *, TrackingMDRef> MDMapT; typedef typename Config::ExtraData ExtraData; MapT Map; - std::unique_ptr<MDMapT> MDMap; + Optional<MDMapT> MDMap; ExtraData Data; + + bool MayMapMetadata = true; + ValueMap(const ValueMap&) = delete; ValueMap& operator=(const ValueMap&) = delete; public: @@ -99,12 +103,27 @@ public: explicit ValueMap(const ExtraData &Data, unsigned NumInitBuckets = 64) : Map(NumInitBuckets), Data(Data) {} - bool hasMD() const { return MDMap; } + bool hasMD() const { return bool(MDMap); } MDMapT &MD() { if (!MDMap) - MDMap.reset(new MDMapT); + MDMap.emplace(); return *MDMap; } + Optional<MDMapT> &getMDMap() { return MDMap; } + + bool mayMapMetadata() const { return MayMapMetadata; } + void enableMapMetadata() { MayMapMetadata = true; } + void disableMapMetadata() { MayMapMetadata = false; } + + /// Get the mapped metadata, if it's in the map. + Optional<Metadata *> getMappedMD(const Metadata *MD) const { + if (!MDMap) + return None; + auto Where = MDMap->find(MD); + if (Where == MDMap->end()) + return None; + return Where->second.get(); + } typedef ValueMapIterator<MapT, KeyT> iterator; typedef ValueMapConstIterator<MapT, KeyT> const_iterator; diff --git a/include/llvm/IR/ValueSymbolTable.h b/include/llvm/IR/ValueSymbolTable.h index 65bd7fc2fec1..61a12db403ea 100644 --- a/include/llvm/IR/ValueSymbolTable.h +++ b/include/llvm/IR/ValueSymbolTable.h @@ -14,13 +14,13 @@ #ifndef LLVM_IR_VALUESYMBOLTABLE_H #define LLVM_IR_VALUESYMBOLTABLE_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/Value.h" #include "llvm/Support/DataTypes.h" namespace llvm { template <typename ValueSubClass> class SymbolTableListTraits; + template <unsigned InternalLen> class SmallString; class BasicBlock; class Function; class NamedMDNode; @@ -39,6 +39,7 @@ class ValueSymbolTable { friend class SymbolTableListTraits<Function>; friend class SymbolTableListTraits<GlobalVariable>; friend class SymbolTableListTraits<GlobalAlias>; + friend class SymbolTableListTraits<GlobalIFunc>; /// @name Types /// @{ public: diff --git a/include/llvm/IR/Verifier.h b/include/llvm/IR/Verifier.h index 89039d24195e..fdb6ce400a8d 100644 --- a/include/llvm/IR/Verifier.h +++ b/include/llvm/IR/Verifier.h @@ -21,8 +21,7 @@ #ifndef LLVM_IR_VERIFIER_H #define LLVM_IR_VERIFIER_H -#include "llvm/ADT/StringRef.h" -#include <string> +#include "llvm/IR/PassManager.h" namespace llvm { @@ -30,7 +29,6 @@ class Function; class FunctionPass; class ModulePass; class Module; -class PreservedAnalyses; class raw_ostream; /// \brief Check a function for errors, useful for use when debugging a @@ -43,10 +41,38 @@ bool verifyFunction(const Function &F, raw_ostream *OS = nullptr); /// \brief Check a module for errors. /// -/// If there are no errors, the function returns false. If an error is found, -/// a message describing the error is written to OS (if non-null) and true is -/// returned. -bool verifyModule(const Module &M, raw_ostream *OS = nullptr); +/// If there are no errors, the function returns false. If an error is +/// found, a message describing the error is written to OS (if +/// non-null) and true is returned. +/// +/// \return true if the module is broken. If BrokenDebugInfo is +/// supplied, DebugInfo verification failures won't be considered as +/// error and instead *BrokenDebugInfo will be set to true. Debug +/// info errors can be "recovered" from by stripping the debug info. +bool verifyModule(const Module &M, raw_ostream *OS = nullptr, + bool *BrokenDebugInfo = nullptr); + +FunctionPass *createVerifierPass(bool FatalErrors = true); + +/// Check a module for errors, and report separate error states for IR +/// and debug info errors. +class VerifierAnalysis : public AnalysisInfoMixin<VerifierAnalysis> { + friend AnalysisInfoMixin<VerifierAnalysis>; + static char PassID; + +public: + struct Result { + bool IRBroken, DebugInfoBroken; + }; + static void *ID() { return (void *)&PassID; } + Result run(Module &M, ModuleAnalysisManager &); + Result run(Function &F, FunctionAnalysisManager &); +}; + +/// Check a module for errors, but report debug info errors separately. +/// Otherwise behaves as the normal verifyModule. Debug info errors can be +/// "recovered" from by stripping the debug info. +bool verifyModule(bool &BrokenDebugInfo, const Module &M, raw_ostream *OS); /// \brief Create a verifier pass. /// @@ -58,20 +84,17 @@ bool verifyModule(const Module &M, raw_ostream *OS = nullptr); /// /// Note that this creates a pass suitable for the legacy pass manager. It has /// nothing to do with \c VerifierPass. -FunctionPass *createVerifierPass(bool FatalErrors = true); - -class VerifierPass { +class VerifierPass : public PassInfoMixin<VerifierPass> { bool FatalErrors; public: explicit VerifierPass(bool FatalErrors = true) : FatalErrors(FatalErrors) {} - PreservedAnalyses run(Module &M); - PreservedAnalyses run(Function &F); - - static StringRef name() { return "VerifierPass"; } + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; + } // End llvm namespace #endif diff --git a/include/llvm/IRReader/IRReader.h b/include/llvm/IRReader/IRReader.h index 523cd3d6df72..7b24ec11fb64 100644 --- a/include/llvm/IRReader/IRReader.h +++ b/include/llvm/IRReader/IRReader.h @@ -15,11 +15,12 @@ #ifndef LLVM_IRREADER_IRREADER_H #define LLVM_IRREADER_IRREADER_H -#include "llvm/Support/MemoryBuffer.h" -#include <string> +#include <memory> namespace llvm { +class StringRef; +class MemoryBufferRef; class Module; class SMDiagnostic; class LLVMContext; diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index 90fbc1d891b7..90ff82fe86d4 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -19,250 +19,298 @@ namespace llvm { class PassRegistry; -/// initializeCore - Initialize all passes linked into the -/// TransformUtils library. +/// Initialize all passes linked into the TransformUtils library. void initializeCore(PassRegistry&); -/// initializeTransformUtils - Initialize all passes linked into the -/// TransformUtils library. +/// Initialize all passes linked into the TransformUtils library. void initializeTransformUtils(PassRegistry&); -/// initializeScalarOpts - Initialize all passes linked into the -/// ScalarOpts library. +/// Initialize all passes linked into the ScalarOpts library. void initializeScalarOpts(PassRegistry&); -/// initializeObjCARCOpts - Initialize all passes linked into the ObjCARCOpts -/// library. +/// Initialize all passes linked into the ObjCARCOpts library. void initializeObjCARCOpts(PassRegistry&); -/// initializeVectorization - Initialize all passes linked into the -/// Vectorize library. +/// Initialize all passes linked into the Vectorize library. void initializeVectorization(PassRegistry&); -/// initializeInstCombine - Initialize all passes linked into the -/// InstCombine library. +/// Initialize all passes linked into the InstCombine library. void initializeInstCombine(PassRegistry&); -/// initializeIPO - Initialize all passes linked into the IPO library. +/// Initialize all passes linked into the IPO library. void initializeIPO(PassRegistry&); -/// initializeInstrumentation - Initialize all passes linked into the -/// Instrumentation library. +/// Initialize all passes linked into the Instrumentation library. void initializeInstrumentation(PassRegistry&); -/// initializeAnalysis - Initialize all passes linked into the Analysis library. +/// Initialize all passes linked into the Analysis library. void initializeAnalysis(PassRegistry&); -/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +/// Initialize all passes linked into the CodeGen library. void initializeCodeGen(PassRegistry&); -/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +/// Initialize all passes linked into the GlobalISel library. +void initializeGlobalISel(PassRegistry &Registry); + +/// Initialize all passes linked into the CodeGen library. void initializeTarget(PassRegistry&); -void initializeAAEvalPass(PassRegistry&); -void initializeAddDiscriminatorsPass(PassRegistry&); +void initializeAAEvalLegacyPassPass(PassRegistry&); +void initializeAAResultsWrapperPassPass(PassRegistry &); void initializeADCELegacyPassPass(PassRegistry&); -void initializeBDCEPass(PassRegistry&); +void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&); +void initializeAddressSanitizerModulePass(PassRegistry&); +void initializeAddressSanitizerPass(PassRegistry&); void initializeAliasSetPrinterPass(PassRegistry&); +void initializeAlignmentFromAssumptionsPass(PassRegistry&); void initializeAlwaysInlinerPass(PassRegistry&); void initializeArgPromotionPass(PassRegistry&); +void initializeAssumptionCacheTrackerPass(PassRegistry &); void initializeAtomicExpandPass(PassRegistry&); -void initializeSampleProfileLoaderPass(PassRegistry&); -void initializeAlignmentFromAssumptionsPass(PassRegistry&); +void initializeBBVectorizePass(PassRegistry&); +void initializeBDCELegacyPassPass(PassRegistry &); void initializeBarrierNoopPass(PassRegistry&); void initializeBasicAAWrapperPassPass(PassRegistry&); -void initializeCallGraphWrapperPassPass(PassRegistry &); void initializeBlockExtractorPassPass(PassRegistry&); void initializeBlockFrequencyInfoWrapperPassPass(PassRegistry&); void initializeBoundsCheckingPass(PassRegistry&); void initializeBranchFolderPassPass(PassRegistry&); void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); -void initializeCallGraphPrinterPass(PassRegistry&); -void initializeCallGraphViewerPass(PassRegistry&); void initializeCFGOnlyPrinterPass(PassRegistry&); void initializeCFGOnlyViewerPass(PassRegistry&); void initializeCFGPrinterPass(PassRegistry&); void initializeCFGSimplifyPassPass(PassRegistry&); -void initializeCFLAAWrapperPassPass(PassRegistry&); -void initializeExternalAAWrapperPassPass(PassRegistry&); -void initializeForwardControlFlowIntegrityPass(PassRegistry&); -void initializeFlattenCFGPassPass(PassRegistry&); -void initializeStructurizeCFGPass(PassRegistry&); void initializeCFGViewerPass(PassRegistry&); -void initializeConstantHoistingPass(PassRegistry&); +void initializeCFLAndersAAWrapperPassPass(PassRegistry&); +void initializeCFLSteensAAWrapperPassPass(PassRegistry&); +void initializeCallGraphDOTPrinterPass(PassRegistry&); +void initializeCallGraphPrinterLegacyPassPass(PassRegistry&); +void initializeCallGraphViewerPass(PassRegistry&); +void initializeCallGraphWrapperPassPass(PassRegistry &); void initializeCodeGenPreparePass(PassRegistry&); -void initializeConstantMergePass(PassRegistry&); +void initializeConstantHoistingLegacyPassPass(PassRegistry&); +void initializeConstantMergeLegacyPassPass(PassRegistry &); void initializeConstantPropagationPass(PassRegistry&); -void initializeMachineCopyPropagationPass(PassRegistry&); -void initializeCostModelAnalysisPass(PassRegistry&); void initializeCorrelatedValuePropagationPass(PassRegistry&); +void initializeCostModelAnalysisPass(PassRegistry&); void initializeCrossDSOCFIPass(PassRegistry&); void initializeDAEPass(PassRegistry&); void initializeDAHPass(PassRegistry&); -void initializeDCEPass(PassRegistry&); -void initializeDSEPass(PassRegistry&); +void initializeDCELegacyPassPass(PassRegistry&); +void initializeDSELegacyPassPass(PassRegistry&); +void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); void initializeDelinearizationPass(PassRegistry &); +void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); +void initializeDependenceAnalysisWrapperPassPass(PassRegistry&); +void initializeDetectDeadLanesPass(PassRegistry&); void initializeDivergenceAnalysisPass(PassRegistry&); void initializeDomOnlyPrinterPass(PassRegistry&); void initializeDomOnlyViewerPass(PassRegistry&); void initializeDomPrinterPass(PassRegistry&); void initializeDomViewerPass(PassRegistry&); -void initializeDominanceFrontierPass(PassRegistry&); +void initializeDominanceFrontierWrapperPassPass(PassRegistry&); void initializeDominatorTreeWrapperPassPass(PassRegistry&); +void initializeDwarfEHPreparePass(PassRegistry&); +void initializeEarlyCSELegacyPassPass(PassRegistry &); void initializeEarlyIfConverterPass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); -void initializeExpandPostRAPass(PassRegistry&); -void initializeAAResultsWrapperPassPass(PassRegistry &); -void initializeGCOVProfilerPass(PassRegistry&); -void initializePGOInstrumentationGenPass(PassRegistry&); -void initializePGOInstrumentationUsePass(PassRegistry&); -void initializeInstrProfilingPass(PassRegistry&); -void initializeAddressSanitizerPass(PassRegistry&); -void initializeAddressSanitizerModulePass(PassRegistry&); -void initializeMemorySanitizerPass(PassRegistry&); -void initializeThreadSanitizerPass(PassRegistry&); -void initializeSanitizerCoverageModulePass(PassRegistry&); -void initializeDataFlowSanitizerPass(PassRegistry&); -void initializeScalarizerPass(PassRegistry&); -void initializeEarlyCSELegacyPassPass(PassRegistry &); -void initializeEliminateAvailableExternallyPass(PassRegistry&); +void initializeEfficiencySanitizerPass(PassRegistry&); +void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry &); +void initializeGVNHoistLegacyPassPass(PassRegistry &); void initializeExpandISelPseudosPass(PassRegistry&); +void initializeExpandPostRAPass(PassRegistry&); +void initializeExternalAAWrapperPassPass(PassRegistry&); +void initializeFinalizeMachineBundlesPass(PassRegistry&); +void initializeFlattenCFGPassPass(PassRegistry&); +void initializeFloat2IntLegacyPassPass(PassRegistry&); void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&); +void initializeForwardControlFlowIntegrityPass(PassRegistry&); +void initializeFuncletLayoutPass(PassRegistry &); +void initializeFunctionImportPassPass(PassRegistry &); void initializeGCMachineCodeAnalysisPass(PassRegistry&); void initializeGCModuleInfoPass(PassRegistry&); -void initializeGVNPass(PassRegistry&); -void initializeGlobalDCEPass(PassRegistry&); -void initializeGlobalOptPass(PassRegistry&); +void initializeGCOVProfilerLegacyPassPass(PassRegistry&); +void initializeGVNLegacyPassPass(PassRegistry&); +void initializeGlobalDCELegacyPassPass(PassRegistry&); +void initializeGlobalMergePass(PassRegistry&); +void initializeGlobalOptLegacyPassPass(PassRegistry&); void initializeGlobalsAAWrapperPassPass(PassRegistry&); +void initializeGuardWideningLegacyPassPass(PassRegistry&); void initializeIPCPPass(PassRegistry&); -void initializeIPSCCPPass(PassRegistry&); -void initializeIVUsersPass(PassRegistry&); +void initializeIPSCCPLegacyPassPass(PassRegistry &); +void initializeIRTranslatorPass(PassRegistry &); +void initializeIVUsersWrapperPassPass(PassRegistry&); void initializeIfConverterPass(PassRegistry&); +void initializeImplicitNullChecksPass(PassRegistry&); +void initializeIndVarSimplifyLegacyPassPass(PassRegistry&); void initializeInductiveRangeCheckEliminationPass(PassRegistry&); -void initializeIndVarSimplifyPass(PassRegistry&); void initializeInferFunctionAttrsLegacyPassPass(PassRegistry&); void initializeInlineCostAnalysisPass(PassRegistry&); -void initializeInstructionCombiningPassPass(PassRegistry&); void initializeInstCountPass(PassRegistry&); void initializeInstNamerPass(PassRegistry&); -void initializeInternalizePassPass(PassRegistry&); +void initializeInstSimplifierPass(PassRegistry&); +void initializeInstrProfilingLegacyPassPass(PassRegistry &); +void initializeInstructionCombiningPassPass(PassRegistry&); +void initializeInterleavedAccessPass(PassRegistry &); +void initializeInternalizeLegacyPassPass(PassRegistry&); void initializeIntervalPartitionPass(PassRegistry&); void initializeJumpThreadingPass(PassRegistry&); -void initializeLCSSAPass(PassRegistry&); -void initializeLICMPass(PassRegistry&); -void initializeLazyValueInfoPass(PassRegistry&); +void initializeLCSSAWrapperPassPass(PassRegistry &); +void initializeLegacyLICMPassPass(PassRegistry&); +void initializeLazyBlockFrequencyInfoPassPass(PassRegistry&); +void initializeLazyValueInfoWrapperPassPass(PassRegistry&); void initializeLintPass(PassRegistry&); +void initializeLiveDebugValuesPass(PassRegistry&); void initializeLiveDebugVariablesPass(PassRegistry&); void initializeLiveIntervalsPass(PassRegistry&); void initializeLiveRegMatrixPass(PassRegistry&); void initializeLiveStacksPass(PassRegistry&); void initializeLiveVariablesPass(PassRegistry&); +void initializeLoadCombinePass(PassRegistry&); void initializeLoaderPassPass(PassRegistry&); +void initializeLoadStoreVectorizerPass(PassRegistry&); void initializeLocalStackSlotPassPass(PassRegistry&); -void initializeLoopDeletionPass(PassRegistry&); +void initializeLoopAccessLegacyAnalysisPass(PassRegistry&); +void initializeLoopDataPrefetchPass(PassRegistry&); +void initializeLoopDeletionLegacyPassPass(PassRegistry&); +void initializeLoopDistributeLegacyPass(PassRegistry&); void initializeLoopExtractorPass(PassRegistry&); +void initializeLoopIdiomRecognizeLegacyPassPass(PassRegistry&); void initializeLoopInfoWrapperPassPass(PassRegistry&); +void initializeLoopInstSimplifyLegacyPassPass(PassRegistry&); void initializeLoopInterchangePass(PassRegistry &); -void initializeLoopInstSimplifyPass(PassRegistry&); -void initializeLoopRotatePass(PassRegistry&); +void initializeLoopLoadEliminationPass(PassRegistry&); +void initializeLoopPassPass(PassRegistry&); +void initializeLoopRerollPass(PassRegistry&); +void initializeLoopRotateLegacyPassPass(PassRegistry&); +void initializeLoopSimplifyCFGLegacyPassPass(PassRegistry&); void initializeLoopSimplifyPass(PassRegistry&); void initializeLoopStrengthReducePass(PassRegistry&); -void initializeGlobalMergePass(PassRegistry&); -void initializeLoopRerollPass(PassRegistry&); void initializeLoopUnrollPass(PassRegistry&); void initializeLoopUnswitchPass(PassRegistry&); -void initializeLoopIdiomRecognizePass(PassRegistry&); -void initializeLowerAtomicPass(PassRegistry&); -void initializeLowerBitSetsPass(PassRegistry&); +void initializeLoopVectorizePass(PassRegistry&); +void initializeLoopVersioningLICMPass(PassRegistry&); +void initializeLoopVersioningPassPass(PassRegistry &); +void initializeLowerAtomicLegacyPassPass(PassRegistry &); +void initializeLowerEmuTLSPass(PassRegistry&); void initializeLowerExpectIntrinsicPass(PassRegistry&); +void initializeLowerGuardIntrinsicPass(PassRegistry&); void initializeLowerIntrinsicsPass(PassRegistry&); void initializeLowerInvokePass(PassRegistry&); void initializeLowerSwitchPass(PassRegistry&); +void initializeLowerTypeTestsPass(PassRegistry&); +void initializeMIRPrintingPassPass(PassRegistry&); void initializeMachineBlockFrequencyInfoPass(PassRegistry&); void initializeMachineBlockPlacementPass(PassRegistry&); void initializeMachineBlockPlacementStatsPass(PassRegistry&); void initializeMachineBranchProbabilityInfoPass(PassRegistry&); void initializeMachineCSEPass(PassRegistry&); -void initializeImplicitNullChecksPass(PassRegistry&); -void initializeMachineDominatorTreePass(PassRegistry&); +void initializeMachineCombinerPass(PassRegistry &); +void initializeMachineCopyPropagationPass(PassRegistry&); void initializeMachineDominanceFrontierPass(PassRegistry&); -void initializeMachinePostDominatorTreePass(PassRegistry&); +void initializeMachineDominatorTreePass(PassRegistry&); +void initializeMachineFunctionPrinterPassPass(PassRegistry&); void initializeMachineLICMPass(PassRegistry&); void initializeMachineLoopInfoPass(PassRegistry&); void initializeMachineModuleInfoPass(PassRegistry&); +void initializeMachinePostDominatorTreePass(PassRegistry&); void initializeMachineRegionInfoPassPass(PassRegistry&); void initializeMachineSchedulerPass(PassRegistry&); void initializeMachineSinkingPass(PassRegistry&); void initializeMachineTraceMetricsPass(PassRegistry&); void initializeMachineVerifierPassPass(PassRegistry&); -void initializeMemCpyOptPass(PassRegistry&); +void initializeMemCpyOptLegacyPassPass(PassRegistry&); void initializeMemDepPrinterPass(PassRegistry&); void initializeMemDerefPrinterPass(PassRegistry&); -void initializeMemoryDependenceAnalysisPass(PassRegistry&); -void initializeMergedLoadStoreMotionPass(PassRegistry &); -void initializeMetaRenamerPass(PassRegistry&); +void initializeMemoryDependenceWrapperPassPass(PassRegistry&); +void initializeMemorySSAWrapperPassPass(PassRegistry&); +void initializeMemorySSAPrinterLegacyPassPass(PassRegistry &); +void initializeMemorySanitizerPass(PassRegistry&); void initializeMergeFunctionsPass(PassRegistry&); +void initializeMergedLoadStoreMotionLegacyPassPass(PassRegistry &); +void initializeMetaRenamerPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&); +void initializeModuleSummaryIndexWrapperPassPass(PassRegistry &); +void initializeNameAnonFunctionPass(PassRegistry &); void initializeNaryReassociatePass(PassRegistry&); void initializeNoAAPass(PassRegistry&); void initializeObjCARCAAWrapperPassPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&); -void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCContractPass(PassRegistry&); +void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCOptPass(PassRegistry&); -void initializePAEvalPass(PassRegistry &); +void initializeOptimizationRemarkEmitterWrapperPassPass(PassRegistry&); void initializeOptimizePHIsPass(PassRegistry&); -void initializePartiallyInlineLibCallsPass(PassRegistry&); +void initializePAEvalPass(PassRegistry &); void initializePEIPass(PassRegistry&); +void initializePGOIndirectCallPromotionLegacyPassPass(PassRegistry&); +void initializePGOInstrumentationGenLegacyPassPass(PassRegistry&); +void initializePGOInstrumentationUseLegacyPassPass(PassRegistry&); void initializePHIEliminationPass(PassRegistry&); -void initializePartialInlinerPass(PassRegistry&); +void initializePhysicalRegisterUsageInfoPass(PassRegistry &); +void initializePartialInlinerLegacyPassPass(PassRegistry &); +void initializePartiallyInlineLibCallsLegacyPassPass(PassRegistry &); +void initializePatchableFunctionPass(PassRegistry &); void initializePeepholeOptimizerPass(PassRegistry&); +void initializePlaceBackedgeSafepointsImplPass(PassRegistry&); +void initializePlaceSafepointsPass(PassRegistry&); void initializePostDomOnlyPrinterPass(PassRegistry&); void initializePostDomOnlyViewerPass(PassRegistry&); void initializePostDomPrinterPass(PassRegistry&); void initializePostDomViewerPass(PassRegistry&); -void initializePostDominatorTreePass(PassRegistry&); -void initializePostOrderFunctionAttrsPass(PassRegistry&); -void initializePostRASchedulerPass(PassRegistry&); +void initializePostDominatorTreeWrapperPassPass(PassRegistry&); void initializePostMachineSchedulerPass(PassRegistry&); +void initializePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); +void initializePostRAHazardRecognizerPass(PassRegistry&); +void initializePostRASchedulerPass(PassRegistry&); +void initializePreISelIntrinsicLoweringLegacyPassPass(PassRegistry&); +void initializePrintBasicBlockPassPass(PassRegistry&); void initializePrintFunctionPassWrapperPass(PassRegistry&); void initializePrintModulePassWrapperPass(PassRegistry&); -void initializePrintBasicBlockPassPass(PassRegistry&); void initializeProcessImplicitDefsPass(PassRegistry&); -void initializePromotePassPass(PassRegistry&); +void initializeProfileSummaryInfoWrapperPassPass(PassRegistry &); +void initializePromoteLegacyPassPass(PassRegistry &); void initializePruneEHPass(PassRegistry&); -void initializeReassociatePass(PassRegistry&); +void initializeReassociateLegacyPassPass(PassRegistry&); +void initializeRegBankSelectPass(PassRegistry &); void initializeRegToMemPass(PassRegistry&); void initializeRegionInfoPassPass(PassRegistry&); void initializeRegionOnlyPrinterPass(PassRegistry&); void initializeRegionOnlyViewerPass(PassRegistry&); void initializeRegionPrinterPass(PassRegistry&); void initializeRegionViewerPass(PassRegistry&); -void initializeReversePostOrderFunctionAttrsPass(PassRegistry&); +void initializeRegisterCoalescerPass(PassRegistry&); +void initializeRenameIndependentSubregsPass(PassRegistry&); +void initializeReversePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); void initializeRewriteStatepointsForGCPass(PassRegistry&); -void initializeSafeStackPass(PassRegistry&); -void initializeSCCPPass(PassRegistry&); -void initializeSROALegacyPassPass(PassRegistry&); -void initializeSROA_DTPass(PassRegistry&); -void initializeSROA_SSAUpPass(PassRegistry&); +void initializeRewriteSymbolsPass(PassRegistry&); +void initializeSCCPLegacyPassPass(PassRegistry &); void initializeSCEVAAWrapperPassPass(PassRegistry&); +void initializeSLPVectorizerPass(PassRegistry&); +void initializeSROALegacyPassPass(PassRegistry&); +void initializeSafeStackPass(PassRegistry&); +void initializeSampleProfileLoaderLegacyPassPass(PassRegistry&); +void initializeSanitizerCoverageModulePass(PassRegistry&); void initializeScalarEvolutionWrapperPassPass(PassRegistry&); +void initializeScalarizerPass(PassRegistry&); +void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); +void initializeSeparateConstOffsetFromGEPPass(PassRegistry &); +void initializeShadowStackGCLoweringPass(PassRegistry&); void initializeShrinkWrapPass(PassRegistry &); void initializeSimpleInlinerPass(PassRegistry&); -void initializeShadowStackGCLoweringPass(PassRegistry&); -void initializeRegisterCoalescerPass(PassRegistry&); void initializeSingleLoopExtractorPass(PassRegistry&); -void initializeSinkingPass(PassRegistry&); -void initializeSeparateConstOffsetFromGEPPass(PassRegistry &); +void initializeSinkingLegacyPassPass(PassRegistry&); +void initializeSjLjEHPreparePass(PassRegistry&); void initializeSlotIndexesPass(PassRegistry&); -void initializeSpillPlacementPass(PassRegistry&); void initializeSpeculativeExecutionPass(PassRegistry&); -void initializeStackProtectorPass(PassRegistry&); +void initializeSpillPlacementPass(PassRegistry&); void initializeStackColoringPass(PassRegistry&); +void initializeStackMapLivenessPass(PassRegistry&); +void initializeStackProtectorPass(PassRegistry&); void initializeStackSlotColoringPass(PassRegistry&); void initializeStraightLineStrengthReducePass(PassRegistry &); void initializeStripDeadDebugInfoPass(PassRegistry&); @@ -270,46 +318,26 @@ void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripSymbolsPass(PassRegistry&); +void initializeStructurizeCFGPass(PassRegistry&); void initializeTailCallElimPass(PassRegistry&); void initializeTailDuplicatePassPass(PassRegistry&); +void initializeTargetLibraryInfoWrapperPassPass(PassRegistry &); void initializeTargetPassConfigPass(PassRegistry&); void initializeTargetTransformInfoWrapperPassPass(PassRegistry &); -void initializeTargetLibraryInfoWrapperPassPass(PassRegistry &); -void initializeAssumptionCacheTrackerPass(PassRegistry &); +void initializeThreadSanitizerPass(PassRegistry&); void initializeTwoAddressInstructionPassPass(PassRegistry&); void initializeTypeBasedAAWrapperPassPass(PassRegistry&); -void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); void initializeUnifyFunctionExitNodesPass(PassRegistry&); -void initializeUnreachableBlockElimPass(PassRegistry&); +void initializeUnpackMachineBundlesPass(PassRegistry&); +void initializeUnreachableBlockElimLegacyPassPass(PassRegistry&); void initializeUnreachableMachineBlockElimPass(PassRegistry&); void initializeVerifierLegacyPassPass(PassRegistry&); void initializeVirtRegMapPass(PassRegistry&); void initializeVirtRegRewriterPass(PassRegistry&); -void initializeInstSimplifierPass(PassRegistry&); -void initializeUnpackMachineBundlesPass(PassRegistry&); -void initializeFinalizeMachineBundlesPass(PassRegistry&); -void initializeLoopAccessAnalysisPass(PassRegistry&); -void initializeLoopVectorizePass(PassRegistry&); -void initializeSLPVectorizerPass(PassRegistry&); -void initializeBBVectorizePass(PassRegistry&); -void initializeMachineFunctionPrinterPassPass(PassRegistry&); -void initializeMIRPrintingPassPass(PassRegistry&); -void initializeStackMapLivenessPass(PassRegistry&); -void initializeLiveDebugValuesPass(PassRegistry&); -void initializeMachineCombinerPass(PassRegistry &); -void initializeLoadCombinePass(PassRegistry&); -void initializeRewriteSymbolsPass(PassRegistry&); +void initializeWholeProgramDevirtPass(PassRegistry &); void initializeWinEHPreparePass(PassRegistry&); -void initializePlaceBackedgeSafepointsImplPass(PassRegistry&); -void initializePlaceSafepointsPass(PassRegistry&); -void initializeDwarfEHPreparePass(PassRegistry&); -void initializeFloat2IntPass(PassRegistry&); -void initializeLoopDistributePass(PassRegistry&); -void initializeSjLjEHPreparePass(PassRegistry&); -void initializeDemandedBitsPass(PassRegistry&); -void initializeFuncletLayoutPass(PassRegistry &); -void initializeLoopLoadEliminationPass(PassRegistry&); -void initializeFunctionImportPassPass(PassRegistry &); +void initializeWriteBitcodePassPass(PassRegistry &); +void initializeXRayInstrumentationPass(PassRegistry &); } #endif diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h new file mode 100644 index 000000000000..5154c0007aaa --- /dev/null +++ b/include/llvm/LTO/LTO.h @@ -0,0 +1,74 @@ +//===-LTO.h - LLVM Link Time Optimizer ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares functions and classes used to support LTO. It is intended +// to be used both by LTO classes as well as by clients (gold-plugin) that +// don't utilize the LTO code generator interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LTO_LTO_H +#define LLVM_LTO_LTO_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/ModuleSummaryIndex.h" + +namespace llvm { + +class LLVMContext; +class MemoryBufferRef; +class Module; + +/// Helper to load a module from bitcode. +std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer, + LLVMContext &Context, bool Lazy); + +/// Provide a "loader" for the FunctionImporter to access function from other +/// modules. +class ModuleLoader { + /// The context that will be used for importing. + LLVMContext &Context; + + /// Map from Module identifier to MemoryBuffer. Used by clients like the + /// FunctionImported to request loading a Module. + StringMap<MemoryBufferRef> &ModuleMap; + +public: + ModuleLoader(LLVMContext &Context, StringMap<MemoryBufferRef> &ModuleMap) + : Context(Context), ModuleMap(ModuleMap) {} + + /// Load a module on demand. + std::unique_ptr<Module> operator()(StringRef Identifier) { + return loadModuleFromBuffer(ModuleMap[Identifier], Context, /*Lazy*/ true); + } +}; + + +/// Resolve Weak and LinkOnce values in the \p Index. Linkage changes recorded +/// in the index and the ThinLTO backends must apply the changes to the Module +/// via thinLTOResolveWeakForLinkerModule. +/// +/// This is done for correctness (if value exported, ensure we always +/// emit a copy), and compile-time optimization (allow drop of duplicates). +void thinLTOResolveWeakForLinkerInIndex( + ModuleSummaryIndex &Index, + function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)> + isPrevailing, + function_ref<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)> + recordNewLinkage); + +/// Update the linkages in the given \p Index to mark exported values +/// as external and non-exported values as internal. The ThinLTO backends +/// must apply the changes to the Module via thinLTOInternalizeModule. +void thinLTOInternalizeAndPromoteInIndex( + ModuleSummaryIndex &Index, + function_ref<bool(StringRef, GlobalValue::GUID)> isExported); +} + +#endif diff --git a/include/llvm/LTO/LTOCodeGenerator.h b/include/llvm/LTO/legacy/LTOCodeGenerator.h index 3820b211a381..d083e37d75b8 100644 --- a/include/llvm/LTO/LTOCodeGenerator.h +++ b/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -36,18 +36,20 @@ #define LLVM_LTO_LTOCODEGENERATOR_H #include "llvm-c/lto.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Module.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include <string> #include <vector> namespace llvm { +template <typename T> class ArrayRef; class LLVMContext; class DiagnosticInfo; - class GlobalValue; class Linker; class Mangler; class MemoryBuffer; @@ -66,17 +68,21 @@ struct LTOCodeGenerator { ~LTOCodeGenerator(); /// Merge given module. Return true on success. + /// + /// Resets \a HasVerifiedInput. bool addModule(struct LTOModule *); /// Set the destination module. + /// + /// Resets \a HasVerifiedInput. void setModule(std::unique_ptr<LTOModule> M); - void setTargetOptions(TargetOptions Options); + void setTargetOptions(const TargetOptions &Options); void setDebugInfo(lto_debug_model); - void setCodePICModel(Reloc::Model Model) { RelocModel = Model; } - + void setCodePICModel(Optional<Reloc::Model> Model) { RelocModel = Model; } + /// Set the file type to be emitted (assembly or object code). - /// The default is TargetMachine::CGFT_ObjectFile. + /// The default is TargetMachine::CGFT_ObjectFile. void setFileType(TargetMachine::CodeGenFileType FT) { FileType = FT; } void setCpu(const char *MCpu) { this->MCpu = MCpu; } @@ -86,6 +92,22 @@ struct LTOCodeGenerator { void setShouldInternalize(bool Value) { ShouldInternalize = Value; } void setShouldEmbedUselists(bool Value) { ShouldEmbedUselists = Value; } + /// Restore linkage of globals + /// + /// When set, the linkage of globals will be restored prior to code + /// generation. That is, a global symbol that had external linkage prior to + /// LTO will be emitted with external linkage again; and a local will remain + /// local. Note that this option only affects the end result - globals may + /// still be internalized in the process of LTO and may be modified and/or + /// deleted where legal. + /// + /// The default behavior will internalize globals (unless on the preserve + /// list) and, if parallel code generation is enabled, will externalize + /// all locals. + void setShouldRestoreGlobalsLinkage(bool Value) { + ShouldRestoreGlobalsLinkage = Value; + } + void addMustPreserveSymbol(StringRef Sym) { MustPreserveSymbols[Sym] = 1; } /// Pass options to the driver and optimization passes. @@ -105,6 +127,8 @@ struct LTOCodeGenerator { /// Write the merged module to the file specified by the given path. Return /// true on success. + /// + /// Calls \a verifyMergedModuleOnce(). bool writeMergedModules(const char *Path); /// Compile the merged module into a *single* output file; the path to output @@ -129,6 +153,8 @@ struct LTOCodeGenerator { bool DisableVectorization); /// Optimizes the merged module. Returns true on success. + /// + /// Calls \a verifyMergedModuleOnce(). bool optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, bool DisableVectorization); @@ -142,6 +168,8 @@ struct LTOCodeGenerator { /// than one element, code generation is done in parallel with out.size() /// threads. Output files will be written to members of out. Returns true on /// success. + /// + /// Calls \a verifyMergedModuleOnce(). bool compileOptimized(ArrayRef<raw_pwrite_stream *> Out); void setDiagnosticHandler(lto_diagnostic_handler_t, void *); @@ -153,21 +181,28 @@ struct LTOCodeGenerator { private: void initializeLTOPasses(); + /// Verify the merged module on first call. + /// + /// Sets \a HasVerifiedInput on first call and doesn't run again on the same + /// input. + void verifyMergedModuleOnce(); + bool compileOptimizedToFile(const char **Name); + void restoreLinkageForExternals(); void applyScopeRestrictions(); - void applyRestriction(GlobalValue &GV, ArrayRef<StringRef> Libcalls, - std::vector<const char *> &MustPreserveList, - SmallPtrSetImpl<GlobalValue *> &AsmUsed, - Mangler &Mangler); + void preserveDiscardableGVs( + Module &TheModule, + llvm::function_ref<bool(const GlobalValue &)> mustPreserveGV); + bool determineTarget(); + std::unique_ptr<TargetMachine> createTargetMachine(); static void DiagnosticHandler(const DiagnosticInfo &DI, void *Context); void DiagnosticHandler2(const DiagnosticInfo &DI); void emitError(const std::string &ErrMsg); - - typedef StringMap<uint8_t> StringSet; + void emitWarning(const std::string &ErrMsg); LLVMContext &Context; std::unique_ptr<Module> MergedModule; @@ -175,9 +210,11 @@ private: std::unique_ptr<TargetMachine> TargetMach; bool EmitDwarfDebugInfo = false; bool ScopeRestrictionsDone = false; - Reloc::Model RelocModel = Reloc::Default; - StringSet MustPreserveSymbols; - StringSet AsmUndefinedRefs; + bool HasVerifiedInput = false; + Optional<Reloc::Model> RelocModel; + StringSet<> MustPreserveSymbols; + StringSet<> AsmUndefinedRefs; + StringMap<GlobalValue::LinkageTypes> ExternalSymbols; std::vector<std::string> CodegenOptions; std::string FeatureStr; std::string MCpu; @@ -185,11 +222,14 @@ private: std::string NativeObjectPath; TargetOptions Options; CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default; + const Target *MArch = nullptr; + std::string TripleStr; unsigned OptLevel = 2; lto_diagnostic_handler_t DiagHandler = nullptr; void *DiagContext = nullptr; bool ShouldInternalize = true; bool ShouldEmbedUselists = false; + bool ShouldRestoreGlobalsLinkage = false; TargetMachine::CodeGenFileType FileType = TargetMachine::CGFT_ObjectFile; }; } diff --git a/include/llvm/LTO/LTOModule.h b/include/llvm/LTO/legacy/LTOModule.h index 97b5865bd47f..2e46219be19e 100644 --- a/include/llvm/LTO/LTOModule.h +++ b/include/llvm/LTO/legacy/LTOModule.h @@ -18,8 +18,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/Module.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Target/TargetMachine.h" #include <string> @@ -59,8 +57,6 @@ private: std::vector<const char*> _asm_undefines; LTOModule(std::unique_ptr<object::IRObjectFile> Obj, TargetMachine *TM); - LTOModule(std::unique_ptr<object::IRObjectFile> Obj, TargetMachine *TM, - std::unique_ptr<LLVMContext> Context); public: ~LTOModule(); @@ -69,6 +65,9 @@ public: static bool isBitcodeFile(const void *mem, size_t length); static bool isBitcodeFile(const char *path); + /// Returns 'true' if the Module is produced for ThinLTO. + bool isThinLTO(); + /// Returns 'true' if the memory buffer is LLVM bitcode for the specified /// triple. static bool isBitcodeForTarget(MemoryBuffer *memBuffer, @@ -92,23 +91,22 @@ public: /// InitializeAllAsmPrinters(); /// InitializeAllAsmParsers(); static ErrorOr<std::unique_ptr<LTOModule>> - createFromFile(LLVMContext &Context, const char *path, TargetOptions options); + createFromFile(LLVMContext &Context, const char *path, + const TargetOptions &options); static ErrorOr<std::unique_ptr<LTOModule>> createFromOpenFile(LLVMContext &Context, int fd, const char *path, - size_t size, TargetOptions options); + size_t size, const TargetOptions &options); static ErrorOr<std::unique_ptr<LTOModule>> createFromOpenFileSlice(LLVMContext &Context, int fd, const char *path, - size_t map_size, off_t offset, TargetOptions options); + size_t map_size, off_t offset, + const TargetOptions &options); static ErrorOr<std::unique_ptr<LTOModule>> createFromBuffer(LLVMContext &Context, const void *mem, size_t length, - TargetOptions options, StringRef path = ""); - + const TargetOptions &options, StringRef path = ""); static ErrorOr<std::unique_ptr<LTOModule>> - createInLocalContext(const void *mem, size_t length, TargetOptions options, + createInLocalContext(std::unique_ptr<LLVMContext> Context, const void *mem, + size_t length, const TargetOptions &options, StringRef path); - static ErrorOr<std::unique_ptr<LTOModule>> - createInContext(const void *mem, size_t length, TargetOptions options, - StringRef path, LLVMContext *Context); const Module &getModule() const { return const_cast<LTOModule*>(this)->getModule(); @@ -207,8 +205,8 @@ private: /// Create an LTOModule (private version). static ErrorOr<std::unique_ptr<LTOModule>> - makeLTOModule(MemoryBufferRef Buffer, TargetOptions options, - LLVMContext *Context); + makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, + LLVMContext &Context, bool ShouldBeLazy); }; } #endif diff --git a/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h new file mode 100644 index 000000000000..539880e8d3a7 --- /dev/null +++ b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -0,0 +1,276 @@ +//===-ThinLTOCodeGenerator.h - LLVM Link Time Optimizer -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the ThinLTOCodeGenerator class, similar to the +// LTOCodeGenerator but for the ThinLTO scheme. It provides an interface for +// linker plugin. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LTO_THINLTOCODEGENERATOR_H +#define LLVM_LTO_THINLTOCODEGENERATOR_H + +#include "llvm-c/lto.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Target/TargetOptions.h" + +#include <string> + +namespace llvm { +class StringRef; +class LLVMContext; +class TargetMachine; + +/// Helper to gather options relevant to the target machine creation +struct TargetMachineBuilder { + Triple TheTriple; + std::string MCpu; + std::string MAttr; + TargetOptions Options; + Optional<Reloc::Model> RelocModel; + CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default; + + std::unique_ptr<TargetMachine> create() const; +}; + +/// This class define an interface similar to the LTOCodeGenerator, but adapted +/// for ThinLTO processing. +/// The ThinLTOCodeGenerator is not intended to be reuse for multiple +/// compilation: the model is that the client adds modules to the generator and +/// ask to perform the ThinLTO optimizations / codegen, and finally destroys the +/// codegenerator. +class ThinLTOCodeGenerator { +public: + /// Add given module to the code generator. + void addModule(StringRef Identifier, StringRef Data); + + /** + * Adds to a list of all global symbols that must exist in the final generated + * code. If a symbol is not listed there, it will be optimized away if it is + * inlined into every usage. + */ + void preserveSymbol(StringRef Name); + + /** + * Adds to a list of all global symbols that are cross-referenced between + * ThinLTO files. If the ThinLTO CodeGenerator can ensure that every + * references from a ThinLTO module to this symbol is optimized away, then + * the symbol can be discarded. + */ + void crossReferenceSymbol(StringRef Name); + + /** + * Process all the modules that were added to the code generator in parallel. + * + * Client can access the resulting object files using getProducedBinaries() + */ + void run(); + + /** + * Return the "in memory" binaries produced by the code generator. + */ + std::vector<std::unique_ptr<MemoryBuffer>> &getProducedBinaries() { + return ProducedBinaries; + } + + /** + * \defgroup Options setters + * @{ + */ + + /** + * \defgroup Cache controlling options + * + * These entry points control the ThinLTO cache. The cache is intended to + * support incremental build, and thus needs to be persistent accross build. + * The client enabled the cache by supplying a path to an existing directory. + * The code generator will use this to store objects files that may be reused + * during a subsequent build. + * To avoid filling the disk space, a few knobs are provided: + * - The pruning interval limit the frequency at which the garbage collector + * will try to scan the cache directory to prune it from expired entries. + * Setting to -1 disable the pruning (default). + * - The pruning expiration time indicates to the garbage collector how old + * an entry needs to be to be removed. + * - Finally, the garbage collector can be instructed to prune the cache till + * the occupied space goes below a threshold. + * @{ + */ + + struct CachingOptions { + std::string Path; // Path to the cache, empty to disable. + int PruningInterval = 1200; // seconds, -1 to disable pruning. + unsigned int Expiration = 7 * 24 * 3600; // seconds (1w default). + unsigned MaxPercentageOfAvailableSpace = 75; // percentage. + }; + + /// Provide a path to a directory where to store the cached files for + /// incremental build. + void setCacheDir(std::string Path) { CacheOptions.Path = std::move(Path); } + + /// Cache policy: interval (seconds) between two prune of the cache. Set to a + /// negative value (default) to disable pruning. A value of 0 will be ignored. + void setCachePruningInterval(int Interval) { + if (Interval) + CacheOptions.PruningInterval = Interval; + } + + /// Cache policy: expiration (in seconds) for an entry. + /// A value of 0 will be ignored. + void setCacheEntryExpiration(unsigned Expiration) { + if (Expiration) + CacheOptions.Expiration = Expiration; + } + + /** + * Sets the maximum cache size that can be persistent across build, in terms + * of percentage of the available space on the the disk. Set to 100 to + * indicate no limit, 50 to indicate that the cache size will not be left over + * half the available space. A value over 100 will be reduced to 100, and a + * value of 0 will be ignored. + * + * + * The formula looks like: + * AvailableSpace = FreeSpace + ExistingCacheSize + * NewCacheSize = AvailableSpace * P/100 + * + */ + void setMaxCacheSizeRelativeToAvailableSpace(unsigned Percentage) { + if (Percentage) + CacheOptions.MaxPercentageOfAvailableSpace = Percentage; + } + + /**@}*/ + + /// Set the path to a directory where to save temporaries at various stages of + /// the processing. + void setSaveTempsDir(std::string Path) { SaveTempsDir = std::move(Path); } + + /// CPU to use to initialize the TargetMachine + void setCpu(std::string Cpu) { TMBuilder.MCpu = std::move(Cpu); } + + /// Subtarget attributes + void setAttr(std::string MAttr) { TMBuilder.MAttr = std::move(MAttr); } + + /// TargetMachine options + void setTargetOptions(TargetOptions Options) { + TMBuilder.Options = std::move(Options); + } + + /// CodeModel + void setCodePICModel(Optional<Reloc::Model> Model) { + TMBuilder.RelocModel = Model; + } + + /// CodeGen optimization level + void setCodeGenOptLevel(CodeGenOpt::Level CGOptLevel) { + TMBuilder.CGOptLevel = CGOptLevel; + } + + /// Disable CodeGen, only run the stages till codegen and stop. The output + /// will be bitcode. + void disableCodeGen(bool Disable) { DisableCodeGen = Disable; } + + /// Perform CodeGen only: disable all other stages. + void setCodeGenOnly(bool CGOnly) { CodeGenOnly = CGOnly; } + + /**@}*/ + + /** + * \defgroup Set of APIs to run individual stages in isolation. + * @{ + */ + + /** + * Produce the combined summary index from all the bitcode files: + * "thin-link". + */ + std::unique_ptr<ModuleSummaryIndex> linkCombinedIndex(); + + /** + * Perform promotion and renaming of exported internal functions, + * and additionally resolve weak and linkonce symbols. + * Index is updated to reflect linkage changes from weak resolution. + */ + void promote(Module &Module, ModuleSummaryIndex &Index); + + /** + * Compute and emit the imported files for module at \p ModulePath. + */ + static void emitImports(StringRef ModulePath, StringRef OutputName, + ModuleSummaryIndex &Index); + + /** + * Perform cross-module importing for the module identified by + * ModuleIdentifier. + */ + void crossModuleImport(Module &Module, ModuleSummaryIndex &Index); + + /** + * Compute the list of summaries needed for importing into module. + */ + static void gatherImportedSummariesForModule( + StringRef ModulePath, ModuleSummaryIndex &Index, + std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex); + + /** + * Perform internalization. Index is updated to reflect linkage changes. + */ + void internalize(Module &Module, ModuleSummaryIndex &Index); + + /** + * Perform post-importing ThinLTO optimizations. + */ + void optimize(Module &Module); + + /** + * Perform ThinLTO CodeGen. + */ + std::unique_ptr<MemoryBuffer> codegen(Module &Module); + + /**@}*/ + +private: + /// Helper factory to build a TargetMachine + TargetMachineBuilder TMBuilder; + + /// Vector holding the in-memory buffer containing the produced binaries. + std::vector<std::unique_ptr<MemoryBuffer>> ProducedBinaries; + + /// Vector holding the input buffers containing the bitcode modules to + /// process. + std::vector<MemoryBufferRef> Modules; + + /// Set of symbols that need to be preserved outside of the set of bitcode + /// files. + StringSet<> PreservedSymbols; + + /// Set of symbols that are cross-referenced between bitcode files. + StringSet<> CrossReferencedSymbols; + + /// Control the caching behavior. + CachingOptions CacheOptions; + + /// Path to a directory to save the temporary bitcode files. + std::string SaveTempsDir; + + /// Flag to enable/disable CodeGen. When set to true, the process stops after + /// optimizations and a bitcode is produced. + bool DisableCodeGen = false; + + /// Flag to indicate that only the CodeGen will be performed, no cross-module + /// importing or optimization. + bool CodeGenOnly = false; +}; +} +#endif diff --git a/include/llvm/LTO/legacy/UpdateCompilerUsed.h b/include/llvm/LTO/legacy/UpdateCompilerUsed.h new file mode 100644 index 000000000000..4be0027e97d7 --- /dev/null +++ b/include/llvm/LTO/legacy/UpdateCompilerUsed.h @@ -0,0 +1,32 @@ +//==------ UpdateCompilerUsed.h - LLVM Link Time Optimizer Utility --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares a helper class to update llvm.compiler_used metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LTO_UPDATE_COMPILER_USED_H +#define LLVM_LTO_UPDATE_COMPILER_USED_H + +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/GlobalValue.h" + +namespace llvm { +class Module; +class TargetMachine; + +/// Find all globals in \p TheModule that are referenced in +/// \p AsmUndefinedRefs, as well as the user-supplied functions definitions that +/// are also libcalls, and create or update the magic "llvm.compiler_used" +/// global in \p TheModule. +void updateCompilerUsed(Module &TheModule, const TargetMachine &TM, + const StringSet<> &AsmUndefinedRefs); +} + +#endif // LLVM_LTO_UPDATE_COMPILER_USED_H diff --git a/include/llvm/LibDriver/LibDriver.h b/include/llvm/LibDriver/LibDriver.h index 09495650c1b9..95feb60be403 100644 --- a/include/llvm/LibDriver/LibDriver.h +++ b/include/llvm/LibDriver/LibDriver.h @@ -15,12 +15,10 @@ #ifndef LLVM_LIBDRIVER_LIBDRIVER_H #define LLVM_LIBDRIVER_LIBDRIVER_H -#include "llvm/ADT/ArrayRef.h" - namespace llvm { +template <typename T> class ArrayRef; -int libDriverMain(llvm::ArrayRef<const char*> ARgs); - +int libDriverMain(ArrayRef<const char *> ARgs); } #endif diff --git a/include/llvm/LineEditor/LineEditor.h b/include/llvm/LineEditor/LineEditor.h index bb106f87ca48..68995d0633ad 100644 --- a/include/llvm/LineEditor/LineEditor.h +++ b/include/llvm/LineEditor/LineEditor.h @@ -15,6 +15,7 @@ #include <cstdio> #include <memory> #include <string> +#include <utility> #include <vector> namespace llvm { @@ -137,7 +138,7 @@ private: template <typename T> struct ListCompleterModel : ListCompleterConcept { - ListCompleterModel(T Value) : Value(Value) {} + ListCompleterModel(T Value) : Value(std::move(Value)) {} std::vector<Completion> getCompletions(StringRef Buffer, size_t Pos) const override { return Value(Buffer, Pos); diff --git a/include/llvm/LinkAllIR.h b/include/llvm/LinkAllIR.h index 2b0604aee067..77e19ce900e3 100644 --- a/include/llvm/LinkAllIR.h +++ b/include/llvm/LinkAllIR.h @@ -43,8 +43,9 @@ namespace { // to know that getenv() never returns -1, this will do the job. if (std::getenv("bar") != (char*) -1) return; - (void)new llvm::Module("", llvm::getGlobalContext()); - (void)new llvm::UnreachableInst(llvm::getGlobalContext()); + llvm::LLVMContext Context; + (void)new llvm::Module("", Context); + (void)new llvm::UnreachableInst(Context); (void) llvm::createVerifierPass(); } } ForceVMCoreLinking; diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 327faac33206..b2721d0a1fd9 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -17,8 +17,10 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasSetTracker.h" +#include "llvm/Analysis/AliasAnalysisEvaluator.h" #include "llvm/Analysis/BasicAliasAnalysis.h" -#include "llvm/Analysis/CFLAliasAnalysis.h" +#include "llvm/Analysis/CFLAndersAliasAnalysis.h" +#include "llvm/Analysis/CFLSteensAliasAnalysis.h" #include "llvm/Analysis/CallPrinter.h" #include "llvm/Analysis/DomPrinter.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -31,14 +33,17 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" #include "llvm/Analysis/ScopedNoAliasAA.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/CodeGen/Passes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/FunctionAttrs.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Utils/SymbolRewriter.h" #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" #include "llvm/Transforms/Vectorize.h" @@ -66,10 +71,11 @@ namespace { (void) llvm::createScopedNoAliasAAWrapperPass(); (void) llvm::createBoundsCheckingPass(); (void) llvm::createBreakCriticalEdgesPass(); - (void) llvm::createCallGraphPrinterPass(); + (void) llvm::createCallGraphDOTPrinterPass(); (void) llvm::createCallGraphViewerPass(); (void) llvm::createCFGSimplificationPass(); - (void) llvm::createCFLAAWrapperPass(); + (void) llvm::createCFLAndersAAWrapperPass(); + (void) llvm::createCFLSteensAAWrapperPass(); (void) llvm::createStructurizeCFGPass(); (void) llvm::createConstantMergePass(); (void) llvm::createConstantPropagationPass(); @@ -78,22 +84,24 @@ namespace { (void) llvm::createDeadCodeEliminationPass(); (void) llvm::createDeadInstEliminationPass(); (void) llvm::createDeadStoreEliminationPass(); - (void) llvm::createDependenceAnalysisPass(); + (void) llvm::createDependenceAnalysisWrapperPass(); (void) llvm::createDivergenceAnalysisPass(); (void) llvm::createDomOnlyPrinterPass(); (void) llvm::createDomPrinterPass(); (void) llvm::createDomOnlyViewerPass(); (void) llvm::createDomViewerPass(); (void) llvm::createGCOVProfilerPass(); - (void) llvm::createPGOInstrumentationGenPass(); - (void) llvm::createPGOInstrumentationUsePass(); - (void) llvm::createInstrProfilingPass(); + (void) llvm::createPGOInstrumentationGenLegacyPass(); + (void) llvm::createPGOInstrumentationUseLegacyPass(); + (void) llvm::createPGOIndirectCallPromotionLegacyPass(); + (void) llvm::createInstrProfilingLegacyPass(); (void) llvm::createFunctionImportPass(); (void) llvm::createFunctionInliningPass(); (void) llvm::createAlwaysInlinerPass(); (void) llvm::createGlobalDCEPass(); (void) llvm::createGlobalOptimizerPass(); (void) llvm::createGlobalsAAWrapperPass(); + (void) llvm::createGuardWideningPass(); (void) llvm::createIPConstantPropagationPass(); (void) llvm::createIPSCCPPass(); (void) llvm::createInductiveRangeCheckEliminationPass(); @@ -106,10 +114,12 @@ namespace { (void) llvm::createLoopExtractorPass(); (void) llvm::createLoopInterchangePass(); (void) llvm::createLoopSimplifyPass(); + (void) llvm::createLoopSimplifyCFGPass(); (void) llvm::createLoopStrengthReducePass(); (void) llvm::createLoopRerollPass(); (void) llvm::createLoopUnrollPass(); (void) llvm::createLoopUnswitchPass(); + (void) llvm::createLoopVersioningLICMPass(); (void) llvm::createLoopIdiomPass(); (void) llvm::createLoopRotatePass(); (void) llvm::createLowerExpectIntrinsicPass(); @@ -137,7 +147,7 @@ namespace { (void) llvm::createRegionViewerPass(); (void) llvm::createSCCPPass(); (void) llvm::createSafeStackPass(); - (void) llvm::createScalarReplAggregatesPass(); + (void) llvm::createSROAPass(); (void) llvm::createSingleLoopExtractorPass(); (void) llvm::createStripSymbolsPass(); (void) llvm::createStripNonDebugSymbolsPass(); @@ -150,6 +160,7 @@ namespace { (void) llvm::createConstantHoistingPass(); (void) llvm::createCodeGenPreparePass(); (void) llvm::createEarlyCSEPass(); + (void) llvm::createGVNHoistPass(); (void) llvm::createMergedLoadStoreMotionPass(); (void) llvm::createGVNPass(); (void) llvm::createMemCpyOptPass(); @@ -157,7 +168,7 @@ namespace { (void) llvm::createPostDomTree(); (void) llvm::createInstructionNamerPass(); (void) llvm::createMetaRenamerPass(); - (void) llvm::createPostOrderFunctionAttrsPass(); + (void) llvm::createPostOrderFunctionAttrsLegacyPass(); (void) llvm::createReversePostOrderFunctionAttrsPass(); (void) llvm::createMergeFunctionsPass(); std::string buf; @@ -175,11 +186,13 @@ namespace { (void) llvm::createInstructionSimplifierPass(); (void) llvm::createLoopVectorizePass(); (void) llvm::createSLPVectorizerPass(); + (void) llvm::createLoadStoreVectorizerPass(); (void) llvm::createBBVectorizePass(); (void) llvm::createPartiallyInlineLibCallsPass(); (void) llvm::createScalarizerPass(); (void) llvm::createSeparateConstOffsetFromGEPPass(); (void) llvm::createSpeculativeExecutionPass(); + (void) llvm::createSpeculativeExecutionIfHasBranchDivergencePass(); (void) llvm::createRewriteSymbolsPass(); (void) llvm::createStraightLineStrengthReducePass(); (void) llvm::createMemDerefPrinter(); @@ -190,7 +203,9 @@ namespace { (void)new llvm::ScalarEvolutionWrapperPass(); llvm::Function::Create(nullptr, llvm::GlobalValue::ExternalLinkage)->viewCFGOnly(); llvm::RGPassManager RGM; - llvm::AliasAnalysis AA; + llvm::TargetLibraryInfoImpl TLII; + llvm::TargetLibraryInfo TLI(TLII); + llvm::AliasAnalysis AA(TLI); llvm::AliasSetTracker X(AA); X.add(nullptr, 0, llvm::AAMDNodes()); // for -print-alias-sets (void) llvm::AreStatisticsEnabled(); diff --git a/include/llvm/Linker/IRMover.h b/include/llvm/Linker/IRMover.h index a964cc4b72c5..578940ed4069 100644 --- a/include/llvm/Linker/IRMover.h +++ b/include/llvm/Linker/IRMover.h @@ -15,10 +15,12 @@ #include <functional> namespace llvm { +class Error; class GlobalValue; -class MDNode; +class Metadata; class Module; class StructType; +class TrackingMDRef; class Type; class IRMover { @@ -39,6 +41,9 @@ class IRMover { static bool isEqual(const StructType *LHS, const StructType *RHS); }; + /// Type of the Metadata map in \a ValueToValueMapTy. + typedef DenseMap<const Metadata *, TrackingMDRef> MDMapT; + public: class IdentifiedStructTypeSet { // The set of opaque types is the composite module. @@ -58,17 +63,22 @@ public: IRMover(Module &M); typedef std::function<void(GlobalValue &)> ValueAdder; - /// Move in the provide values. The source is destroyed. - /// Returns true on error. - bool move(Module &Src, ArrayRef<GlobalValue *> ValuesToLink, - std::function<void(GlobalValue &GV, ValueAdder Add)> AddLazyFor, - DenseMap<unsigned, MDNode *> *ValIDToTempMDMap = nullptr, - bool IsMetadataLinkingPostpass = false); + + /// Move in the provide values in \p ValuesToLink from \p Src. + /// + /// - \p AddLazyFor is a call back that the IRMover will call when a global + /// value is referenced by one of the ValuesToLink (transitively) but was + /// not present in ValuesToLink. The GlobalValue and a ValueAdder callback + /// are passed as an argument, and the callback is expected to be called + /// if the GlobalValue needs to be added to the \p ValuesToLink and linked. + Error move(std::unique_ptr<Module> Src, ArrayRef<GlobalValue *> ValuesToLink, + std::function<void(GlobalValue &GV, ValueAdder Add)> AddLazyFor); Module &getModule() { return Composite; } private: Module &Composite; IdentifiedStructTypeSet IdentifiedStructTypes; + MDMapT SharedMDs; ///< A Metadata map to use for all calls to \a move(). }; } // End llvm namespace diff --git a/include/llvm/Linker/Linker.h b/include/llvm/Linker/Linker.h index 2b051e6d15c9..b077c373326f 100644 --- a/include/llvm/Linker/Linker.h +++ b/include/llvm/Linker/Linker.h @@ -10,7 +10,6 @@ #ifndef LLVM_LINKER_LINKER_H #define LLVM_LINKER_LINKER_H -#include "llvm/IR/FunctionInfo.h" #include "llvm/Linker/IRMover.h" namespace llvm { @@ -30,7 +29,10 @@ public: None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2) + InternalizeLinkedSymbols = (1 << 2), + /// Don't force link referenced linkonce definitions, import declaration. + DontForceLinkLinkonceODR = (1 << 3) + }; Linker(Module &M); @@ -39,38 +41,18 @@ public: /// /// Passing OverrideSymbols as true will have symbols from Src /// shadow those in the Dest. - /// For ThinLTO function importing/exporting the \p FunctionInfoIndex - /// is passed. If \p FunctionsToImport is provided, only the functions that + /// For ThinLTO function importing/exporting the \p ModuleSummaryIndex + /// is passed. If \p GlobalsToImport is provided, only the globals that /// are part of the set will be imported from the source module. - /// The \p ValIDToTempMDMap is populated by the linker when function - /// importing is performed. /// /// Returns true on error. bool linkInModule(std::unique_ptr<Module> Src, unsigned Flags = Flags::None, - const FunctionInfoIndex *Index = nullptr, - DenseSet<const GlobalValue *> *FunctionsToImport = nullptr, - DenseMap<unsigned, MDNode *> *ValIDToTempMDMap = nullptr); - - /// This exists to implement the deprecated LLVMLinkModules C api. Don't use - /// for anything else. - bool linkInModuleForCAPI(Module &Src); + DenseSet<const GlobalValue *> *GlobalsToImport = nullptr); static bool linkModules(Module &Dest, std::unique_ptr<Module> Src, unsigned Flags = Flags::None); - - /// \brief Link metadata from \p Src into the composite. The source is - /// destroyed. - /// - /// The \p ValIDToTempMDMap sound have been populated earlier during function - /// importing from \p Src. - bool linkInMetadata(Module &Src, - DenseMap<unsigned, MDNode *> *ValIDToTempMDMap); }; -/// Perform in-place global value handling on the given Module for -/// exported local functions renamed and promoted for ThinLTO. -bool renameModuleForThinLTO(Module &M, const FunctionInfoIndex *Index); - } // End llvm namespace #endif diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index 51312ff80447..ce17a2a06758 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -11,6 +11,7 @@ #define LLVM_MC_MCASMBACKEND_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCFixup.h" @@ -28,7 +29,7 @@ class MCRelaxableFragment; class MCObjectWriter; class MCSection; class MCValue; -class raw_ostream; +class raw_pwrite_stream; /// Generic interface to target specific assembler backends. class MCAsmBackend { @@ -38,8 +39,6 @@ class MCAsmBackend { protected: // Can only create subclasses. MCAsmBackend(); - unsigned HasDataInCodeSupport : 1; - public: virtual ~MCAsmBackend(); @@ -50,17 +49,6 @@ public: /// emit the final object file. virtual MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const = 0; - /// Create a new ELFObjectTargetWriter to enable non-standard - /// ELFObjectWriters. - virtual MCELFObjectTargetWriter *createELFObjectTargetWriter() const { - llvm_unreachable("createELFObjectTargetWriter is not supported by asm " - "backend"); - } - - /// Check whether this target implements data-in-code markers. If not, data - /// region directives will be ignored. - bool hasDataInCodeSupport() const { return HasDataInCodeSupport; } - /// \name Target Fixup Interfaces /// @{ @@ -68,9 +56,7 @@ public: virtual unsigned getNumFixupKinds() const = 0; /// Map a relocation name used in .reloc to a fixup kind. - /// Returns true and sets MappedKind if Name is successfully mapped. - /// Otherwise returns false and leaves MappedKind unchanged. - virtual bool getFixupKind(StringRef Name, MCFixupKind &MappedKind) const; + virtual Optional<MCFixupKind> getFixupKind(StringRef Name) const; /// Get information on a fixup kind. virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; @@ -116,8 +102,10 @@ public: /// /// \param Inst The instruction to relax, which may be the same as the /// output. + /// \param STI the subtarget information for the associated instruction. /// \param [out] Res On return, the relaxed instruction. - virtual void relaxInstruction(const MCInst &Inst, MCInst &Res) const = 0; + virtual void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const = 0; /// @} @@ -133,6 +121,10 @@ public: /// \return - True on success. virtual bool writeNopData(uint64_t Count, MCObjectWriter *OW) const = 0; + /// Give backend an opportunity to finish layout after relaxation + virtual void finishLayout(MCAssembler const &Asm, + MCAsmLayout &Layout) const {} + /// Handle any target-specific assembler flags. By default, do nothing. virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {} diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 384584ef4ef0..e6ed5688d18d 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -53,6 +53,12 @@ namespace LCOMM { enum LCOMMType { NoAlignment, ByteAlignment, Log2Alignment }; } +enum class DebugCompressionType { + DCT_None, // no compression + DCT_Zlib, // zlib style complession + DCT_ZlibGnu // zlib-gnu style compression +}; + /// This class is intended to be used as a base class for asm /// properties and features specific to the target. class MCAsmInfo { @@ -280,6 +286,10 @@ protected: /// to false. bool HasNoDeadStrip; + /// True if this target supports the MachO .alt_entry directive. Defaults to + /// false. + bool HasAltEntry; + /// Used to declare a global as being a weak symbol. Defaults to ".weak". const char *WeakDirective; @@ -352,13 +362,20 @@ protected: /// construction (see LLVMTargetMachine::initAsmInfo()). bool UseIntegratedAssembler; - /// Compress DWARF debug sections. Defaults to false. - bool CompressDebugSections; + /// Preserve Comments in assembly + bool PreserveAsmComments; + + /// Compress DWARF debug sections. Defaults to no compression. + DebugCompressionType CompressDebugSections; /// True if the integrated assembler should interpret 'a >> b' constant /// expressions as logical rather than arithmetic. bool UseLogicalShr; + // If true, emit GOTPCRELX/REX_GOTPCRELX instead of GOTPCREL, on + // X86_64 ELF. + bool RelaxELFRelocations = true; + public: explicit MCAsmInfo(); virtual ~MCAsmInfo(); @@ -483,7 +500,7 @@ public: bool getAlignmentIsInBytes() const { return AlignmentIsInBytes; } unsigned getTextAlignFillValue() const { return TextAlignFillValue; } const char *getGlobalDirective() const { return GlobalDirective; } - bool doesSetDirectiveSuppressesReloc() const { + bool doesSetDirectiveSuppressReloc() const { return SetDirectiveSuppressesReloc; } bool hasAggressiveSymbolFolding() const { return HasAggressiveSymbolFolding; } @@ -498,6 +515,7 @@ public: bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } bool hasIdentDirective() const { return HasIdentDirective; } bool hasNoDeadStrip() const { return HasNoDeadStrip; } + bool hasAltEntry() const { return HasAltEntry; } const char *getWeakDirective() const { return WeakDirective; } const char *getWeakRefDirective() const { return WeakRefDirective; } bool hasWeakDefDirective() const { return HasWeakDefDirective; } @@ -520,6 +538,10 @@ public: ExceptionHandling getExceptionHandlingType() const { return ExceptionsType; } WinEH::EncodingType getWinEHEncodingType() const { return WinEHEncodingType; } + void setExceptionsType(ExceptionHandling EH) { + ExceptionsType = EH; + } + /// Returns true if the exception handling method for the platform uses call /// frame information to unwind. bool usesCFIForEH() const { @@ -556,13 +578,26 @@ public: UseIntegratedAssembler = Value; } - bool compressDebugSections() const { return CompressDebugSections; } + /// Return true if assembly (inline or otherwise) should be parsed. + bool preserveAsmComments() const { return PreserveAsmComments; } + + /// Set whether assembly (inline or otherwise) should be parsed. + virtual void setPreserveAsmComments(bool Value) { + PreserveAsmComments = Value; + } - void setCompressDebugSections(bool CompressDebugSections) { + DebugCompressionType compressDebugSections() const { + return CompressDebugSections; + } + + void setCompressDebugSections(DebugCompressionType CompressDebugSections) { this->CompressDebugSections = CompressDebugSections; } bool shouldUseLogicalShr() const { return UseLogicalShr; } + + bool canRelaxRelocations() const { return RelaxELFRelocations; } + void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; } }; } diff --git a/include/llvm/MC/MCAsmInfoELF.h b/include/llvm/MC/MCAsmInfoELF.h index 7125f5c7ad7a..f8bb943aac4e 100644 --- a/include/llvm/MC/MCAsmInfoELF.h +++ b/include/llvm/MC/MCAsmInfoELF.h @@ -18,6 +18,10 @@ class MCAsmInfoELF : public MCAsmInfo { MCSection *getNonexecutableStackSection(MCContext &Ctx) const final; protected: + /// Targets which have non-executable stacks by default can set this to false + /// to disable the special section which requests a non-executable stack. + bool UsesNonexecutableStackSection; + MCAsmInfoELF(); }; } diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index c0bd12875839..aa3b451152df 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -123,7 +123,7 @@ private: // here. Maybe when the relocation stuff moves to target specific, // this can go with it? The streamer would need some target specific // refactoring too. - mutable SmallPtrSet<const MCSymbol *, 64> ThumbFuncs; + mutable SmallPtrSet<const MCSymbol *, 32> ThumbFuncs; /// \brief The bundle alignment size currently set in the assembler. /// @@ -189,6 +189,9 @@ private: bool relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); bool relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF); + bool relaxCVInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &DF); + bool relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &DF); /// finishLayout - Finalize a layout, including fragment lowering. void finishLayout(MCAsmLayout &Layout); @@ -243,8 +246,8 @@ public: // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. - MCAssembler(MCContext &Context_, MCAsmBackend &Backend_, - MCCodeEmitter &Emitter_, MCObjectWriter &Writer_); + MCAssembler(MCContext &Context, MCAsmBackend &Backend, + MCCodeEmitter &Emitter, MCObjectWriter &Writer); ~MCAssembler(); /// Reuse an assembler instance diff --git a/include/llvm/MC/MCCodeGenInfo.h b/include/llvm/MC/MCCodeGenInfo.h deleted file mode 100644 index 0a4744f1d0f7..000000000000 --- a/include/llvm/MC/MCCodeGenInfo.h +++ /dev/null @@ -1,51 +0,0 @@ -//===-- llvm/MC/MCCodeGenInfo.h - Target CodeGen Info -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file tracks information about the target which can affect codegen, -// asm parsing, and asm printing. For example, relocation model. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MC_MCCODEGENINFO_H -#define LLVM_MC_MCCODEGENINFO_H - -#include "llvm/Support/CodeGen.h" - -namespace llvm { - -class MCCodeGenInfo { - /// RelocationModel - Relocation model: static, pic, etc. - /// - Reloc::Model RelocationModel; - - /// CMModel - Code model. - /// - CodeModel::Model CMModel; - - /// OptLevel - Optimization level. - /// - CodeGenOpt::Level OptLevel; - -public: - void initMCCodeGenInfo(Reloc::Model RM = Reloc::Default, - CodeModel::Model CM = CodeModel::Default, - CodeGenOpt::Level OL = CodeGenOpt::Default); - - Reloc::Model getRelocationModel() const { return RelocationModel; } - - CodeModel::Model getCodeModel() const { return CMModel; } - - CodeGenOpt::Level getOptLevel() const { return OptLevel; } - - // Allow overriding OptLevel on a per-function basis. - void setOptLevel(CodeGenOpt::Level Level) { OptLevel = Level; } -}; -} // namespace llvm - -#endif diff --git a/include/llvm/MC/MCCodeView.h b/include/llvm/MC/MCCodeView.h new file mode 100644 index 000000000000..d999ff555997 --- /dev/null +++ b/include/llvm/MC/MCCodeView.h @@ -0,0 +1,210 @@ +//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Holds state from .cv_file and .cv_loc directives for later emission. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCCODEVIEW_H +#define LLVM_MC_MCCODEVIEW_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCFragment.h" +#include <map> +#include <vector> + +namespace llvm { +class MCContext; +class MCObjectStreamer; +class MCStreamer; + +/// \brief Instances of this class represent the information from a +/// .cv_loc directive. +class MCCVLoc { + uint32_t FunctionId; + uint32_t FileNum; + uint32_t Line; + uint16_t Column; + uint16_t PrologueEnd : 1; + uint16_t IsStmt : 1; + +private: // MCContext manages these + friend class MCContext; + MCCVLoc(unsigned functionid, unsigned fileNum, unsigned line, unsigned column, + bool prologueend, bool isstmt) + : FunctionId(functionid), FileNum(fileNum), Line(line), Column(column), + PrologueEnd(prologueend), IsStmt(isstmt) {} + + // Allow the default copy constructor and assignment operator to be used + // for an MCCVLoc object. + +public: + unsigned getFunctionId() const { return FunctionId; } + + /// \brief Get the FileNum of this MCCVLoc. + unsigned getFileNum() const { return FileNum; } + + /// \brief Get the Line of this MCCVLoc. + unsigned getLine() const { return Line; } + + /// \brief Get the Column of this MCCVLoc. + unsigned getColumn() const { return Column; } + + bool isPrologueEnd() const { return PrologueEnd; } + bool isStmt() const { return IsStmt; } + + void setFunctionId(unsigned FID) { FunctionId = FID; } + + /// \brief Set the FileNum of this MCCVLoc. + void setFileNum(unsigned fileNum) { FileNum = fileNum; } + + /// \brief Set the Line of this MCCVLoc. + void setLine(unsigned line) { Line = line; } + + /// \brief Set the Column of this MCCVLoc. + void setColumn(unsigned column) { + assert(column <= UINT16_MAX); + Column = column; + } + + void setPrologueEnd(bool PE) { PrologueEnd = PE; } + void setIsStmt(bool IS) { IsStmt = IS; } +}; + +/// \brief Instances of this class represent the line information for +/// the CodeView line table entries. Which is created after a machine +/// instruction is assembled and uses an address from a temporary label +/// created at the current address in the current section and the info from +/// the last .cv_loc directive seen as stored in the context. +class MCCVLineEntry : public MCCVLoc { + const MCSymbol *Label; + +private: + // Allow the default copy constructor and assignment operator to be used + // for an MCCVLineEntry object. + +public: + // Constructor to create an MCCVLineEntry given a symbol and the dwarf loc. + MCCVLineEntry(const MCSymbol *Label, const MCCVLoc loc) + : MCCVLoc(loc), Label(Label) {} + + const MCSymbol *getLabel() const { return Label; } + + // This is called when an instruction is assembled into the specified + // section and if there is information from the last .cv_loc directive that + // has yet to have a line entry made for it is made. + static void Make(MCObjectStreamer *MCOS); +}; + +/// Holds state from .cv_file and .cv_loc directives for later emission. +class CodeViewContext { +public: + CodeViewContext(); + ~CodeViewContext(); + + bool isValidFileNumber(unsigned FileNumber) const; + bool addFile(unsigned FileNumber, StringRef Filename); + ArrayRef<StringRef> getFilenames() { return Filenames; } + + /// \brief Add a line entry. + void addLineEntry(const MCCVLineEntry &LineEntry) { + size_t Offset = MCCVLines.size(); + auto I = MCCVLineStartStop.insert( + {LineEntry.getFunctionId(), {Offset, Offset + 1}}); + if (!I.second) + I.first->second.second = Offset + 1; + MCCVLines.push_back(LineEntry); + } + + std::vector<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) { + std::vector<MCCVLineEntry> FilteredLines; + + auto I = MCCVLineStartStop.find(FuncId); + if (I != MCCVLineStartStop.end()) + for (size_t Idx = I->second.first, End = I->second.second; Idx != End; + ++Idx) + if (MCCVLines[Idx].getFunctionId() == FuncId) + FilteredLines.push_back(MCCVLines[Idx]); + return FilteredLines; + } + + std::pair<size_t, size_t> getLineExtent(unsigned FuncId) { + auto I = MCCVLineStartStop.find(FuncId); + // Return an empty extent if there are no cv_locs for this function id. + if (I == MCCVLineStartStop.end()) + return {~0ULL, 0}; + return I->second; + } + + ArrayRef<MCCVLineEntry> getLinesForExtent(size_t L, size_t R) { + if (R <= L) + return None; + if (L >= MCCVLines.size()) + return None; + return makeArrayRef(&MCCVLines[L], R - L); + } + + /// Emits a line table substream. + void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId, + const MCSymbol *FuncBegin, + const MCSymbol *FuncEnd); + + void emitInlineLineTableForFunction( + MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId, + unsigned SourceLineNum, const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds); + + /// Encodes the binary annotations once we have a layout. + void encodeInlineLineTable(MCAsmLayout &Layout, + MCCVInlineLineTableFragment &F); + + void + emitDefRange(MCObjectStreamer &OS, + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion); + + void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F); + + /// Emits the string table substream. + void emitStringTable(MCObjectStreamer &OS); + + /// Emits the file checksum substream. + void emitFileChecksums(MCObjectStreamer &OS); + +private: + /// Map from string to string table offset. + StringMap<unsigned> StringTable; + + /// The fragment that ultimately holds our strings. + MCDataFragment *StrTabFragment = nullptr; + bool InsertedStrTabFragment = false; + + MCDataFragment *getStringTableFragment(); + + /// Add something to the string table. + StringRef addToStringTable(StringRef S); + + /// Get a string table offset. + unsigned getStringTableOffset(StringRef S); + + /// An array of absolute paths. Eventually this may include the file checksum. + SmallVector<StringRef, 4> Filenames; + + /// The offset of the first and last .cv_loc directive for a given function + /// id. + std::map<unsigned, std::pair<size_t, size_t>> MCCVLineStartStop; + + /// A collection of MCCVLineEntry for each section. + std::vector<MCCVLineEntry> MCCVLines; +}; + +} // end namespace llvm +#endif diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index e5a9afd9968c..fe1377e054e8 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -16,6 +16,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/SectionKind.h" @@ -42,6 +43,7 @@ namespace llvm { class MCSectionMachO; class MCSectionELF; class MCSectionCOFF; + class CodeViewContext; /// Context object for machine code objects. This class owns all of the /// sections that it creates. @@ -66,6 +68,8 @@ namespace llvm { /// The MCObjectFileInfo for this target. const MCObjectFileInfo *MOFI; + std::unique_ptr<CodeViewContext> CVContext; + /// Allocator object used for creating machine code objects. /// /// We use a bump pointer allocator to avoid the need to track all allocated @@ -92,7 +96,9 @@ namespace llvm { DenseMap<std::pair<unsigned, unsigned>, MCSymbol *> LocalSymbols; /// Keeps tracks of names that were used both for used declared and - /// artificial symbols. + /// artificial symbols. The value is "true" if the name has been used for a + /// non-section symbol (there can be at most one of those, plus an unlimited + /// number of section symbols with the same name). StringMap<bool, BumpPtrAllocator &> UsedNames; /// The next ID to dole out to an unnamed assembler temporary symbol with @@ -135,6 +141,10 @@ namespace llvm { MCDwarfLoc CurrentDwarfLoc; bool DwarfLocSeen; + /// The current CodeView line information from the last .cv_loc directive. + MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true); + bool CVLocSeen = false; + /// Generate dwarf debugging info for assembly source files. bool GenDwarfForAssembly; @@ -190,16 +200,19 @@ namespace llvm { std::string SectionName; StringRef GroupName; int SelectionKey; + unsigned UniqueID; COFFSectionKey(StringRef SectionName, StringRef GroupName, - int SelectionKey) + int SelectionKey, unsigned UniqueID) : SectionName(SectionName), GroupName(GroupName), - SelectionKey(SelectionKey) {} + SelectionKey(SelectionKey), UniqueID(UniqueID) {} bool operator<(const COFFSectionKey &Other) const { if (SectionName != Other.SectionName) return SectionName < Other.SectionName; if (GroupName != Other.GroupName) return GroupName < Other.GroupName; - return SelectionKey < Other.SelectionKey; + if (SelectionKey != Other.SelectionKey) + return SelectionKey < Other.SelectionKey; + return UniqueID < Other.UniqueID; } }; @@ -237,6 +250,8 @@ namespace llvm { const MCObjectFileInfo *getObjectFileInfo() const { return MOFI; } + CodeViewContext &getCVContext(); + void setAllowTemporaryLabels(bool Value) { AllowTemporaryLabels = Value; } void setUseNamesOnTempLabels(bool Value) { UseNamesOnTempLabels = Value; } @@ -303,6 +318,13 @@ namespace llvm { /// \name Section Management /// @{ + enum : unsigned { + /// Pass this value as the UniqueID during section creation to get the + /// generic section with the given name and characteristics. The usual + /// sections such as .text use this ID. + GenericSectionID = ~0U + }; + /// Return the MCSection for the specified mach-o section. This requires /// the operands to be valid. MCSectionMachO *getMachOSection(StringRef Segment, StringRef Section, @@ -317,48 +339,56 @@ namespace llvm { BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags) { return getELFSection(Section, Type, Flags, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, const char *BeginSymName) { return getELFSection(Section, Type, Flags, 0, "", BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group) { + const Twine &Group) { return getELFSection(Section, Type, Flags, EntrySize, Group, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, const char *BeginSymName) { + const Twine &Group, const char *BeginSymName) { return getELFSection(Section, Type, Flags, EntrySize, Group, ~0, BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, unsigned UniqueID) { + const Twine &Group, unsigned UniqueID) { return getELFSection(Section, Type, Flags, EntrySize, Group, UniqueID, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, unsigned UniqueID, + const Twine &Group, unsigned UniqueID, const char *BeginSymName); - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, const char *BeginSymName, const MCSectionELF *Associated); - MCSectionELF *createELFRelSection(StringRef Name, unsigned Type, + /// Get a section with the provided group identifier. This section is + /// named by concatenating \p Prefix with '.' then \p Suffix. The \p Type + /// describes the type of the section and \p Flags are used to further + /// configure this named section. + MCSectionELF *getELFNamedSection(const Twine &Prefix, const Twine &Suffix, + unsigned Type, unsigned Flags, + unsigned EntrySize = 0); + + MCSectionELF *createELFRelSection(const Twine &Name, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, const MCSectionELF *Associated); @@ -370,6 +400,7 @@ namespace llvm { MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, SectionKind Kind, StringRef COMDATSymName, int Selection, + unsigned UniqueID = GenericSectionID, const char *BeginSymName = nullptr); MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, @@ -382,8 +413,9 @@ namespace llvm { /// section containing KeySym. For example, to create a debug info section /// associated with an inline function, pass the normal debug info section /// as Sec and the function symbol as KeySym. - MCSectionCOFF *getAssociativeCOFFSection(MCSectionCOFF *Sec, - const MCSymbol *KeySym); + MCSectionCOFF * + getAssociativeCOFFSection(MCSectionCOFF *Sec, const MCSymbol *KeySym, + unsigned UniqueID = GenericSectionID); // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); @@ -394,14 +426,11 @@ namespace llvm { /// @{ /// \brief Get the compilation directory for DW_AT_comp_dir - /// This can be overridden by clients which want to control the reported - /// compilation directory and have it be something other than the current - /// working directory. - /// Returns an empty string if the current directory cannot be determined. + /// The compilation directory should be set with \c setCompilationDir before + /// calling this function. If it is unset, an empty string will be returned. StringRef getCompilationDir() const { return CompilationDir; } /// \brief Set the compilation directory for DW_AT_comp_dir - /// Override the default (CWD) compilation directory. void setCompilationDir(StringRef S) { CompilationDir = S.str(); } /// \brief Get the main file name for use in error messages and debug @@ -505,6 +534,35 @@ namespace llvm { /// @} + + /// \name CodeView Management + /// @{ + + /// Creates an entry in the cv file table. + unsigned getCVFile(StringRef FileName, unsigned FileNumber); + + /// Saves the information from the currently parsed .cv_loc directive + /// and sets CVLocSeen. When the next instruction is assembled an entry + /// in the line number table with this information and the address of the + /// instruction will be created. + void setCurrentCVLoc(unsigned FunctionId, unsigned FileNo, unsigned Line, + unsigned Column, bool PrologueEnd, bool IsStmt) { + CurrentCVLoc.setFunctionId(FunctionId); + CurrentCVLoc.setFileNum(FileNo); + CurrentCVLoc.setLine(Line); + CurrentCVLoc.setColumn(Column); + CurrentCVLoc.setPrologueEnd(PrologueEnd); + CurrentCVLoc.setIsStmt(IsStmt); + CVLocSeen = true; + } + void clearCVLocSeen() { CVLocSeen = false; } + + bool getCVLocSeen() { return CVLocSeen; } + const MCCVLoc &getCurrentCVLoc() { return CurrentCVLoc; } + + bool isValidCVFileNumber(unsigned FileNumber); + /// @} + char *getSecureLogFile() { return SecureLogFile; } raw_fd_ostream *getSecureLog() { return SecureLog.get(); } bool getSecureLogUsed() { return SecureLogUsed; } diff --git a/include/llvm/MC/MCDirectives.h b/include/llvm/MC/MCDirectives.h index 326b2a1ac061..8c74b169135b 100644 --- a/include/llvm/MC/MCDirectives.h +++ b/include/llvm/MC/MCDirectives.h @@ -35,6 +35,7 @@ enum MCSymbolAttr { MCSA_Local, ///< .local (ELF) MCSA_NoDeadStrip, ///< .no_dead_strip (MachO) MCSA_SymbolResolver, ///< .symbol_resolver (MachO) + MCSA_AltEntry, ///< .alt_entry (MachO) MCSA_PrivateExtern, ///< .private_extern (MachO) MCSA_Protected, ///< .protected (ELF) MCSA_Reference, ///< .reference (MachO) diff --git a/include/llvm/MC/MCDisassembler.h b/include/llvm/MC/MCDisassembler/MCDisassembler.h index 57c40d660f64..9006d87abb43 100644 --- a/include/llvm/MC/MCDisassembler.h +++ b/include/llvm/MC/MCDisassembler/MCDisassembler.h @@ -6,16 +6,16 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#ifndef LLVM_MC_MCDISASSEMBLER_H -#define LLVM_MC_MCDISASSEMBLER_H +#ifndef LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H +#define LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H #include "llvm-c/Disassembler.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/MC/MCSymbolizer.h" +#include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/Support/DataTypes.h" namespace llvm { +template <typename T> class ArrayRef; class MCInst; class MCSubtargetInfo; class raw_ostream; diff --git a/include/llvm/MC/MCExternalSymbolizer.h b/include/llvm/MC/MCDisassembler/MCExternalSymbolizer.h index 2c7d23707c95..bd3e5d4638e5 100644 --- a/include/llvm/MC/MCExternalSymbolizer.h +++ b/include/llvm/MC/MCDisassembler/MCExternalSymbolizer.h @@ -13,11 +13,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_MC_MCEXTERNALSYMBOLIZER_H -#define LLVM_MC_MCEXTERNALSYMBOLIZER_H +#ifndef LLVM_MC_MCDISASSEMBLER_MCEXTERNALSYMBOLIZER_H +#define LLVM_MC_MCDISASSEMBLER_MCEXTERNALSYMBOLIZER_H #include "llvm-c/Disassembler.h" -#include "llvm/MC/MCSymbolizer.h" +#include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include <memory> namespace llvm { diff --git a/include/llvm/MC/MCRelocationInfo.h b/include/llvm/MC/MCDisassembler/MCRelocationInfo.h index 40e0217b8d83..25334f755ee6 100644 --- a/include/llvm/MC/MCRelocationInfo.h +++ b/include/llvm/MC/MCDisassembler/MCRelocationInfo.h @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_MC_MCRELOCATIONINFO_H -#define LLVM_MC_MCRELOCATIONINFO_H +#ifndef LLVM_MC_MCDISASSEMBLER_MCRELOCATIONINFO_H +#define LLVM_MC_MCDISASSEMBLER_MCRELOCATIONINFO_H #include "llvm/Support/Compiler.h" @@ -38,10 +38,6 @@ public: MCRelocationInfo(MCContext &Ctx); virtual ~MCRelocationInfo(); - /// \brief Create an MCExpr for the relocation \p Rel. - /// \returns If possible, an MCExpr corresponding to Rel, else 0. - virtual const MCExpr *createExprForRelocation(object::RelocationRef Rel); - /// \brief Create an MCExpr for the target-specific \p VariantKind. /// The VariantKinds are defined in llvm-c/Disassembler.h. /// Used by MCExternalSymbolizer. diff --git a/include/llvm/MC/MCSymbolizer.h b/include/llvm/MC/MCDisassembler/MCSymbolizer.h index 2ef17673f091..713467c0a3e7 100644 --- a/include/llvm/MC/MCSymbolizer.h +++ b/include/llvm/MC/MCDisassembler/MCSymbolizer.h @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_MC_MCSYMBOLIZER_H -#define LLVM_MC_MCSYMBOLIZER_H +#ifndef LLVM_MC_MCDISASSEMBLER_MCSYMBOLIZER_H +#define LLVM_MC_MCDISASSEMBLER_MCSYMBOLIZER_H -#include "llvm/MC/MCRelocationInfo.h" +#include "llvm/MC/MCDisassembler/MCRelocationInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include <cassert> diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index 8a50863a0c39..0c555d377d8b 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -15,20 +15,18 @@ #ifndef LLVM_MC_MCDWARF_H #define LLVM_MC_MCDWARF_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Dwarf.h" -#include "llvm/Support/raw_ostream.h" -#include <map> #include <string> #include <utility> #include <vector> namespace llvm { +template <typename T> class ArrayRef; +class raw_ostream; class MCAsmBackend; class MCContext; class MCObjectStreamer; @@ -72,7 +70,7 @@ class MCDwarfLoc { private: // MCContext manages these friend class MCContext; - friend class MCLineEntry; + friend class MCDwarfLineEntry; MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags, unsigned isa, unsigned discriminator) : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa), @@ -135,16 +133,16 @@ public: /// instruction is assembled and uses an address from a temporary label /// created at the current address in the current section and the info from /// the last .loc directive seen as stored in the context. -class MCLineEntry : public MCDwarfLoc { +class MCDwarfLineEntry : public MCDwarfLoc { MCSymbol *Label; private: // Allow the default copy constructor and assignment operator to be used - // for an MCLineEntry object. + // for an MCDwarfLineEntry object. public: - // Constructor to create an MCLineEntry given a symbol and the dwarf loc. - MCLineEntry(MCSymbol *label, const MCDwarfLoc loc) + // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc. + MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc) : MCDwarfLoc(loc), Label(label) {} MCSymbol *getLabel() const { return Label; } @@ -162,21 +160,21 @@ public: class MCLineSection { public: // \brief Add an entry to this MCLineSection's line entries. - void addLineEntry(const MCLineEntry &LineEntry, MCSection *Sec) { + void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) { MCLineDivisions[Sec].push_back(LineEntry); } - typedef std::vector<MCLineEntry> MCLineEntryCollection; - typedef MCLineEntryCollection::iterator iterator; - typedef MCLineEntryCollection::const_iterator const_iterator; - typedef MapVector<MCSection *, MCLineEntryCollection> MCLineDivisionMap; + typedef std::vector<MCDwarfLineEntry> MCDwarfLineEntryCollection; + typedef MCDwarfLineEntryCollection::iterator iterator; + typedef MCDwarfLineEntryCollection::const_iterator const_iterator; + typedef MapVector<MCSection *, MCDwarfLineEntryCollection> MCLineDivisionMap; private: - // A collection of MCLineEntry for each section. + // A collection of MCDwarfLineEntry for each section. MCLineDivisionMap MCLineDivisions; public: - // Returns the collection of MCLineEntry for a given Compile Unit ID. + // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID. const MCLineDivisionMap &getMCLineEntries() const { return MCLineDivisions; } diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h index 193dac018b2b..376e21821316 100644 --- a/include/llvm/MC/MCELFObjectWriter.h +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -11,12 +11,15 @@ #define LLVM_MC_MCELFOBJECTWRITER_H #include "llvm/ADT/Triple.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/raw_ostream.h" #include <vector> namespace llvm { class MCAssembler; +class MCContext; class MCFixup; class MCFragment; class MCObjectWriter; @@ -30,10 +33,21 @@ struct ELFRelocationEntry { const MCSymbolELF *Symbol; // The symbol to relocate with. unsigned Type; // The type of the relocation. uint64_t Addend; // The addend to use. + const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it. + uint64_t OriginalAddend; // The original value of addend. ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type, - uint64_t Addend) - : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend) {} + uint64_t Addend, const MCSymbolELF *OriginalSymbol, + uint64_t OriginalAddend) + : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend), + OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {} + + void print(raw_ostream &Out) const { + Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type + << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol + << ", OriginalAddend=" << OriginalAddend; + } + void dump() const { print(errs()); } }; class MCELFObjectTargetWriter { @@ -64,8 +78,8 @@ public: virtual ~MCELFObjectTargetWriter() {} - virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsPCRel) const = 0; + virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const = 0; virtual bool needsRelocateWithSymbol(const MCSymbol &Sym, unsigned Type) const; diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index 6eb2c2c343ff..b108f0df52b6 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -15,7 +15,6 @@ #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/DataTypes.h" -#include <vector> namespace llvm { class MCAsmBackend; diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index f6ccdc095551..b0e4736565b0 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -73,7 +73,8 @@ public: /// \name Utility Methods /// @{ - void print(raw_ostream &OS, const MCAsmInfo *MAI) const; + void print(raw_ostream &OS, const MCAsmInfo *MAI, + bool InParens = false) const; void dump() const; /// @} @@ -165,6 +166,7 @@ public: VK_GOT, VK_GOTOFF, + VK_GOTREL, VK_GOTPCREL, VK_GOTTPOFF, VK_INDNTPOFF, @@ -176,6 +178,8 @@ public: VK_TLSLDM, VK_TPOFF, VK_DTPOFF, + VK_TLSCALL, // symbol(tlscall) + VK_TLSDESC, // symbol(tlsdesc) VK_TLVP, // Mach-O thread local variable relocations VK_TLVPPAGE, VK_TLVPPAGEOFF, @@ -194,8 +198,6 @@ public: VK_ARM_PREL31, VK_ARM_SBREL, // symbol(sbrel) VK_ARM_TLSLDO, // symbol(tlsldo) - VK_ARM_TLSCALL, // symbol(tlscall) - VK_ARM_TLSDESC, // symbol(tlsdesc) VK_ARM_TLSDESCSEQ, VK_PPC_LO, // symbol@l @@ -214,7 +216,6 @@ public: VK_PPC_TOC_HI, // symbol@toc@h VK_PPC_TOC_HA, // symbol@toc@ha VK_PPC_DTPMOD, // symbol@dtpmod - VK_PPC_TPREL, // symbol@tprel VK_PPC_TPREL_LO, // symbol@tprel@l VK_PPC_TPREL_HI, // symbol@tprel@h VK_PPC_TPREL_HA, // symbol@tprel@ha @@ -222,7 +223,6 @@ public: VK_PPC_TPREL_HIGHERA, // symbol@tprel@highera VK_PPC_TPREL_HIGHEST, // symbol@tprel@highest VK_PPC_TPREL_HIGHESTA, // symbol@tprel@highesta - VK_PPC_DTPREL, // symbol@dtprel VK_PPC_DTPREL_LO, // symbol@dtprel@l VK_PPC_DTPREL_HI, // symbol@dtprel@h VK_PPC_DTPREL_HA, // symbol@dtprel@ha @@ -251,33 +251,6 @@ public: VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local - VK_Mips_GPREL, - VK_Mips_GOT_CALL, - VK_Mips_GOT16, - VK_Mips_GOT, - VK_Mips_ABS_HI, - VK_Mips_ABS_LO, - VK_Mips_TLSGD, - VK_Mips_TLSLDM, - VK_Mips_DTPREL_HI, - VK_Mips_DTPREL_LO, - VK_Mips_GOTTPREL, - VK_Mips_TPREL_HI, - VK_Mips_TPREL_LO, - VK_Mips_GPOFF_HI, - VK_Mips_GPOFF_LO, - VK_Mips_GOT_DISP, - VK_Mips_GOT_PAGE, - VK_Mips_GOT_OFST, - VK_Mips_HIGHER, - VK_Mips_HIGHEST, - VK_Mips_GOT_HI16, - VK_Mips_GOT_LO16, - VK_Mips_CALL_HI16, - VK_Mips_CALL_LO16, - VK_Mips_PCREL_HI16, - VK_Mips_PCREL_LO16, - VK_COFF_IMGREL32, // symbol@imgrel (image-relative) VK_Hexagon_PCREL, diff --git a/include/llvm/MC/MCFragment.h b/include/llvm/MC/MCFragment.h index 7d6db525ce61..e0a2bfc23747 100644 --- a/include/llvm/MC/MCFragment.h +++ b/include/llvm/MC/MCFragment.h @@ -40,6 +40,8 @@ public: FT_DwarfFrame, FT_LEB, FT_SafeSEH, + FT_CVInlineLines, + FT_CVDefRange, FT_Dummy }; @@ -210,7 +212,8 @@ public: static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); - return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data; + return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data || + Kind == MCFragment::FT_CVDefRange; } }; @@ -321,36 +324,19 @@ public: class MCFillFragment : public MCFragment { - /// Value - Value to use for filling bytes. - int64_t Value; - - /// ValueSize - The size (in bytes) of \p Value to use when filling, or 0 if - /// this is a virtual fill fragment. - unsigned ValueSize; + /// Value to use for filling bytes. + uint8_t Value; - /// Size - The number of bytes to insert. + /// The number of bytes to insert. uint64_t Size; public: - MCFillFragment(int64_t Value, unsigned ValueSize, uint64_t Size, - MCSection *Sec = nullptr) - : MCFragment(FT_Fill, false, 0, Sec), Value(Value), ValueSize(ValueSize), - Size(Size) { - assert((!ValueSize || (Size % ValueSize) == 0) && - "Fill size must be a multiple of the value size!"); - } - - /// \name Accessors - /// @{ - - int64_t getValue() const { return Value; } - - unsigned getValueSize() const { return ValueSize; } + MCFillFragment(uint8_t Value, uint64_t Size, MCSection *Sec = nullptr) + : MCFragment(FT_Fill, false, 0, Sec), Value(Value), Size(Size) {} + uint8_t getValue() const { return Value; } uint64_t getSize() const { return Size; } - /// @} - static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Fill; } @@ -501,6 +487,79 @@ public: } }; +/// Fragment representing the binary annotations produced by the +/// .cv_inline_linetable directive. +class MCCVInlineLineTableFragment : public MCFragment { + unsigned SiteFuncId; + unsigned StartFileId; + unsigned StartLineNum; + const MCSymbol *FnStartSym; + const MCSymbol *FnEndSym; + SmallVector<unsigned, 3> SecondaryFuncs; + SmallString<8> Contents; + + /// CodeViewContext has the real knowledge about this format, so let it access + /// our members. + friend class CodeViewContext; + +public: + MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId, + unsigned StartLineNum, const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym, + ArrayRef<unsigned> SecondaryFuncs, + MCSection *Sec = nullptr) + : MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId), + StartFileId(StartFileId), StartLineNum(StartLineNum), + FnStartSym(FnStartSym), FnEndSym(FnEndSym), + SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {} + + /// \name Accessors + /// @{ + + const MCSymbol *getFnStartSym() const { return FnStartSym; } + const MCSymbol *getFnEndSym() const { return FnEndSym; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_CVInlineLines; + } +}; + +/// Fragment representing the .cv_def_range directive. +class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> { + SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 2> Ranges; + SmallString<32> FixedSizePortion; + + /// CodeViewContext has the real knowledge about this format, so let it access + /// our members. + friend class CodeViewContext; + +public: + MCCVDefRangeFragment( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion, MCSection *Sec = nullptr) + : MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec), + Ranges(Ranges.begin(), Ranges.end()), + FixedSizePortion(FixedSizePortion) {} + + /// \name Accessors + /// @{ + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const { + return Ranges; + } + + StringRef getFixedSizePortion() const { return FixedSizePortion; } + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_CVDefRange; + } +}; + } // end namespace llvm #endif diff --git a/include/llvm/MC/MCInstPrinter.h b/include/llvm/MC/MCInstPrinter.h index 0eafd02c51c6..2119c5a633b4 100644 --- a/include/llvm/MC/MCInstPrinter.h +++ b/include/llvm/MC/MCInstPrinter.h @@ -10,11 +10,11 @@ #ifndef LLVM_MC_MCINSTPRINTER_H #define LLVM_MC_MCINSTPRINTER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Format.h" namespace llvm { +template <typename T> class ArrayRef; class MCInst; class raw_ostream; class MCAsmInfo; diff --git a/include/llvm/MC/MCLinkerOptimizationHint.h b/include/llvm/MC/MCLinkerOptimizationHint.h index a519c4b71b03..200bb93f64c8 100644 --- a/include/llvm/MC/MCLinkerOptimizationHint.h +++ b/include/llvm/MC/MCLinkerOptimizationHint.h @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/MC/MCMachObjectWriter.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -28,6 +27,7 @@ namespace llvm { // Forward declarations. class MCAsmLayout; class MCSymbol; +class MachObjectWriter; /// Linker Optimization Hint Type. enum MCLOHType { @@ -123,31 +123,12 @@ public: /// Emit this directive as: /// <kind, numArgs, addr1, ..., addrN> - void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { - raw_ostream &OutStream = ObjWriter.getStream(); - emit_impl(OutStream, ObjWriter, Layout); - } + void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const; /// Get the size in bytes of this directive if emitted in \p ObjWriter with /// the given \p Layout. uint64_t getEmitSize(const MachObjectWriter &ObjWriter, - const MCAsmLayout &Layout) const { - class raw_counting_ostream : public raw_ostream { - uint64_t Count; - - void write_impl(const char *, size_t size) override { Count += size; } - - uint64_t current_pos() const override { return Count; } - - public: - raw_counting_ostream() : Count(0) {} - ~raw_counting_ostream() override { flush(); } - }; - - raw_counting_ostream OutStream; - emit_impl(OutStream, ObjWriter, Layout); - return OutStream.tell(); - } + const MCAsmLayout &Layout) const; }; class MCLOHContainer { diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h index cd3db957afc1..1a685dbd608e 100644 --- a/include/llvm/MC/MCMachObjectWriter.h +++ b/include/llvm/MC/MCMachObjectWriter.h @@ -11,7 +11,6 @@ #define LLVM_MC_MCMACHOBJECTWRITER_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallString.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCObjectWriter.h" diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index 8a3a6af3bf79..cef4e5b3eb93 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -127,6 +127,7 @@ protected: MCSection *DwarfGnuPubTypesSection; MCSection *COFFDebugSymbolsSection; + MCSection *COFFDebugTypesSection; /// Extra TLS Variable Data section. /// @@ -158,6 +159,7 @@ protected: MCSection *MergeableConst4Section; MCSection *MergeableConst8Section; MCSection *MergeableConst16Section; + MCSection *MergeableConst32Section; // MachO specific sections. @@ -183,6 +185,7 @@ protected: MCSection *SixteenByteConstantSection; MCSection *LazySymbolPointerSection; MCSection *NonLazySymbolPointerSection; + MCSection *ThreadLocalPointerSection; /// COFF specific sections. MCSection *DrectveSection; @@ -191,12 +194,8 @@ protected: MCSection *SXDataSection; public: - void InitMCObjectFileInfo(const Triple &TT, Reloc::Model RM, - CodeModel::Model CM, MCContext &ctx); - LLVM_ATTRIBUTE_DEPRECATED( - void InitMCObjectFileInfo(StringRef TT, Reloc::Model RM, - CodeModel::Model CM, MCContext &ctx), - "StringRef GNU Triple argument replaced by a llvm::Triple object"); + void InitMCObjectFileInfo(const Triple &TT, bool PIC, CodeModel::Model CM, + MCContext &ctx); bool getSupportsWeakOmittedEHFrame() const { return SupportsWeakOmittedEHFrame; @@ -274,6 +273,10 @@ public: MCSection *getCOFFDebugSymbolsSection() const { return COFFDebugSymbolsSection; } + MCSection *getCOFFDebugTypesSection() const { + return COFFDebugTypesSection; + } + MCSection *getTLSExtraDataSection() const { return TLSExtraDataSection; } const MCSection *getTLSDataSection() const { return TLSDataSection; } @@ -293,6 +296,9 @@ public: const MCSection *getMergeableConst16Section() const { return MergeableConst16Section; } + const MCSection *getMergeableConst32Section() const { + return MergeableConst32Section; + } // MachO specific sections. const MCSection *getTLSTLVSection() const { return TLSTLVSection; } @@ -324,6 +330,9 @@ public: MCSection *getNonLazySymbolPointerSection() const { return NonLazySymbolPointerSection; } + MCSection *getThreadLocalPointerSection() const { + return ThreadLocalPointerSection; + } // COFF specific sections. MCSection *getDrectveSection() const { return DrectveSection; } @@ -338,18 +347,18 @@ public: enum Environment { IsMachO, IsELF, IsCOFF }; Environment getObjectFileType() const { return Env; } - Reloc::Model getRelocM() const { return RelocM; } + bool isPositionIndependent() const { return PositionIndependent; } private: Environment Env; - Reloc::Model RelocM; + bool PositionIndependent; CodeModel::Model CMModel; MCContext *Ctx; Triple TT; - void initMachOMCObjectFileInfo(Triple T); - void initELFMCObjectFileInfo(Triple T); - void initCOFFMCObjectFileInfo(Triple T); + void initMachOMCObjectFileInfo(const Triple &T); + void initELFMCObjectFileInfo(const Triple &T); + void initCOFFMCObjectFileInfo(const Triple &T); public: const Triple &getTargetTriple() const { return TT; } diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 9fe2fda21353..d7775f27868c 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -59,7 +59,6 @@ public: void EmitFrames(MCAsmBackend *MAB); void EmitCFISections(bool EH, bool Debug) override; -protected: MCFragment *getCurrentFragment() const; void insert(MCFragment *F) { @@ -73,6 +72,7 @@ protected: /// fragment is not a data fragment. MCDataFragment *getOrCreateDataFragment(); +protected: bool changeSectionImpl(MCSection *Section, const MCExpr *Subsection); /// If any labels have been emitted but not assigned fragments, ensure that @@ -122,11 +122,31 @@ public: unsigned PointerSize); void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label); + void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, + unsigned Column, bool PrologueEnd, bool IsStmt, + StringRef FileName) override; + void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin, + const MCSymbol *End) override; + void EmitCVInlineLinetableDirective( + unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, + ArrayRef<unsigned> SecondaryFunctionIds) override; + void EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion) override; + void EmitCVStringTableDirective() override; + void EmitCVFileChecksumsDirective() override; void EmitGPRel32Value(const MCExpr *Value) override; void EmitGPRel64Value(const MCExpr *Value) override; bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) override; - void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; + using MCStreamer::emitFill; + void emitFill(uint64_t NumBytes, uint8_t FillValue) override; + void emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc = SMLoc()) override; + void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, + SMLoc Loc = SMLoc()) override; + void FinishImpl() override; /// Emit the absolute difference between two symbols if possible. diff --git a/include/llvm/MC/MCObjectWriter.h b/include/llvm/MC/MCObjectWriter.h index 63c833ac20d6..0ecebe42a0b9 100644 --- a/include/llvm/MC/MCObjectWriter.h +++ b/include/llvm/MC/MCObjectWriter.h @@ -22,6 +22,7 @@ class MCAsmLayout; class MCAssembler; class MCFixup; class MCFragment; +class MCSymbol; class MCSymbolRefExpr; class MCValue; diff --git a/include/llvm/MC/MCParser/AsmLexer.h b/include/llvm/MC/MCParser/AsmLexer.h index 1bb6d212784e..c779121b6cf0 100644 --- a/include/llvm/MC/MCParser/AsmLexer.h +++ b/include/llvm/MC/MCParser/AsmLexer.h @@ -29,7 +29,8 @@ class AsmLexer : public MCAsmLexer { const char *CurPtr; StringRef CurBuf; - bool isAtStartOfLine; + bool IsAtStartOfLine; + bool IsAtStartOfStatement; void operator=(const AsmLexer&) = delete; AsmLexer(const AsmLexer&) = delete; @@ -45,17 +46,15 @@ public: void setBuffer(StringRef Buf, const char *ptr = nullptr); StringRef LexUntilEndOfStatement() override; - StringRef LexUntilEndOfLine(); size_t peekTokens(MutableArrayRef<AsmToken> Buf, bool ShouldSkipSpace = true) override; - bool isAtStartOfComment(const char *Ptr); - bool isAtStatementSeparator(const char *Ptr); - const MCAsmInfo &getMAI() const { return MAI; } private: + bool isAtStartOfComment(const char *Ptr); + bool isAtStatementSeparator(const char *Ptr); int getNextChar(); AsmToken ReturnError(const char *Loc, const std::string &Msg); @@ -67,6 +66,8 @@ private: AsmToken LexQuote(); AsmToken LexFloatLiteral(); AsmToken LexHexFloatLiteral(bool NoIntDigits); + + StringRef LexUntilEndOfLine(); }; } // end namespace llvm diff --git a/include/llvm/MC/MCParser/MCAsmLexer.h b/include/llvm/MC/MCParser/MCAsmLexer.h index 55279f49529a..3dd22c93d363 100644 --- a/include/llvm/MC/MCParser/MCAsmLexer.h +++ b/include/llvm/MC/MCParser/MCAsmLexer.h @@ -11,10 +11,13 @@ #define LLVM_MC_MCPARSER_MCASMLEXER_H #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" +#include <utility> namespace llvm { @@ -36,12 +39,15 @@ public: // Real values. Real, + // Comments + Comment, + HashDirective, // No-value. EndOfStatement, Colon, Space, Plus, Minus, Tilde, - Slash, // '/' + Slash, // '/' BackSlash, // '\' LParen, RParen, LBrac, RBrac, LCurly, RCurly, Star, Dot, Comma, Dollar, Equal, EqualEqual, @@ -64,7 +70,7 @@ private: public: AsmToken() {} AsmToken(TokenKind Kind, StringRef Str, APInt IntVal) - : Kind(Kind), Str(Str), IntVal(IntVal) {} + : Kind(Kind), Str(Str), IntVal(std::move(IntVal)) {} AsmToken(TokenKind Kind, StringRef Str, int64_t IntVal = 0) : Kind(Kind), Str(Str), IntVal(64, IntVal, true) {} @@ -150,8 +156,12 @@ public: const AsmToken &Lex() { assert(!CurTok.empty()); CurTok.erase(CurTok.begin()); - if (CurTok.empty()) - CurTok.emplace_back(LexToken()); + // LexToken may generate multiple tokens via UnLex but will always return + // the first one. Place returned value at head of CurTok vector. + if (CurTok.empty()) { + AsmToken T = LexToken(); + CurTok.insert(CurTok.begin(), T); + } return CurTok.front(); } diff --git a/include/llvm/MC/MCTargetAsmParser.h b/include/llvm/MC/MCParser/MCTargetAsmParser.h index 03b2dc9a282c..28a7b9664882 100644 --- a/include/llvm/MC/MCTargetAsmParser.h +++ b/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_MC_MCTARGETASMPARSER_H -#define LLVM_MC_MCTARGETASMPARSER_H +#ifndef LLVM_MC_MCPARSER_MCTARGETASMPARSER_H +#define LLVM_MC_MCPARSER_MCTARGETASMPARSER_H #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" @@ -40,6 +40,7 @@ enum AsmRewriteKind { AOK_Output, // Rewrite in terms of $N. AOK_SizeDirective, // Add a sizing directive (e.g., dword ptr). AOK_Label, // Rewrite local labels. + AOK_EndOfStatement, // Add EndOfStatement (e.g., "\n\t"). AOK_Skip // Skip emission (e.g., offset/type operators). }; @@ -55,6 +56,7 @@ const char AsmRewritePrecedence [] = { 3, // AOK_Output 5, // AOK_SizeDirective 1, // AOK_Label + 5, // AOK_EndOfStatement 2 // AOK_Skip }; diff --git a/include/llvm/MC/MCRegisterInfo.h b/include/llvm/MC/MCRegisterInfo.h index a4d5e0867232..548280614e92 100644 --- a/include/llvm/MC/MCRegisterInfo.h +++ b/include/llvm/MC/MCRegisterInfo.h @@ -182,6 +182,7 @@ private: const DwarfLLVMRegPair *Dwarf2LRegs; // Dwarf to LLVM regs mapping const DwarfLLVMRegPair *EHDwarf2LRegs; // Dwarf to LLVM regs mapping EH DenseMap<unsigned, int> L2SEHRegs; // LLVM to SEH regs mapping + DenseMap<unsigned, int> L2CVRegs; // LLVM to CV regs mapping public: /// DiffListIterator - Base iterator class that can traverse the @@ -309,6 +310,10 @@ public: L2SEHRegs[LLVMReg] = SEHReg; } + void mapLLVMRegToCVReg(unsigned LLVMReg, int CVReg) { + L2CVRegs[LLVMReg] = CVReg; + } + /// \brief This method should return the register where the return /// address can be found. unsigned getRARegister() const { @@ -396,6 +401,10 @@ public: /// number. Returns LLVM register number if there is no equivalent value. int getSEHRegNum(unsigned RegNum) const; + /// \brief Map a target register to an equivalent CodeView register + /// number. + int getCodeViewRegNum(unsigned RegNum) const; + regclass_iterator regclass_begin() const { return Classes; } regclass_iterator regclass_end() const { return Classes+NumClasses; } @@ -440,6 +449,11 @@ public: return RegA == RegB || isSuperRegister(RegA, RegB); } + /// \brief Returns true if RegB is a super-register or sub-register of RegA + /// or if RegB == RegA. + bool isSuperOrSubRegisterEq(unsigned RegA, unsigned RegB) const { + return isSubRegisterEq(RegA, RegB) || isSuperRegister(RegA, RegB); + } }; //===----------------------------------------------------------------------===// diff --git a/include/llvm/MC/MCSchedule.h b/include/llvm/MC/MCSchedule.h index d7f9b69a9a2c..37728797f626 100644 --- a/include/llvm/MC/MCSchedule.h +++ b/include/llvm/MC/MCSchedule.h @@ -165,9 +165,6 @@ struct MCSchedModel { static const unsigned DefaultLoopMicroOpBufferSize = 0; // LoadLatency is the expected latency of load instructions. - // - // If MinLatency >= 0, this may be overriden for individual load opcodes by - // InstrItinerary OperandCycles. unsigned LoadLatency; static const unsigned DefaultLoadLatency = 4; @@ -175,7 +172,6 @@ struct MCSchedModel { // See TargetInstrInfo::isHighLatencyDef(). // By default, this is set to an arbitrarily high number of cycles // likely to have some impact on scheduling heuristics. - // If MinLatency >= 0, this may be overriden by InstrItinData OperandCycles. unsigned HighLatency; static const unsigned DefaultHighLatency = 10; diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index 09a98929113a..a8d7af9bd651 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -15,7 +15,6 @@ #define LLVM_MC_MCSECTION_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/MC/MCFragment.h" diff --git a/include/llvm/MC/MCSectionCOFF.h b/include/llvm/MC/MCSectionCOFF.h index d94682c8c381..c9fd8ea1605d 100644 --- a/include/llvm/MC/MCSectionCOFF.h +++ b/include/llvm/MC/MCSectionCOFF.h @@ -32,6 +32,13 @@ class MCSectionCOFF final : public MCSection { /// below. mutable unsigned Characteristics; + /// The unique IDs used with the .pdata and .xdata sections created internally + /// by the assembler. This ID is used to ensure that for every .text section, + /// there is exactly one .pdata and one .xdata section, which is required by + /// the Microsoft incremental linker. This data is mutable because this ID is + /// not notionally part of the section. + mutable unsigned WinCFISectionID = ~0U; + /// The COMDAT symbol of this section. Only valid if this is a COMDAT section. /// Two COMDAT sections are merged if they have the same COMDAT symbol. MCSymbol *COMDATSymbol; @@ -71,6 +78,12 @@ public: bool UseCodeAlign() const override; bool isVirtualSection() const override; + unsigned getOrAssignWinCFISectionID(unsigned *NextID) const { + if (WinCFISectionID == ~0U) + WinCFISectionID = (*NextID)++; + return WinCFISectionID; + } + static bool classof(const MCSection *S) { return S->getVariant() == SV_COFF; } }; diff --git a/include/llvm/MC/MCSectionELF.h b/include/llvm/MC/MCSectionELF.h index b3bb3ad4e02c..dabd787b0d45 100644 --- a/include/llvm/MC/MCSectionELF.h +++ b/include/llvm/MC/MCSectionELF.h @@ -75,6 +75,7 @@ public: unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } + void setFlags(unsigned F) { Flags = F; } const MCSymbolELF *getGroup() const { return Group; } void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 04d143ffef66..cd710ee43425 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -183,6 +183,12 @@ class MCStreamer { /// PushSection. SmallVector<std::pair<MCSectionSubPair, MCSectionSubPair>, 4> SectionStack; + /// The next unique ID to use when creating a WinCFI-related section (.pdata + /// or .xdata). This ID ensures that we have a one-to-one mapping from + /// code section to unwind info section, which MSVC's incremental linker + /// requires. + unsigned NextWinCFIID = 0; + protected: MCStreamer(MCContext &Ctx); @@ -222,6 +228,8 @@ public: return DwarfFrameInfos; } + bool hasUnfinishedDwarfFrameInfo(); + unsigned getNumWinFrameInfos() { return WinFrameInfos.size(); } ArrayRef<WinEH::FrameInfo *> getWinFrameInfos() const { return WinFrameInfos; @@ -244,7 +252,7 @@ public: /// correctly? virtual bool isIntegratedAssemblerRequired() const { return false; } - /// \brief Add a textual command. + /// \brief Add a textual comment. /// /// Typically for comments that can be emitted to the generated .s /// file if applicable as a QoI issue to make the output of the compiler @@ -266,6 +274,12 @@ public: /// only prints comments, the object streamer ignores it instead of asserting. virtual void emitRawComment(const Twine &T, bool TabPrefix = true); + /// \brief Add explicit comment T. T is required to be a valid + /// comment in the output and does not need to be escaped. + virtual void addExplicitComment(const Twine &T); + /// \brief Emit added explicit comments. + virtual void emitExplicitComments(); + /// AddBlankLine - Emit a blank line to a .s file to pretty it up. virtual void AddBlankLine() {} @@ -515,6 +529,10 @@ public: /// etc. virtual void EmitBytes(StringRef Data); + /// Functionally identical to EmitBytes. When emitting textual assembly, this + /// method uses .byte directives instead of .ascii or .asciz for readability. + virtual void EmitBinaryData(StringRef Data); + /// \brief Emit the expression \p Value into the output as a native /// integer of the given \p Size bytes. /// @@ -567,7 +585,29 @@ public: /// \brief Emit NumBytes bytes worth of the value specified by FillValue. /// This implements directives such as '.space'. - virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue); + virtual void emitFill(uint64_t NumBytes, uint8_t FillValue); + + /// \brief Emit \p Size bytes worth of the value specified by \p FillValue. + /// + /// This is used to implement assembler directives such as .space or .skip. + /// + /// \param NumBytes - The number of bytes to emit. + /// \param FillValue - The value to use when filling bytes. + /// \param Loc - The location of the expression for error reporting. + virtual void emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc = SMLoc()); + + /// \brief Emit \p NumValues copies of \p Size bytes. Each \p Size bytes is + /// taken from the lowest order 4 bytes of \p Expr expression. + /// + /// This is used to implement assembler directives such as .fill. + /// + /// \param NumValues - The number of copies of \p Size bytes to emit. + /// \param Size - The size (in bytes) of each repeated value. + /// \param Expr - The expression from which \p Size bytes are used. + virtual void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr); + virtual void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, + SMLoc Loc = SMLoc()); /// \brief Emit NumBytes worth of zeros. /// This function properly handles data in virtual sections. @@ -640,6 +680,40 @@ public: unsigned Isa, unsigned Discriminator, StringRef FileName); + /// \brief Associate a filename with a specified logical file number. This + /// implements the '.cv_file 4 "foo.c"' assembler directive. + virtual unsigned EmitCVFileDirective(unsigned FileNo, StringRef Filename); + + /// \brief This implements the CodeView '.cv_loc' assembler directive. + virtual void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, + unsigned Line, unsigned Column, + bool PrologueEnd, bool IsStmt, + StringRef FileName); + + /// \brief This implements the CodeView '.cv_linetable' assembler directive. + virtual void EmitCVLinetableDirective(unsigned FunctionId, + const MCSymbol *FnStart, + const MCSymbol *FnEnd); + + /// \brief This implements the CodeView '.cv_inline_linetable' assembler + /// directive. + virtual void EmitCVInlineLinetableDirective( + unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, + const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, + ArrayRef<unsigned> SecondaryFunctionIds); + + /// \brief This implements the CodeView '.cv_def_range' assembler + /// directive. + virtual void EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion); + + /// \brief This implements the CodeView '.cv_stringtable' assembler directive. + virtual void EmitCVStringTableDirective() {} + + /// \brief This implements the CodeView '.cv_filechecksums' assembler directive. + virtual void EmitCVFileChecksumsDirective() {} + /// Emit the absolute difference between two symbols. /// /// \pre Offset of \c Hi is greater than the offset \c Lo. @@ -684,6 +758,14 @@ public: virtual void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except); virtual void EmitWinEHHandlerData(); + /// Get the .pdata section used for the given section. Typically the given + /// section is either the main .text section or some other COMDAT .text + /// section, but it may be any section containing code. + MCSection *getAssociatedPDataSection(const MCSection *TextSec); + + /// Get the .xdata section used for the given section. + MCSection *getAssociatedXDataSection(const MCSection *TextSec); + virtual void EmitSyntaxDirective(); /// \brief Emit a .reloc directive. diff --git a/include/llvm/MC/MCSubtargetInfo.h b/include/llvm/MC/MCSubtargetInfo.h index 446feefc4500..5ede043fa2ee 100644 --- a/include/llvm/MC/MCSubtargetInfo.h +++ b/include/llvm/MC/MCSubtargetInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_MC_MCSUBTARGETINFO_H #define LLVM_MC_MCSUBTARGETINFO_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/MC/SubtargetFeature.h" #include <string> diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index c51ecfcb0c5c..23e34b7869a5 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -17,7 +17,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringMap.h" -#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCFragment.h" #include "llvm/Support/Compiler.h" namespace llvm { @@ -87,7 +87,7 @@ protected: /// IsUsed - True if this symbol has been used. mutable unsigned IsUsed : 1; - mutable bool IsRegistered : 1; + mutable unsigned IsRegistered : 1; /// This symbol is visible outside this translation unit. mutable unsigned IsExternal : 1; diff --git a/include/llvm/MC/MCSymbolMachO.h b/include/llvm/MC/MCSymbolMachO.h index 5b0321fe9f73..25220e4a8109 100644 --- a/include/llvm/MC/MCSymbolMachO.h +++ b/include/llvm/MC/MCSymbolMachO.h @@ -9,6 +9,7 @@ #ifndef LLVM_MC_MCSYMBOLMACHO_H #define LLVM_MC_MCSYMBOLMACHO_H +#include "llvm/ADT/Twine.h" #include "llvm/MC/MCSymbol.h" namespace llvm { @@ -33,6 +34,7 @@ class MCSymbolMachO : public MCSymbol { SF_WeakReference = 0x0040, SF_WeakDefinition = 0x0080, SF_SymbolResolver = 0x0100, + SF_AltEntry = 0x0200, // Common alignment SF_CommonAlignmentMask = 0xF0FF, @@ -88,6 +90,14 @@ public: modifyFlags(SF_SymbolResolver, SF_SymbolResolver); } + void setAltEntry() const { + modifyFlags(SF_AltEntry, SF_AltEntry); + } + + bool isAltEntry() const { + return getFlags() & SF_AltEntry; + } + void setDesc(unsigned Value) const { assert(Value == (Value & SF_DescFlagsMask) && "Invalid .desc value!"); @@ -96,7 +106,7 @@ public: /// \brief Get the encoded value of the flags as they will be emitted in to /// the MachO binary - uint16_t getEncodedFlags() const { + uint16_t getEncodedFlags(bool EncodeAsAltEntry) const { uint16_t Flags = getFlags(); // Common alignment is packed into the 'desc' bits. @@ -113,6 +123,9 @@ public: } } + if (EncodeAsAltEntry) + Flags |= SF_AltEntry; + return Flags; } diff --git a/include/llvm/MC/MCTargetOptions.h b/include/llvm/MC/MCTargetOptions.h index 4b66a750cb7d..1d170b757cb3 100644 --- a/include/llvm/MC/MCTargetOptions.h +++ b/include/llvm/MC/MCTargetOptions.h @@ -36,6 +36,10 @@ public: bool ShowMCEncoding : 1; bool ShowMCInst : 1; bool AsmVerbose : 1; + + /// Preserve Comments in Assembly. + bool PreserveAsmComments : 1; + int DwarfVersion; /// getABIName - If this returns a non-empty string this represents the /// textual name of the ABI that we want the backend to use, e.g. o32, or diff --git a/include/llvm/MC/MCWin64EH.h b/include/llvm/MC/MCWin64EH.h index 0e81a191cd2c..83ea738de8c3 100644 --- a/include/llvm/MC/MCWin64EH.h +++ b/include/llvm/MC/MCWin64EH.h @@ -17,7 +17,6 @@ #include "llvm/MC/MCWinEH.h" #include "llvm/Support/Win64EH.h" -#include <vector> namespace llvm { class MCStreamer; diff --git a/include/llvm/MC/MCWinEH.h b/include/llvm/MC/MCWinEH.h index 723d7a397c49..4ca52a6654eb 100644 --- a/include/llvm/MC/MCWinEH.h +++ b/include/llvm/MC/MCWinEH.h @@ -13,11 +13,9 @@ #include <vector> namespace llvm { -class MCContext; class MCSection; class MCStreamer; class MCSymbol; -class StringRef; namespace WinEH { struct Instruction { @@ -31,50 +29,35 @@ struct Instruction { }; struct FrameInfo { - const MCSymbol *Begin; - const MCSymbol *End; - const MCSymbol *ExceptionHandler; - const MCSymbol *Function; - const MCSymbol *PrologEnd; - const MCSymbol *Symbol; + const MCSymbol *Begin = nullptr; + const MCSymbol *End = nullptr; + const MCSymbol *ExceptionHandler = nullptr; + const MCSymbol *Function = nullptr; + const MCSymbol *PrologEnd = nullptr; + const MCSymbol *Symbol = nullptr; + const MCSection *TextSection = nullptr; - bool HandlesUnwind; - bool HandlesExceptions; + bool HandlesUnwind = false; + bool HandlesExceptions = false; - int LastFrameInst; - const FrameInfo *ChainedParent; + int LastFrameInst = -1; + const FrameInfo *ChainedParent = nullptr; std::vector<Instruction> Instructions; - FrameInfo() - : Begin(nullptr), End(nullptr), ExceptionHandler(nullptr), - Function(nullptr), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(nullptr), Instructions() {} + FrameInfo() = default; FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel) - : Begin(BeginFuncEHLabel), End(nullptr), ExceptionHandler(nullptr), - Function(Function), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(nullptr), Instructions() {} + : Begin(BeginFuncEHLabel), Function(Function) {} FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel, const FrameInfo *ChainedParent) - : Begin(BeginFuncEHLabel), End(nullptr), ExceptionHandler(nullptr), - Function(Function), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(ChainedParent), Instructions() {} + : Begin(BeginFuncEHLabel), Function(Function), + ChainedParent(ChainedParent) {} }; class UnwindEmitter { public: - static MCSection *getPDataSection(const MCSymbol *Function, - MCContext &Context); - static MCSection *getXDataSection(const MCSymbol *Function, - MCContext &Context); + virtual ~UnwindEmitter(); - virtual ~UnwindEmitter() { } - - // - // This emits the unwind info sections (.pdata and .xdata in PE/COFF). - // + /// This emits the unwind info sections (.pdata and .xdata in PE/COFF). virtual void Emit(MCStreamer &Streamer) const = 0; virtual void EmitUnwindInfo(MCStreamer &Streamer, FrameInfo *FI) const = 0; }; diff --git a/include/llvm/MC/SectionKind.h b/include/llvm/MC/SectionKind.h index b09b93cfc377..02fb22623cf7 100644 --- a/include/llvm/MC/SectionKind.h +++ b/include/llvm/MC/SectionKind.h @@ -63,6 +63,10 @@ class SectionKind { /// for example, vectors. MergeableConst16, + /// MergeableConst32 - This is a section used by 32-byte constants, + /// for example, vectors. + MergeableConst32, + /// Writeable - This is the base of all segments that need to be written /// to during program runtime. @@ -125,11 +129,12 @@ public: bool isMergeableConst() const { return K == MergeableConst4 || K == MergeableConst8 || - K == MergeableConst16; + K == MergeableConst16 || K == MergeableConst32; } bool isMergeableConst4() const { return K == MergeableConst4; } bool isMergeableConst8() const { return K == MergeableConst8; } bool isMergeableConst16() const { return K == MergeableConst16; } + bool isMergeableConst32() const { return K == MergeableConst32; } bool isWriteable() const { return isThreadLocal() || isGlobalWriteableData(); @@ -180,6 +185,7 @@ public: static SectionKind getMergeableConst4() { return get(MergeableConst4); } static SectionKind getMergeableConst8() { return get(MergeableConst8); } static SectionKind getMergeableConst16() { return get(MergeableConst16); } + static SectionKind getMergeableConst32() { return get(MergeableConst32); } static SectionKind getThreadBSS() { return get(ThreadBSS); } static SectionKind getThreadData() { return get(ThreadData); } static SectionKind getBSS() { return get(BSS); } diff --git a/include/llvm/MC/StringTableBuilder.h b/include/llvm/MC/StringTableBuilder.h index adde86b45583..f2b8ecd2d997 100644 --- a/include/llvm/MC/StringTableBuilder.h +++ b/include/llvm/MC/StringTableBuilder.h @@ -23,12 +23,15 @@ public: private: SmallString<256> StringTable; - DenseMap<StringRef, size_t> StringIndexMap; + DenseMap<CachedHash<StringRef>, size_t> StringIndexMap; size_t Size = 0; Kind K; + unsigned Alignment; + + void finalizeStringTable(bool Optimize); public: - StringTableBuilder(Kind K); + StringTableBuilder(Kind K, unsigned Alignment = 1); /// \brief Add a string to the builder. Returns the position of S in the /// table. The position will be changed if finalize is used. @@ -39,6 +42,10 @@ public: /// be added after this point. void finalize(); + /// Finalize the string table without reording it. In this mode, offsets + /// returned by add will still be valid. + void finalizeInOrder(); + /// \brief Retrieve the string table data. Can only be used after the table /// is finalized. StringRef data() const { @@ -50,7 +57,10 @@ public: /// after the table is finalized. size_t getOffset(StringRef S) const; - const DenseMap<StringRef, size_t> &getMap() const { return StringIndexMap; } + const DenseMap<CachedHash<StringRef>, size_t> &getMap() const { + return StringIndexMap; + } + size_t getSize() const { return Size; } void clear(); diff --git a/include/llvm/MC/SubtargetFeature.h b/include/llvm/MC/SubtargetFeature.h index 75d1e7997119..ed4abd772821 100644 --- a/include/llvm/MC/SubtargetFeature.h +++ b/include/llvm/MC/SubtargetFeature.h @@ -18,12 +18,13 @@ #ifndef LLVM_MC_SUBTARGETFEATURE_H #define LLVM_MC_SUBTARGETFEATURE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/DataTypes.h" #include <bitset> +#include <vector> namespace llvm { +template <typename T> class ArrayRef; class raw_ostream; class StringRef; diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 8dd042a2533f..cfba2567371a 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -14,6 +14,7 @@ #ifndef LLVM_OBJECT_ARCHIVE_H #define LLVM_OBJECT_ARCHIVE_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/Binary.h" @@ -42,7 +43,7 @@ struct ArchiveMemberHeader { sys::fs::perms getAccessMode() const; sys::TimeValue getLastModified() const; llvm::StringRef getRawLastModified() const { - return StringRef(LastModified, sizeof(LastModified)).rtrim(" "); + return StringRef(LastModified, sizeof(LastModified)).rtrim(' '); } unsigned getUID() const; unsigned getGID() const; @@ -78,6 +79,7 @@ public: ErrorOr<Child> getNext() const; ErrorOr<StringRef> getName() const; + ErrorOr<std::string> getFullName() const; StringRef getRawName() const { return getHeader()->getName(); } sys::TimeValue getLastModified() const { return getHeader()->getLastModified(); @@ -100,26 +102,25 @@ public: ErrorOr<MemoryBufferRef> getMemoryBufferRef() const; - ErrorOr<std::unique_ptr<Binary>> + Expected<std::unique_ptr<Binary>> getAsBinary(LLVMContext *Context = nullptr) const; }; class child_iterator { - ErrorOr<Child> child; + Child C; + Error *E; public: - child_iterator() : child(Child(nullptr, nullptr, nullptr)) {} - child_iterator(const Child &c) : child(c) {} - child_iterator(std::error_code EC) : child(EC) {} - const ErrorOr<Child> *operator->() const { return &child; } - const ErrorOr<Child> &operator*() const { return child; } + child_iterator() : C(Child(nullptr, nullptr, nullptr)), E(nullptr) {} + child_iterator(const Child &C, Error *E) : C(C), E(E) {} + const Child *operator->() const { return &C; } + const Child &operator*() const { return C; } bool operator==(const child_iterator &other) const { - // We ignore error states so that comparisions with end() work, which - // allows range loops. - if (child.getError() || other.child.getError()) - return false; - return *child == *other.child; + // Ignore errors here: If an error occurred during increment then getNext + // will have been set to child_end(), and the following comparison should + // do the right thing. + return C == other.C; } bool operator!=(const child_iterator &other) const { @@ -129,8 +130,15 @@ public: // Code in loops with child_iterators must check for errors on each loop // iteration. And if there is an error break out of the loop. child_iterator &operator++() { // Preincrement - assert(child && "Can't increment iterator with error"); - child = child->getNext(); + assert(E && "Can't increment iterator with no Error attached"); + if (auto ChildOrErr = C.getNext()) + C = *ChildOrErr; + else { + ErrorAsOutParameter ErrAsOutParam(*E); + C = C.getParent()->child_end().C; + *E = errorCodeToError(ChildOrErr.getError()); + E = nullptr; + } return *this; } }; @@ -175,23 +183,25 @@ public: } }; - Archive(MemoryBufferRef Source, std::error_code &EC); - static ErrorOr<std::unique_ptr<Archive>> create(MemoryBufferRef Source); + Archive(MemoryBufferRef Source, Error &Err); + static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source); enum Kind { K_GNU, K_MIPS64, K_BSD, + K_DARWIN64, K_COFF }; Kind kind() const { return (Kind)Format; } bool isThin() const { return IsThin; } - child_iterator child_begin(bool SkipInternal = true) const; + child_iterator child_begin(Error &Err, bool SkipInternal = true) const; child_iterator child_end() const; - iterator_range<child_iterator> children(bool SkipInternal = true) const { - return make_range(child_begin(SkipInternal), child_end()); + iterator_range<child_iterator> children(Error &Err, + bool SkipInternal = true) const { + return make_range(child_begin(Err, SkipInternal), child_end()); } symbol_iterator symbol_begin() const; @@ -206,12 +216,16 @@ public: } // check if a symbol is in the archive - child_iterator findSym(StringRef name) const; + Expected<Optional<Child>> findSym(StringRef name) const; bool hasSymbolTable() const; StringRef getSymbolTable() const { return SymbolTable; } uint32_t getNumberOfSymbols() const; + std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() { + return std::move(ThinBuffers); + } + private: StringRef SymbolTable; StringRef StringTable; @@ -220,7 +234,7 @@ private: uint16_t FirstRegularStartOfFile = -1; void setFirstRegular(const Child &C); - unsigned Format : 2; + unsigned Format : 3; unsigned IsThin : 1; mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; }; diff --git a/include/llvm/Object/ArchiveWriter.h b/include/llvm/Object/ArchiveWriter.h index b5d2ba358080..55b58fac4f66 100644 --- a/include/llvm/Object/ArchiveWriter.h +++ b/include/llvm/Object/ArchiveWriter.h @@ -20,29 +20,36 @@ namespace llvm { -class NewArchiveIterator { - bool IsNewMember; - StringRef Name; - - object::Archive::Child OldMember; - -public: - NewArchiveIterator(const object::Archive::Child &OldMember, StringRef Name); - NewArchiveIterator(StringRef FileName); - bool isNewMember() const; - StringRef getName() const; - - const object::Archive::Child &getOld() const; - - StringRef getNew() const; - llvm::ErrorOr<int> getFD(sys::fs::file_status &NewStatus) const; - const sys::fs::file_status &getStatus() const; +struct NewArchiveMember { + std::unique_ptr<MemoryBuffer> Buf; + sys::TimeValue ModTime = sys::TimeValue::PosixZeroTime(); + unsigned UID = 0, GID = 0, Perms = 0644; + + NewArchiveMember() = default; + NewArchiveMember(NewArchiveMember &&Other) + : Buf(std::move(Other.Buf)), ModTime(Other.ModTime), UID(Other.UID), + GID(Other.GID), Perms(Other.Perms) {} + NewArchiveMember &operator=(NewArchiveMember &&Other) { + Buf = std::move(Other.Buf); + ModTime = Other.ModTime; + UID = Other.UID; + GID = Other.GID; + Perms = Other.Perms; + return *this; + } + NewArchiveMember(MemoryBufferRef BufRef); + + static Expected<NewArchiveMember> + getOldMember(const object::Archive::Child &OldMember, bool Deterministic); + + static Expected<NewArchiveMember> getFile(StringRef FileName, + bool Deterministic); }; std::pair<StringRef, std::error_code> -writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers, +writeArchive(StringRef ArcName, std::vector<NewArchiveMember> &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin); + bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf = nullptr); } #endif diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index a0d1127781f6..5dff5406fcdd 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -42,8 +42,8 @@ protected: ID_Archive, ID_MachOUniversalBinary, ID_COFFImportFile, - ID_IR, // LLVM IR - ID_FunctionIndex, // Function summary index + ID_IR, // LLVM IR + ID_ModuleSummaryIndex, // Module summary index // Object and children. ID_StartObjects, @@ -123,7 +123,7 @@ public: return TypeID == ID_IR; } - bool isFunctionIndex() const { return TypeID == ID_FunctionIndex; } + bool isModuleSummaryIndex() const { return TypeID == ID_ModuleSummaryIndex; } bool isLittleEndian() const { return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || @@ -134,8 +134,8 @@ public: /// @brief Create a Binary from Source, autodetecting the file type. /// /// @param Source The data to create the Binary from. -ErrorOr<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source, - LLVMContext *Context = nullptr); +Expected<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source, + LLVMContext *Context = nullptr); template <typename T> class OwningBinary { std::unique_ptr<T> Bin; @@ -185,7 +185,7 @@ template <typename T> const T* OwningBinary<T>::getBinary() const { return Bin.get(); } -ErrorOr<OwningBinary<Binary>> createBinary(StringRef Path); +Expected<OwningBinary<Binary>> createBinary(StringRef Path); } } diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 3e69c3e6e5d4..dcc58b06e228 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -169,6 +169,26 @@ struct import_directory_table_entry { support::ulittle32_t ImportAddressTableRVA; }; +struct debug_directory { + support::ulittle32_t Characteristics; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t Type; + support::ulittle32_t SizeOfData; + support::ulittle32_t AddressOfRawData; + support::ulittle32_t PointerToRawData; +}; + +/// Information that is resent in debug_directory::AddressOfRawData if Type is +/// IMAGE_DEBUG_TYPE_CODEVIEW. +struct debug_pdb_info { + support::ulittle32_t Signature; + uint8_t Guid[16]; + support::ulittle32_t Age; + // PDBFileName: The null-terminated PDB file name follows. +}; + template <typename IntTy> struct import_lookup_table_entry { IntTy Data; @@ -414,6 +434,18 @@ struct coff_section { return (Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL) && NumberOfRelocations == UINT16_MAX; } + uint32_t getAlignment() const { + // The IMAGE_SCN_TYPE_NO_PAD bit is a legacy way of getting to + // IMAGE_SCN_ALIGN_1BYTES. + if (Characteristics & COFF::IMAGE_SCN_TYPE_NO_PAD) + return 1; + + // Bit [20:24] contains section alignment. Both 0 and 1 mean alignment 1. + uint32_t Shift = (Characteristics >> 20) & 0xF; + if (Shift > 0) + return 1U << (Shift - 1); + return 1; + } }; struct coff_relocation { @@ -427,20 +459,32 @@ struct coff_aux_function_definition { support::ulittle32_t TotalSize; support::ulittle32_t PointerToLinenumber; support::ulittle32_t PointerToNextFunction; + char Unused1[2]; }; +static_assert(sizeof(coff_aux_function_definition) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_bf_and_ef_symbol { char Unused1[4]; support::ulittle16_t Linenumber; char Unused2[6]; support::ulittle32_t PointerToNextFunction; + char Unused3[2]; }; +static_assert(sizeof(coff_aux_bf_and_ef_symbol) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_weak_external { support::ulittle32_t TagIndex; support::ulittle32_t Characteristics; + char Unused1[10]; }; +static_assert(sizeof(coff_aux_weak_external) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_section_definition { support::ulittle32_t Length; support::ulittle16_t NumberOfRelocations; @@ -458,12 +502,19 @@ struct coff_aux_section_definition { } }; +static_assert(sizeof(coff_aux_section_definition) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_clr_token { uint8_t AuxType; uint8_t Reserved; support::ulittle32_t SymbolTableIndex; + char MBZ[12]; }; +static_assert(sizeof(coff_aux_clr_token) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_import_header { support::ulittle16_t Sig1; support::ulittle16_t Sig2; @@ -485,6 +536,26 @@ struct coff_import_directory_table_entry { support::ulittle32_t ImportAddressTableRVA; }; +template <typename IntTy> +struct coff_tls_directory { + IntTy StartAddressOfRawData; + IntTy EndAddressOfRawData; + IntTy AddressOfIndex; + IntTy AddressOfCallBacks; + support::ulittle32_t SizeOfZeroFill; + support::ulittle32_t Characteristics; + uint32_t getAlignment() const { + // Bit [20:24] contains section alignment. + uint32_t Shift = (Characteristics & 0x00F00000) >> 20; + if (Shift > 0) + return 1U << (Shift - 1); + return 0; + } +}; + +typedef coff_tls_directory<support::little32_t> coff_tls_directory32; +typedef coff_tls_directory<support::little64_t> coff_tls_directory64; + struct coff_load_configuration32 { support::ulittle32_t Characteristics; support::ulittle32_t TimeDateStamp; @@ -563,12 +634,13 @@ private: const char *StringTable; uint32_t StringTableSize; const import_directory_table_entry *ImportDirectory; - uint32_t NumberOfImportDirectory; const delay_import_directory_table_entry *DelayImportDirectory; uint32_t NumberOfDelayImportDirectory; const export_directory_table_entry *ExportDirectory; const coff_base_reloc_block_header *BaseRelocHeader; const coff_base_reloc_block_header *BaseRelocEnd; + const debug_directory *DebugDirectoryBegin; + const debug_directory *DebugDirectoryEnd; std::error_code getString(uint32_t offset, StringRef &Res) const; @@ -582,6 +654,7 @@ private: std::error_code initDelayImportTablePtr(); std::error_code initExportTablePtr(); std::error_code initBaseRelocPtr(); + std::error_code initDebugDirectoryPtr(); public: uintptr_t getSymbolTable() const { @@ -647,13 +720,13 @@ public: } protected: void moveSymbolNext(DataRefImpl &Symb) const override; - ErrorOr<StringRef> getSymbolName(DataRefImpl Symb) const override; - ErrorOr<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; - SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; - ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, StringRef &Res) const override; @@ -662,6 +735,7 @@ protected: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -693,6 +767,7 @@ public: uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; unsigned getArch() const override; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } import_directory_iterator import_directory_begin() const; import_directory_iterator import_directory_end() const; @@ -702,12 +777,21 @@ public: export_directory_iterator export_directory_end() const; base_reloc_iterator base_reloc_begin() const; base_reloc_iterator base_reloc_end() const; + const debug_directory *debug_directory_begin() const { + return DebugDirectoryBegin; + } + const debug_directory *debug_directory_end() const { + return DebugDirectoryEnd; + } iterator_range<import_directory_iterator> import_directories() const; iterator_range<delay_import_directory_iterator> delay_import_directories() const; iterator_range<export_directory_iterator> export_directories() const; iterator_range<base_reloc_iterator> base_relocs() const; + iterator_range<const debug_directory *> debug_directories() const { + return make_range(debug_directory_begin(), debug_directory_end()); + } const dos_header *getDOSHeader() const { if (!PE32Header && !PE32PlusHeader) @@ -776,9 +860,28 @@ public: uint64_t getImageBase() const; std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const; std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const; + + /// Given an RVA base and size, returns a valid array of bytes or an error + /// code if the RVA and size is not contained completely within a valid + /// section. + std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, + ArrayRef<uint8_t> &Contents) const; + std::error_code getHintName(uint32_t Rva, uint16_t &Hint, StringRef &Name) const; + /// Get PDB information out of a codeview debug directory entry. + std::error_code getDebugPDBInfo(const debug_directory *DebugDir, + const debug_pdb_info *&Info, + StringRef &PDBFileName) const; + + /// Get PDB information from an executable. If the information is not present, + /// Info will be set to nullptr and PDBFileName will be empty. An error is + /// returned only on corrupt object files. Convenience accessor that can be + /// used if the debug directory is not already handy. + std::error_code getDebugPDBInfo(const debug_pdb_info *&Info, + StringRef &PDBFileName) const; + bool isRelocatableObject() const override; bool is64() const { return PE32PlusHeader; } @@ -807,9 +910,6 @@ public: std::error_code getImportTableEntry(const import_directory_table_entry *&Result) const; - std::error_code - getImportLookupEntry(const import_lookup_table_entry32 *&Result) const; - private: const import_directory_table_entry *ImportTable; uint32_t Index; @@ -881,7 +981,9 @@ public: void moveNext(); std::error_code getSymbolName(StringRef &Result) const; + std::error_code isOrdinal(bool &Result) const; std::error_code getOrdinal(uint16_t &Result) const; + std::error_code getHintNameRVA(uint32_t &Result) const; private: const import_lookup_table_entry32 *Entry32; @@ -909,6 +1011,30 @@ private: const COFFObjectFile *OwningObject; }; +// Corresponds to `_FPO_DATA` structure in the PE/COFF spec. +struct FpoData { + support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code + support::ulittle32_t Size; // cbProcSize: # bytes in function + support::ulittle32_t NumLocals; // cdwLocals: # bytes in locals/4 + support::ulittle16_t NumParams; // cdwParams: # bytes in params/4 + support::ulittle16_t Attributes; + + // cbProlog: # bytes in prolog + int getPrologSize() const { return Attributes & 0xF; } + + // cbRegs: # regs saved + int getNumSavedRegs() const { return (Attributes >> 8) & 0x7; } + + // fHasSEH: true if seh is func + bool hasSEH() const { return (Attributes >> 9) & 1; } + + // fUseBP: true if EBP has been allocated + bool useBP() const { return (Attributes >> 10) & 1; } + + // cbFrame: frame pointer + int getFP() const { return Attributes >> 14; } +}; + } // end namespace object } // end namespace llvm diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index b0eaa3f5ed4d..80b8be03810c 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -54,14 +54,19 @@ public: typedef Elf_Versym_Impl<ELFT> Elf_Versym; typedef Elf_Hash_Impl<ELFT> Elf_Hash; typedef Elf_GnuHash_Impl<ELFT> Elf_GnuHash; - typedef iterator_range<const Elf_Dyn *> Elf_Dyn_Range; - typedef iterator_range<const Elf_Shdr *> Elf_Shdr_Range; - typedef iterator_range<const Elf_Sym *> Elf_Sym_Range; + typedef typename ELFT::DynRange Elf_Dyn_Range; + typedef typename ELFT::ShdrRange Elf_Shdr_Range; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::RelRange Elf_Rel_Range; + typedef typename ELFT::RelaRange Elf_Rela_Range; + typedef typename ELFT::PhdrRange Elf_Phdr_Range; const uint8_t *base() const { return reinterpret_cast<const uint8_t *>(Buf.data()); } + size_t getBufSize() const { return Buf.size(); } + private: StringRef Buf; @@ -104,22 +109,10 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } - ErrorOr<const Elf_Dyn *> dynamic_table_begin(const Elf_Phdr *Phdr) const; - ErrorOr<const Elf_Dyn *> dynamic_table_end(const Elf_Phdr *Phdr) const; - ErrorOr<Elf_Dyn_Range> dynamic_table(const Elf_Phdr *Phdr) const { - ErrorOr<const Elf_Dyn *> Begin = dynamic_table_begin(Phdr); - if (std::error_code EC = Begin.getError()) - return EC; - ErrorOr<const Elf_Dyn *> End = dynamic_table_end(Phdr); - if (std::error_code EC = End.getError()) - return EC; - return make_range(*Begin, *End); - } - const Elf_Shdr *section_begin() const; const Elf_Shdr *section_end() const; Elf_Shdr_Range sections() const { - return make_range(section_begin(), section_end()); + return makeArrayRef(section_begin(), section_end()); } const Elf_Sym *symbol_begin(const Elf_Shdr *Sec) const { @@ -138,11 +131,9 @@ public: return symbol_begin(Sec) + Size / sizeof(Elf_Sym); } Elf_Sym_Range symbols(const Elf_Shdr *Sec) const { - return make_range(symbol_begin(Sec), symbol_end(Sec)); + return makeArrayRef(symbol_begin(Sec), symbol_end(Sec)); } - typedef iterator_range<const Elf_Rela *> Elf_Rela_Range; - const Elf_Rela *rela_begin(const Elf_Shdr *sec) const { if (sec->sh_entsize != sizeof(Elf_Rela)) report_fatal_error("Invalid relocation entry size"); @@ -157,7 +148,7 @@ public: } Elf_Rela_Range relas(const Elf_Shdr *Sec) const { - return make_range(rela_begin(Sec), rela_end(Sec)); + return makeArrayRef(rela_begin(Sec), rela_end(Sec)); } const Elf_Rel *rel_begin(const Elf_Shdr *sec) const { @@ -173,9 +164,8 @@ public: return rel_begin(sec) + Size / sizeof(Elf_Rel); } - typedef iterator_range<const Elf_Rel *> Elf_Rel_Range; Elf_Rel_Range rels(const Elf_Shdr *Sec) const { - return make_range(rel_begin(Sec), rel_end(Sec)); + return makeArrayRef(rel_begin(Sec), rel_end(Sec)); } /// \brief Iterate over program header table. @@ -189,10 +179,8 @@ public: return program_header_begin() + Header->e_phnum; } - typedef iterator_range<const Elf_Phdr *> Elf_Phdr_Range; - const Elf_Phdr_Range program_headers() const { - return make_range(program_header_begin(), program_header_end()); + return makeArrayRef(program_header_begin(), program_header_end()); } uint64_t getNumSections() const; @@ -200,6 +188,9 @@ public: uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef<Elf_Word> ShndxTable) const; + uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, + const Elf_Sym *FirstSym, + ArrayRef<Elf_Word> ShndxTable) const; const Elf_Ehdr *getHeader() const { return Header; } ErrorOr<const Elf_Shdr *> getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, @@ -225,8 +216,15 @@ template <class ELFT> uint32_t ELFFile<ELFT>::getExtendedSymbolTableIndex( const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef<Elf_Word> ShndxTable) const { + return getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable); +} + +template <class ELFT> +uint32_t ELFFile<ELFT>::getExtendedSymbolTableIndex( + const Elf_Sym *Sym, const Elf_Sym *FirstSym, + ArrayRef<Elf_Word> ShndxTable) const { assert(Sym->st_shndx == ELF::SHN_XINDEX); - unsigned Index = Sym - symbol_begin(SymTab); + unsigned Index = Sym - FirstSym; // The size of the table was checked in getSHNDXTable. return ShndxTable[Index]; @@ -404,34 +402,6 @@ const typename ELFFile<ELFT>::Elf_Shdr *ELFFile<ELFT>::section_end() const { } template <class ELFT> -ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> -ELFFile<ELFT>::dynamic_table_begin(const Elf_Phdr *Phdr) const { - if (!Phdr) - return nullptr; - assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); - uintX_t Offset = Phdr->p_offset; - if (Offset > Buf.size()) - return object_error::parse_failed; - return reinterpret_cast<const Elf_Dyn *>(base() + Offset); -} - -template <class ELFT> -ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> -ELFFile<ELFT>::dynamic_table_end(const Elf_Phdr *Phdr) const { - if (!Phdr) - return nullptr; - assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); - uintX_t Size = Phdr->p_filesz; - if (Size % sizeof(Elf_Dyn)) - return object_error::elf_invalid_dynamic_table_size; - // FIKME: Check for overflow? - uintX_t End = Phdr->p_offset + Size; - if (End > Buf.size()) - return object_error::parse_failed; - return reinterpret_cast<const Elf_Dyn *>(base() + End); -} - -template <class ELFT> template <typename T> const T *ELFFile<ELFT>::getEntry(uint32_t Section, uint32_t Entry) const { ErrorOr<const Elf_Shdr *> Sec = getSection(Section); diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 5d826da4c2fc..07c6364a6894 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -14,23 +14,28 @@ #ifndef LLVM_OBJECT_ELFOBJECTFILE_H #define LLVM_OBJECT_ELFOBJECTFILE_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cctype> -#include <limits> -#include <utility> +#include <cassert> +#include <cstdint> +#include <system_error> namespace llvm { namespace object { @@ -47,6 +52,7 @@ class ELFObjectFileBase : public ObjectFile { protected: ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source); + virtual uint16_t getEMachine() const = 0; virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0; virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0; virtual uint8_t getSymbolELFType(DataRefImpl Symb) const = 0; @@ -55,14 +61,16 @@ protected: virtual uint64_t getSectionFlags(DataRefImpl Sec) const = 0; virtual ErrorOr<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0; -public: +public: typedef iterator_range<elf_symbol_iterator> elf_symbol_iterator_range; virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0; elf_symbol_iterator_range symbols() const; static inline bool classof(const Binary *v) { return v->isELF(); } + + SubtargetFeatures getFeatures() const override; }; class ELFSectionRef : public SectionRef { @@ -175,6 +183,7 @@ ELFObjectFileBase::symbols() const { } template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { + uint16_t getEMachine() const override; uint64_t getSymbolSize(DataRefImpl Sym) const override; public: @@ -197,18 +206,18 @@ protected: ArrayRef<Elf_Word> ShndxTable; void moveSymbolNext(DataRefImpl &Symb) const override; - ErrorOr<StringRef> getSymbolName(DataRefImpl Symb) const override; - ErrorOr<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; uint8_t getSymbolOther(DataRefImpl Symb) const override; uint8_t getSymbolELFType(DataRefImpl Symb) const override; - SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; - ErrorOr<section_iterator> getSymbolSection(const Elf_Sym *Symb, - const Elf_Shdr *SymTab) const; - ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(const Elf_Sym *Symb, + const Elf_Shdr *SymTab) const; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, @@ -218,6 +227,7 @@ protected: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -284,11 +294,9 @@ protected: // A symbol is exported if its binding is either GLOBAL or WEAK, and its // visibility is either DEFAULT or PROTECTED. All other symbols are not // exported. - if ((Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK) && - (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED)) - return true; - - return false; + return ((Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK) && + (Visibility == ELF::STV_DEFAULT || + Visibility == ELF::STV_PROTECTED)); } // This flag is used for classof, to distinguish ELFObjectFile from @@ -354,7 +362,7 @@ void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const { } template <class ELFT> -ErrorOr<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { +Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { const Elf_Sym *ESym = getSymbol(Sym); const Elf_Shdr *SymTableSec = *EF.getSection(Sym.d.a); const Elf_Shdr *StringTableSec = *EF.getSection(SymTableSec->sh_link); @@ -389,7 +397,7 @@ uint64_t ELFObjectFile<ELFT>::getSymbolValueImpl(DataRefImpl Symb) const { } template <class ELFT> -ErrorOr<uint64_t> +Expected<uint64_t> ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { uint64_t Result = getSymbolValue(Symb); const Elf_Sym *ESym = getSymbol(Symb); @@ -407,7 +415,7 @@ ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { ErrorOr<const Elf_Shdr *> SectionOrErr = EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = SectionOrErr.getError()) - return EC; + return errorCodeToError(EC); const Elf_Shdr *Section = *SectionOrErr; if (Section) Result += Section->sh_addr; @@ -425,6 +433,11 @@ uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const { } template <class ELFT> +uint16_t ELFObjectFile<ELFT>::getEMachine() const { + return EF.getHeader()->e_machine; +} + +template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const { return getSymbol(Sym)->st_size; } @@ -445,7 +458,8 @@ uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const { } template <class ELFT> -SymbolRef::Type ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { +Expected<SymbolRef::Type> +ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { const Elf_Sym *ESym = getSymbol(Symb); switch (ESym->getType()) { @@ -487,12 +501,17 @@ uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { Result |= SymbolRef::SF_FormatSpecific; if (EF.getHeader()->e_machine == ELF::EM_ARM) { - if (ErrorOr<StringRef> NameOrErr = getSymbolName(Sym)) { + if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) { StringRef Name = *NameOrErr; if (Name.startswith("$d") || Name.startswith("$t") || Name.startswith("$a")) Result |= SymbolRef::SF_FormatSpecific; + } else { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); } + if (ESym->getType() == ELF::STT_FUNC && (ESym->st_value & 1) == 1) + Result |= SymbolRef::SF_Thumb; } if (ESym->st_shndx == ELF::SHN_UNDEF) @@ -511,12 +530,12 @@ uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { } template <class ELFT> -ErrorOr<section_iterator> +Expected<section_iterator> ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym, const Elf_Shdr *SymTab) const { ErrorOr<const Elf_Shdr *> ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = ESecOrErr.getError()) - return EC; + return errorCodeToError(EC); const Elf_Shdr *ESec = *ESecOrErr; if (!ESec) @@ -528,7 +547,7 @@ ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym, } template <class ELFT> -ErrorOr<section_iterator> +Expected<section_iterator> ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb) const { const Elf_Sym *Sym = getSymbol(Symb); const Elf_Shdr *SymTab = *EF.getSection(Symb.d.a); @@ -576,6 +595,11 @@ uint64_t ELFObjectFile<ELFT>::getSectionAlignment(DataRefImpl Sec) const { } template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionCompressed(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED; +} + +template <class ELFT> bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const { return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; } @@ -606,22 +630,6 @@ ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const { uintptr_t SHT = reinterpret_cast<uintptr_t>(EF.section_begin()); RelData.d.a = (Sec.p - SHT) / EF.getHeader()->e_shentsize; RelData.d.b = 0; - - const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p); - if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL) - return relocation_iterator(RelocationRef(RelData, this)); - - const Elf_Shdr *RelSec = getRelSection(RelData); - ErrorOr<const Elf_Shdr *> SymSecOrErr = EF.getSection(RelSec->sh_link); - if (std::error_code EC = SymSecOrErr.getError()) - report_fatal_error(EC.message()); - const Elf_Shdr *SymSec = *SymSecOrErr; - uint32_t SymSecType = SymSec->sh_type; - if (SymSecType != ELF::SHT_SYMTAB && SymSecType != ELF::SHT_DYNSYM) - report_fatal_error("Invalid symbol table section type!"); - if (SymSecType == ELF::SHT_DYNSYM) - RelData.d.b = 1; - return relocation_iterator(RelocationRef(RelData, this)); } @@ -633,7 +641,14 @@ ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const { if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL) return Begin; DataRefImpl RelData = Begin->getRawDataRefImpl(); - RelData.d.b += (S->sh_size / S->sh_entsize) << 1; + const Elf_Shdr *RelSec = getRelSection(RelData); + + // Error check sh_link here so that getRelocationSymbol can just use it. + ErrorOr<const Elf_Shdr *> SymSecOrErr = EF.getSection(RelSec->sh_link); + if (std::error_code EC = SymSecOrErr.getError()) + report_fatal_error(EC.message()); + + RelData.d.b += S->sh_size / S->sh_entsize; return relocation_iterator(RelocationRef(RelData, this)); } @@ -657,7 +672,7 @@ ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { // Relocations template <class ELFT> void ELFObjectFile<ELFT>::moveRelocationNext(DataRefImpl &Rel) const { - Rel.d.b += 2; + ++Rel.d.b; } template <class ELFT> @@ -672,12 +687,10 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { if (!symbolIdx) return symbol_end(); - bool IsDyn = Rel.d.b & 1; + // FIXME: error check symbolIdx DataRefImpl SymbolData; - if (IsDyn) - SymbolData = toDRI(DotDynSymSec, symbolIdx); - else - SymbolData = toDRI(DotSymtabSec, symbolIdx); + SymbolData.d.a = sec->sh_link; + SymbolData.d.b = symbolIdx; return symbol_iterator(SymbolRef(SymbolData, this)); } @@ -725,14 +738,14 @@ template <class ELFT> const typename ELFObjectFile<ELFT>::Elf_Rel * ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const { assert(getRelSection(Rel)->sh_type == ELF::SHT_REL); - return EF.template getEntry<Elf_Rel>(Rel.d.a, Rel.d.b >> 1); + return EF.template getEntry<Elf_Rel>(Rel.d.a, Rel.d.b); } template <class ELFT> const typename ELFObjectFile<ELFT>::Elf_Rela * ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const { assert(getRelSection(Rela)->sh_type == ELF::SHT_RELA); - return EF.template getEntry<Elf_Rela>(Rela.d.a, Rela.d.b >> 1); + return EF.template getEntry<Elf_Rela>(Rela.d.a, Rela.d.b); } template <class ELFT> @@ -835,6 +848,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF32-avr"; case ELF::EM_HEXAGON: return "ELF32-hexagon"; + case ELF::EM_LANAI: + return "ELF32-lanai"; case ELF::EM_MIPS: return "ELF32-mips"; case ELF::EM_PPC: @@ -844,6 +859,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF32-sparc"; case ELF::EM_WEBASSEMBLY: return "ELF32-wasm"; + case ELF::EM_AMDGPU: + return "ELF32-amdgpu"; default: return "ELF32-unknown"; } @@ -865,6 +882,12 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF64-mips"; case ELF::EM_WEBASSEMBLY: return "ELF64-wasm"; + case ELF::EM_AMDGPU: + return (EF.getHeader()->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA + && IsLittleEndian) ? + "ELF64-amdgpu-hsacobj" : "ELF64-amdgpu"; + case ELF::EM_BPF: + return "ELF64-BPF"; default: return "ELF64-unknown"; } @@ -891,6 +914,8 @@ unsigned ELFObjectFile<ELFT>::getArch() const { return Triple::avr; case ELF::EM_HEXAGON: return Triple::hexagon; + case ELF::EM_LANAI: + return Triple::lanai; case ELF::EM_MIPS: switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: @@ -919,6 +944,15 @@ unsigned ELFObjectFile<ELFT>::getArch() const { default: return Triple::UnknownArch; } + case ELF::EM_AMDGPU: + return (EF.getHeader()->e_ident[ELF::EI_CLASS] == ELF::ELFCLASS64 + && EF.getHeader()->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA + && IsLittleEndian) ? + Triple::amdgcn : Triple::UnknownArch; + + case ELF::EM_BPF: + return IsLittleEndian ? Triple::bpfel : Triple::bpfeb; + default: return Triple::UnknownArch; } @@ -934,7 +968,7 @@ template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const { return EF.getHeader()->e_type == ELF::ET_REL; } -} -} +} // end namespace object +} // end namespace llvm -#endif +#endif // LLVM_OBJECT_ELFOBJECTFILE_H diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 07b312a7d77c..55028f360dbf 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -21,9 +21,60 @@ namespace object { using support::endianness; -template <endianness target_endianness, bool is64Bits> struct ELFType { - static const endianness TargetEndianness = target_endianness; - static const bool Is64Bits = is64Bits; +template <class ELFT> struct Elf_Ehdr_Impl; +template <class ELFT> struct Elf_Shdr_Impl; +template <class ELFT> struct Elf_Sym_Impl; +template <class ELFT> struct Elf_Dyn_Impl; +template <class ELFT> struct Elf_Phdr_Impl; +template <class ELFT, bool isRela> struct Elf_Rel_Impl; +template <class ELFT> struct Elf_Verdef_Impl; +template <class ELFT> struct Elf_Verdaux_Impl; +template <class ELFT> struct Elf_Verneed_Impl; +template <class ELFT> struct Elf_Vernaux_Impl; +template <class ELFT> struct Elf_Versym_Impl; +template <class ELFT> struct Elf_Hash_Impl; +template <class ELFT> struct Elf_GnuHash_Impl; +template <class ELFT> struct Elf_Chdr_Impl; + +template <endianness E, bool Is64> struct ELFType { +private: + template <typename Ty> + using packed = support::detail::packed_endian_specific_integral<Ty, E, 2>; + +public: + static const endianness TargetEndianness = E; + static const bool Is64Bits = Is64; + + typedef typename std::conditional<Is64, uint64_t, uint32_t>::type uint; + typedef Elf_Ehdr_Impl<ELFType<E, Is64>> Ehdr; + typedef Elf_Shdr_Impl<ELFType<E, Is64>> Shdr; + typedef Elf_Sym_Impl<ELFType<E, Is64>> Sym; + typedef Elf_Dyn_Impl<ELFType<E, Is64>> Dyn; + typedef Elf_Phdr_Impl<ELFType<E, Is64>> Phdr; + typedef Elf_Rel_Impl<ELFType<E, Is64>, false> Rel; + typedef Elf_Rel_Impl<ELFType<E, Is64>, true> Rela; + typedef Elf_Verdef_Impl<ELFType<E, Is64>> Verdef; + typedef Elf_Verdaux_Impl<ELFType<E, Is64>> Verdaux; + typedef Elf_Verneed_Impl<ELFType<E, Is64>> Verneed; + typedef Elf_Vernaux_Impl<ELFType<E, Is64>> Vernaux; + typedef Elf_Versym_Impl<ELFType<E, Is64>> Versym; + typedef Elf_Hash_Impl<ELFType<E, Is64>> Hash; + typedef Elf_GnuHash_Impl<ELFType<E, Is64>> GnuHash; + typedef Elf_Chdr_Impl<ELFType<E, Is64>> Chdr; + typedef ArrayRef<Dyn> DynRange; + typedef ArrayRef<Shdr> ShdrRange; + typedef ArrayRef<Sym> SymRange; + typedef ArrayRef<Rel> RelRange; + typedef ArrayRef<Rela> RelaRange; + typedef ArrayRef<Phdr> PhdrRange; + + typedef packed<uint16_t> Half; + typedef packed<uint32_t> Word; + typedef packed<int32_t> Sword; + typedef packed<uint64_t> Xword; + typedef packed<int64_t> Sxword; + typedef packed<uint> Addr; + typedef packed<uint> Off; }; typedef ELFType<support::little, false> ELF32LE; @@ -208,14 +259,14 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> { return getBinding() != ELF::STB_LOCAL; } - ErrorOr<StringRef> getName(StringRef StrTab) const; + Expected<StringRef> getName(StringRef StrTab) const; }; template <class ELFT> -ErrorOr<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const { +Expected<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const { uint32_t Offset = this->st_name; if (Offset >= StrTab.size()) - return object_error::parse_failed; + return errorCodeToError(object_error::parse_failed); return StringRef(StrTab.data() + Offset); } @@ -320,12 +371,10 @@ struct Elf_Dyn_Impl : Elf_Dyn_Base<ELFT> { uintX_t getPtr() const { return d_un.d_ptr; } }; -// Elf_Rel: Elf Relocation -template <class ELFT, bool isRela> struct Elf_Rel_Impl; - template <endianness TargetEndianness> struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + static const bool IsRela = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply @@ -361,12 +410,14 @@ template <endianness TargetEndianness> struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, true> : public Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + static const bool IsRela = true; Elf_Sword r_addend; // Compute value for relocatable field by adding this }; template <endianness TargetEndianness> struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + static const bool IsRela = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply @@ -411,6 +462,7 @@ template <endianness TargetEndianness> struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, true> : public Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + static const bool IsRela = true; Elf_Sxword r_addend; // Compute value for relocatable field by adding this. }; @@ -508,6 +560,25 @@ struct Elf_GnuHash_Impl { } }; +// Compressed section headers. +// http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header +template <endianness TargetEndianness> +struct Elf_Chdr_Impl<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word ch_type; + Elf_Word ch_size; + Elf_Word ch_addralign; +}; + +template <endianness TargetEndianness> +struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word ch_type; + Elf_Word ch_reserved; + Elf_Xword ch_size; + Elf_Xword ch_addralign; +}; + // MIPS .reginfo section template <class ELFT> struct Elf_Mips_RegInfo; diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index 0f79a6ed0dd8..cd55e5dc26d7 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -14,11 +14,15 @@ #ifndef LLVM_OBJECT_ERROR_H #define LLVM_OBJECT_ERROR_H +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" #include <system_error> namespace llvm { namespace object { +class Binary; + const std::error_category &object_category(); enum class object_error { @@ -30,16 +34,51 @@ enum class object_error { string_table_non_null_end, invalid_section_index, bitcode_section_not_found, - elf_invalid_dynamic_table_size, - macho_small_load_command, - macho_load_segment_too_many_sections, - macho_load_segment_too_small, }; inline std::error_code make_error_code(object_error e) { return std::error_code(static_cast<int>(e), object_category()); } +/// Base class for all errors indicating malformed binary files. +/// +/// Having a subclass for all malformed binary files allows archive-walking +/// code to skip malformed files without having to understand every possible +/// way that a binary file might be malformed. +/// +/// Currently inherits from ECError for easy interoperability with +/// std::error_code, but this will be removed in the future. +class BinaryError : public ErrorInfo<BinaryError, ECError> { +public: + static char ID; + BinaryError() { + // Default to parse_failed, can be overridden with setErrorCode. + setErrorCode(make_error_code(object_error::parse_failed)); + } +}; + +/// Generic binary error. +/// +/// For errors that don't require their own specific sub-error (most errors) +/// this class can be used to describe the error via a string message. +class GenericBinaryError : public ErrorInfo<GenericBinaryError, BinaryError> { +public: + static char ID; + GenericBinaryError(Twine Msg); + GenericBinaryError(Twine Msg, object_error ECOverride); + const std::string &getMessage() const { return Msg; } + void log(raw_ostream &OS) const override; +private: + std::string Msg; +}; + +/// isNotObjectErrorInvalidFileType() is used when looping through the children +/// of an archive after calling getAsBinary() on the child and it returns an +/// llvm::Error. In the cases we want to loop through the children and ignore the +/// non-objects in the archive this is used to test the error to see if an +/// error() function needs to called on the llvm::Error. +Error isNotObjectErrorInvalidFileType(llvm::Error Err); + } // end namespace object. } // end namespace llvm. diff --git a/include/llvm/Object/FunctionIndexObjectFile.h b/include/llvm/Object/FunctionIndexObjectFile.h deleted file mode 100644 index 74b461dc7cc7..000000000000 --- a/include/llvm/Object/FunctionIndexObjectFile.h +++ /dev/null @@ -1,110 +0,0 @@ -//===- FunctionIndexObjectFile.h - Function index file implementation -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the FunctionIndexObjectFile template class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_OBJECT_FUNCTIONINDEXOBJECTFILE_H -#define LLVM_OBJECT_FUNCTIONINDEXOBJECTFILE_H - -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/Object/SymbolicFile.h" - -namespace llvm { -class FunctionInfoIndex; -class Module; - -namespace object { -class ObjectFile; - -/// This class is used to read just the function summary index related -/// sections out of the given object (which may contain a single module's -/// bitcode or be a combined index bitcode file). It builds a FunctionInfoIndex -/// object. -class FunctionIndexObjectFile : public SymbolicFile { - std::unique_ptr<FunctionInfoIndex> Index; - -public: - FunctionIndexObjectFile(MemoryBufferRef Object, - std::unique_ptr<FunctionInfoIndex> I); - ~FunctionIndexObjectFile() override; - - // TODO: Walk through FunctionMap entries for function symbols. - // However, currently these interfaces are not used by any consumers. - void moveSymbolNext(DataRefImpl &Symb) const override { - llvm_unreachable("not implemented"); - } - std::error_code printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const override { - llvm_unreachable("not implemented"); - return std::error_code(); - } - uint32_t getSymbolFlags(DataRefImpl Symb) const override { - llvm_unreachable("not implemented"); - return 0; - } - basic_symbol_iterator symbol_begin_impl() const override { - llvm_unreachable("not implemented"); - return basic_symbol_iterator(BasicSymbolRef()); - } - basic_symbol_iterator symbol_end_impl() const override { - llvm_unreachable("not implemented"); - return basic_symbol_iterator(BasicSymbolRef()); - } - - const FunctionInfoIndex &getIndex() const { - return const_cast<FunctionIndexObjectFile *>(this)->getIndex(); - } - FunctionInfoIndex &getIndex() { return *Index; } - std::unique_ptr<FunctionInfoIndex> takeIndex(); - - static inline bool classof(const Binary *v) { return v->isFunctionIndex(); } - - /// \brief Finds and returns bitcode embedded in the given object file, or an - /// error code if not found. - static ErrorOr<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); - - /// \brief Finds and returns bitcode in the given memory buffer (which may - /// be either a bitcode file or a native object file with embedded bitcode), - /// or an error code if not found. - static ErrorOr<MemoryBufferRef> - findBitcodeInMemBuffer(MemoryBufferRef Object); - - /// \brief Looks for function summary in the given memory buffer, - /// returns true if found, else false. - static bool - hasFunctionSummaryInMemBuffer(MemoryBufferRef Object, - DiagnosticHandlerFunction DiagnosticHandler); - - /// \brief Parse function index in the given memory buffer. - /// Return new FunctionIndexObjectFile instance containing parsed function - /// summary/index. - static ErrorOr<std::unique_ptr<FunctionIndexObjectFile>> - create(MemoryBufferRef Object, DiagnosticHandlerFunction DiagnosticHandler, - bool IsLazy = false); - - /// \brief Parse the function summary information for function with the - /// given name out of the given buffer. Parsed information is - /// stored on the index object saved in this object. - std::error_code - findFunctionSummaryInMemBuffer(MemoryBufferRef Object, - DiagnosticHandlerFunction DiagnosticHandler, - StringRef FunctionName); -}; -} - -/// Parse the function index out of an IR file and return the function -/// index object if found, or nullptr if not. -ErrorOr<std::unique_ptr<FunctionInfoIndex>> -getFunctionIndexForFile(StringRef Path, - DiagnosticHandlerFunction DiagnosticHandler); -} - -#endif diff --git a/include/llvm/Object/IRObjectFile.h b/include/llvm/Object/IRObjectFile.h index ef655287c34c..9fe011e17d62 100644 --- a/include/llvm/Object/IRObjectFile.h +++ b/include/llvm/Object/IRObjectFile.h @@ -20,6 +20,7 @@ namespace llvm { class Mangler; class Module; class GlobalValue; +class Triple; namespace object { class ObjectFile; @@ -59,6 +60,15 @@ public: /// error code if not found. static ErrorOr<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); + /// Parse inline ASM and collect the symbols that are not defined in + /// the current module. + /// + /// For each found symbol, call \p AsmUndefinedRefs with the name of the + /// symbol found and the associated flags. + static void CollectAsmUndefinedRefs( + const Triple &TheTriple, StringRef InlineAsm, + function_ref<void(StringRef, BasicSymbolRef::Flags)> AsmUndefinedRefs); + /// \brief Finds and returns bitcode in the given memory buffer (which may /// be either a bitcode file or a native object file with embedded bitcode), /// or an error code if not found. diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index e02ce3b21416..7906db1e8a77 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -193,24 +193,24 @@ public: typedef SmallVector<LoadCommandInfo, 4> LoadCommandList; typedef LoadCommandList::const_iterator load_command_iterator; - MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, - std::error_code &EC); + static Expected<std::unique_ptr<MachOObjectFile>> + create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits); void moveSymbolNext(DataRefImpl &Symb) const override; uint64_t getNValue(DataRefImpl Sym) const; - ErrorOr<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; // MachO specific. std::error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const; unsigned getSectionType(SectionRef Sec) const; - ErrorOr<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; - SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; - ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; unsigned getSymbolSectionID(SymbolRef Symb) const; unsigned getSectionID(SectionRef Sec) const; @@ -222,10 +222,12 @@ public: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; bool isSectionVirtual(DataRefImpl Sec) const override; + bool isSectionBitcode(DataRefImpl Sec) const override; relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; @@ -251,6 +253,7 @@ public: // MachO specific. basic_symbol_iterator getSymbolByIndex(unsigned Index) const; + uint64_t getSymbolIndex(DataRefImpl Symb) const; section_iterator section_begin() const override; section_iterator section_end() const override; @@ -259,7 +262,8 @@ public: StringRef getFileFormatName() const override; unsigned getArch() const override; - Triple getArch(const char **McpuDefault, Triple *ThumbTriple) const; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + Triple getArchTriple(const char **McpuDefault = nullptr) const; relocation_iterator section_rel_begin(unsigned Index) const; relocation_iterator section_rel_end(unsigned Index) const; @@ -405,12 +409,8 @@ public: StringRef &Suffix); static Triple::ArchType getArch(uint32_t CPUType); - static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault = nullptr); - static Triple getThumbArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault = nullptr); - static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault, Triple *ThumbTriple); + static Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault = nullptr); static bool isValidArch(StringRef ArchFlag); static Triple getHostArch(); @@ -441,6 +441,10 @@ public: } private: + + MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, + Error &Err); + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; union { diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index a11d381a700a..7eb2af944f3d 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -14,21 +14,22 @@ #ifndef LLVM_OBJECT_MACHOUNIVERSAL_H #define LLVM_OBJECT_MACHOUNIVERSAL_H -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" #include "llvm/Object/MachO.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MachO.h" namespace llvm { +class StringRef; + namespace object { class MachOUniversalBinary : public Binary { virtual void anchor(); + uint32_t Magic; uint32_t NumberOfObjects; public: class ObjectForArch { @@ -37,6 +38,7 @@ public: uint32_t Index; /// \brief Descriptor of the object. MachO::fat_arch Header; + MachO::fat_arch_64 Header64; public: ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index); @@ -51,19 +53,58 @@ public: } ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); } - uint32_t getCPUType() const { return Header.cputype; } - uint32_t getCPUSubType() const { return Header.cpusubtype; } - uint32_t getOffset() const { return Header.offset; } - uint32_t getSize() const { return Header.size; } - uint32_t getAlign() const { return Header.align; } + uint32_t getCPUType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cputype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cputype; + } + uint32_t getCPUSubType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cpusubtype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cpusubtype; + } + uint32_t getOffset() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.offset; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.offset; + } + uint32_t getSize() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.size; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.size; + } + uint32_t getAlign() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.align; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.align; + } + uint32_t getReserved() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return 0; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.reserved; + } std::string getArchTypeName() const { - Triple T = MachOObjectFile::getArch(Header.cputype, Header.cpusubtype); - return T.getArchName(); + if (Parent->getMagic() == MachO::FAT_MAGIC) { + Triple T = + MachOObjectFile::getArchTriple(Header.cputype, Header.cpusubtype); + return T.getArchName(); + } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 + Triple T = + MachOObjectFile::getArchTriple(Header64.cputype, + Header64.cpusubtype); + return T.getArchName(); + } } - ErrorOr<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const; + Expected<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const; - ErrorOr<std::unique_ptr<Archive>> getAsArchive() const; + Expected<std::unique_ptr<Archive>> getAsArchive() const; }; class object_iterator { @@ -86,8 +127,8 @@ public: } }; - MachOUniversalBinary(MemoryBufferRef Souce, std::error_code &EC); - static ErrorOr<std::unique_ptr<MachOUniversalBinary>> + MachOUniversalBinary(MemoryBufferRef Souce, Error &Err); + static Expected<std::unique_ptr<MachOUniversalBinary>> create(MemoryBufferRef Source); object_iterator begin_objects() const { @@ -101,6 +142,7 @@ public: return make_range(begin_objects(), end_objects()); } + uint32_t getMagic() const { return Magic; } uint32_t getNumberOfObjects() const { return NumberOfObjects; } // Cast methods. @@ -108,7 +150,7 @@ public: return V->isMachOUniversalBinary(); } - ErrorOr<std::unique_ptr<MachOObjectFile>> + Expected<std::unique_ptr<MachOObjectFile>> getObjectForArch(StringRef ArchName) const; }; diff --git a/include/llvm/Object/ModuleSummaryIndexObjectFile.h b/include/llvm/Object/ModuleSummaryIndexObjectFile.h new file mode 100644 index 000000000000..d021fb29427f --- /dev/null +++ b/include/llvm/Object/ModuleSummaryIndexObjectFile.h @@ -0,0 +1,103 @@ +//===- ModuleSummaryIndexObjectFile.h - Summary index file implementation -=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the ModuleSummaryIndexObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MODULESUMMARYINDEXOBJECTFILE_H +#define LLVM_OBJECT_MODULESUMMARYINDEXOBJECTFILE_H + +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Object/SymbolicFile.h" + +namespace llvm { +class ModuleSummaryIndex; +class Module; + +namespace object { +class ObjectFile; + +/// This class is used to read just the module summary index related +/// sections out of the given object (which may contain a single module's +/// bitcode or be a combined index bitcode file). It builds a ModuleSummaryIndex +/// object. +class ModuleSummaryIndexObjectFile : public SymbolicFile { + std::unique_ptr<ModuleSummaryIndex> Index; + +public: + ModuleSummaryIndexObjectFile(MemoryBufferRef Object, + std::unique_ptr<ModuleSummaryIndex> I); + ~ModuleSummaryIndexObjectFile() override; + + // TODO: Walk through GlobalValueMap entries for symbols. + // However, currently these interfaces are not used by any consumers. + void moveSymbolNext(DataRefImpl &Symb) const override { + llvm_unreachable("not implemented"); + } + std::error_code printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override { + llvm_unreachable("not implemented"); + return std::error_code(); + } + uint32_t getSymbolFlags(DataRefImpl Symb) const override { + llvm_unreachable("not implemented"); + return 0; + } + basic_symbol_iterator symbol_begin_impl() const override { + llvm_unreachable("not implemented"); + return basic_symbol_iterator(BasicSymbolRef()); + } + basic_symbol_iterator symbol_end_impl() const override { + llvm_unreachable("not implemented"); + return basic_symbol_iterator(BasicSymbolRef()); + } + + const ModuleSummaryIndex &getIndex() const { + return const_cast<ModuleSummaryIndexObjectFile *>(this)->getIndex(); + } + ModuleSummaryIndex &getIndex() { return *Index; } + std::unique_ptr<ModuleSummaryIndex> takeIndex(); + + static inline bool classof(const Binary *v) { + return v->isModuleSummaryIndex(); + } + + /// \brief Finds and returns bitcode embedded in the given object file, or an + /// error code if not found. + static ErrorOr<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); + + /// \brief Finds and returns bitcode in the given memory buffer (which may + /// be either a bitcode file or a native object file with embedded bitcode), + /// or an error code if not found. + static ErrorOr<MemoryBufferRef> + findBitcodeInMemBuffer(MemoryBufferRef Object); + + /// \brief Looks for summary sections in the given memory buffer, + /// returns true if found, else false. + static bool hasGlobalValueSummaryInMemBuffer( + MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); + + /// \brief Parse module summary index in the given memory buffer. + /// Return new ModuleSummaryIndexObjectFile instance containing parsed module + /// summary/index. + static ErrorOr<std::unique_ptr<ModuleSummaryIndexObjectFile>> + create(MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); +}; +} + +/// Parse the module summary index out of an IR file and return the module +/// summary index object if found, or nullptr if not. +ErrorOr<std::unique_ptr<ModuleSummaryIndex>> getModuleSummaryIndexForFile( + StringRef Path, const DiagnosticHandlerFunction &DiagnosticHandler); +} + +#endif diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index ce0c891ee0c2..6272a5f056eb 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -15,13 +15,13 @@ #define LLVM_OBJECT_OBJECTFILE_H #include "llvm/ADT/StringRef.h" +#include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include <cstring> -#include <vector> namespace llvm { namespace object { @@ -90,10 +90,12 @@ public: /// @brief Get the alignment of this section as the actual value (not log 2). uint64_t getAlignment() const; + bool isCompressed() const; bool isText() const; bool isData() const; bool isBSS() const; bool isVirtual() const; + bool isBitcode() const; bool containsSymbol(SymbolRef S) const; @@ -130,10 +132,10 @@ public: assert(isa<ObjectFile>(BasicSymbolRef::getObject())); } - ErrorOr<StringRef> getName() const; + Expected<StringRef> getName() const; /// Returns the symbol virtual address (i.e. address at which it will be /// mapped). - ErrorOr<uint64_t> getAddress() const; + Expected<uint64_t> getAddress() const; /// Return the value of the symbol depending on the object this can be an /// offset or a virtual address. @@ -142,11 +144,11 @@ public: /// @brief Get the alignment of this symbol as the actual value (not log 2). uint32_t getAlignment() const; uint64_t getCommonSize() const; - SymbolRef::Type getType() const; + Expected<SymbolRef::Type> getType() const; /// @brief Get section this symbol is defined in reference to. Result is /// end_sections() if it is undefined or is an absolute symbol. - ErrorOr<section_iterator> getSection() const; + Expected<section_iterator> getSection() const; const ObjectFile *getObject() const; }; @@ -193,15 +195,15 @@ protected: // Implementations assume that the DataRefImpl is valid and has not been // modified externally. It's UB otherwise. friend class SymbolRef; - virtual ErrorOr<StringRef> getSymbolName(DataRefImpl Symb) const = 0; + virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0; std::error_code printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; - virtual ErrorOr<uint64_t> getSymbolAddress(DataRefImpl Symb) const = 0; + virtual Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const = 0; virtual uint64_t getSymbolValueImpl(DataRefImpl Symb) const = 0; virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const; virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0; - virtual SymbolRef::Type getSymbolType(DataRefImpl Symb) const = 0; - virtual ErrorOr<section_iterator> + virtual Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const = 0; + virtual Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const = 0; // Same as above for SectionRef. @@ -214,11 +216,13 @@ protected: virtual std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const = 0; virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0; + virtual bool isSectionCompressed(DataRefImpl Sec) const = 0; virtual bool isSectionText(DataRefImpl Sec) const = 0; virtual bool isSectionData(DataRefImpl Sec) const = 0; virtual bool isSectionBSS(DataRefImpl Sec) const = 0; // A section is 'virtual' if its contents aren't present in the object image. virtual bool isSectionVirtual(DataRefImpl Sec) const = 0; + virtual bool isSectionBitcode(DataRefImpl Sec) const; virtual relocation_iterator section_rel_begin(DataRefImpl Sec) const = 0; virtual relocation_iterator section_rel_end(DataRefImpl Sec) const = 0; virtual section_iterator getRelocatedSection(DataRefImpl Sec) const; @@ -259,6 +263,7 @@ public: virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; + virtual SubtargetFeatures getFeatures() const = 0; /// Returns platform-specific object flags, if any. virtual std::error_code getPlatformFlags(unsigned &Result) const { @@ -273,12 +278,12 @@ public: /// @param ObjectPath The path to the object file. ObjectPath.isObject must /// return true. /// @brief Create ObjectFile from path. - static ErrorOr<OwningBinary<ObjectFile>> + static Expected<OwningBinary<ObjectFile>> createObjectFile(StringRef ObjectPath); - static ErrorOr<std::unique_ptr<ObjectFile>> + static Expected<std::unique_ptr<ObjectFile>> createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type); - static ErrorOr<std::unique_ptr<ObjectFile>> + static Expected<std::unique_ptr<ObjectFile>> createObjectFile(MemoryBufferRef Object) { return createObjectFile(Object, sys::fs::file_magic::unknown); } @@ -294,19 +299,20 @@ public: static ErrorOr<std::unique_ptr<ObjectFile>> createELFObjectFile(MemoryBufferRef Object); - static ErrorOr<std::unique_ptr<MachOObjectFile>> + static Expected<std::unique_ptr<MachOObjectFile>> createMachOObjectFile(MemoryBufferRef Object); + }; // Inline function definitions. inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner) : BasicSymbolRef(SymbolP, Owner) {} -inline ErrorOr<StringRef> SymbolRef::getName() const { +inline Expected<StringRef> SymbolRef::getName() const { return getObject()->getSymbolName(getRawDataRefImpl()); } -inline ErrorOr<uint64_t> SymbolRef::getAddress() const { +inline Expected<uint64_t> SymbolRef::getAddress() const { return getObject()->getSymbolAddress(getRawDataRefImpl()); } @@ -322,11 +328,11 @@ inline uint64_t SymbolRef::getCommonSize() const { return getObject()->getCommonSymbolSize(getRawDataRefImpl()); } -inline ErrorOr<section_iterator> SymbolRef::getSection() const { +inline Expected<section_iterator> SymbolRef::getSection() const { return getObject()->getSymbolSection(getRawDataRefImpl()); } -inline SymbolRef::Type SymbolRef::getType() const { +inline Expected<SymbolRef::Type> SymbolRef::getType() const { return getObject()->getSymbolType(getRawDataRefImpl()); } @@ -378,6 +384,10 @@ inline uint64_t SectionRef::getAlignment() const { return OwningObject->getSectionAlignment(SectionPimpl); } +inline bool SectionRef::isCompressed() const { + return OwningObject->isSectionCompressed(SectionPimpl); +} + inline bool SectionRef::isText() const { return OwningObject->isSectionText(SectionPimpl); } @@ -394,6 +404,10 @@ inline bool SectionRef::isVirtual() const { return OwningObject->isSectionVirtual(SectionPimpl); } +inline bool SectionRef::isBitcode() const { + return OwningObject->isSectionBitcode(SectionPimpl); +} + inline relocation_iterator SectionRef::relocation_begin() const { return OwningObject->section_rel_begin(SectionPimpl); } diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index d5e4258cb0a7..5e0df98d8627 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -16,7 +16,6 @@ #ifndef LLVM_OBJECT_RELOCVISITOR_H #define LLVM_OBJECT_RELOCVISITOR_H -#include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" @@ -175,6 +174,14 @@ private: case llvm::ELF::R_ARM_ABS32: return visitELF_ARM_ABS32(R, Value); } + case Triple::lanai: + switch (RelocType) { + case llvm::ELF::R_LANAI_32: + return visitELF_Lanai_32(R, Value); + default: + HasError = true; + return RelocToApply(); + } case Triple::mipsel: case Triple::mips: switch (RelocType) { @@ -311,6 +318,13 @@ private: return RelocToApply(Res, 4); } + /// Lanai ELF + RelocToApply visitELF_Lanai_32(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend(R); + uint32_t Res = (Value + Addend) & 0xFFFFFFFF; + return RelocToApply(Res, 4); + } + /// MIPS ELF RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) { uint32_t Res = Value & 0xFFFFFFFF; diff --git a/include/llvm/Object/StackMapParser.h b/include/llvm/Object/StackMapParser.h index 276eab6c294e..e58162de1501 100644 --- a/include/llvm/Object/StackMapParser.h +++ b/include/llvm/Object/StackMapParser.h @@ -10,9 +10,8 @@ #ifndef LLVM_CODEGEN_STACKMAPPARSER_H #define LLVM_CODEGEN_STACKMAPPARSER_H -#include "llvm/Support/Debug.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" -#include <map> #include <vector> namespace llvm { diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 0c5b38111a9c..894c2670f265 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -16,6 +16,7 @@ #include "llvm/Object/Binary.h" #include "llvm/Support/Format.h" +#include <utility> namespace llvm { namespace object { @@ -58,7 +59,7 @@ class content_iterator content_type Current; public: - content_iterator(content_type symb) : Current(symb) {} + content_iterator(content_type symb) : Current(std::move(symb)) {} const content_type *operator->() const { return &Current; } @@ -153,15 +154,15 @@ public: } // construction aux. - static ErrorOr<std::unique_ptr<SymbolicFile>> + static Expected<std::unique_ptr<SymbolicFile>> createSymbolicFile(MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context); - static ErrorOr<std::unique_ptr<SymbolicFile>> + static Expected<std::unique_ptr<SymbolicFile>> createSymbolicFile(MemoryBufferRef Object) { return createSymbolicFile(Object, sys::fs::file_magic::unknown, nullptr); } - static ErrorOr<OwningBinary<SymbolicFile>> + static Expected<OwningBinary<SymbolicFile>> createSymbolicFile(StringRef ObjectPath); static inline bool classof(const Binary *v) { diff --git a/include/llvm/Object/COFFYAML.h b/include/llvm/ObjectYAML/COFFYAML.h index 12a25223bd37..65ad1dde67f5 100644 --- a/include/llvm/Object/COFFYAML.h +++ b/include/llvm/ObjectYAML/COFFYAML.h @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_OBJECT_COFFYAML_H -#define LLVM_OBJECT_COFFYAML_H +#ifndef LLVM_OBJECTYAML_COFFYAML_H +#define LLVM_OBJECTYAML_COFFYAML_H #include "llvm/ADT/Optional.h" -#include "llvm/MC/YAML.h" +#include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/COFF.h" namespace llvm { @@ -54,7 +54,7 @@ namespace COFFYAML { struct Section { COFF::section Header; - unsigned Alignment; + unsigned Alignment = 0; yaml::BinaryRef SectionData; std::vector<Relocation> Relocations; StringRef Name; @@ -63,8 +63,8 @@ namespace COFFYAML { struct Symbol { COFF::symbol Header; - COFF::SymbolBaseType SimpleType; - COFF::SymbolComplexType ComplexType; + COFF::SymbolBaseType SimpleType = COFF::IMAGE_SYM_TYPE_NULL; + COFF::SymbolComplexType ComplexType = COFF::IMAGE_SYM_DTYPE_NULL; Optional<COFF::AuxiliaryFunctionDefinition> FunctionDefinition; Optional<COFF::AuxiliarybfAndefSymbol> bfAndefSymbol; Optional<COFF::AuxiliaryWeakExternal> WeakExternal; diff --git a/include/llvm/Object/ELFYAML.h b/include/llvm/ObjectYAML/ELFYAML.h index df0aa500c8a2..81a4ec28c94f 100644 --- a/include/llvm/Object/ELFYAML.h +++ b/include/llvm/ObjectYAML/ELFYAML.h @@ -13,10 +13,10 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_OBJECT_ELFYAML_H -#define LLVM_OBJECT_ELFYAML_H +#ifndef LLVM_OBJECTYAML_ELFYAML_H +#define LLVM_OBJECTYAML_ELFYAML_H -#include "llvm/MC/YAML.h" +#include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/ELF.h" namespace llvm { diff --git a/include/llvm/ObjectYAML/MachOYAML.h b/include/llvm/ObjectYAML/MachOYAML.h new file mode 100644 index 000000000000..bb15e64789d0 --- /dev/null +++ b/include/llvm/ObjectYAML/MachOYAML.h @@ -0,0 +1,296 @@ +//===- MachOYAML.h - Mach-O YAMLIO implementation ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares classes for handling the YAML representation +/// of Mach-O. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_MACHOYAML_H +#define LLVM_OBJECTYAML_MACHOYAML_H + +#include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/MachO.h" + +namespace llvm { +namespace MachOYAML { + +struct Section { + char sectname[16]; + char segname[16]; + llvm::yaml::Hex64 addr; + uint64_t size; + llvm::yaml::Hex32 offset; + uint32_t align; + llvm::yaml::Hex32 reloff; + uint32_t nreloc; + llvm::yaml::Hex32 flags; + llvm::yaml::Hex32 reserved1; + llvm::yaml::Hex32 reserved2; + llvm::yaml::Hex32 reserved3; +}; + +struct FileHeader { + llvm::yaml::Hex32 magic; + llvm::yaml::Hex32 cputype; + llvm::yaml::Hex32 cpusubtype; + llvm::yaml::Hex32 filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + llvm::yaml::Hex32 flags; + llvm::yaml::Hex32 reserved; +}; + +struct LoadCommand { + virtual ~LoadCommand(); + llvm::MachO::macho_load_command Data; + std::vector<Section> Sections; + std::vector<llvm::yaml::Hex8> PayloadBytes; + std::string PayloadString; + uint64_t ZeroPadBytes; +}; + +struct NListEntry { + uint32_t n_strx; + uint8_t n_type; + uint8_t n_sect; + uint16_t n_desc; + uint64_t n_value; +}; +struct RebaseOpcode { + MachO::RebaseOpcode Opcode; + uint8_t Imm; + std::vector<yaml::Hex64> ExtraData; +}; + +struct BindOpcode { + MachO::BindOpcode Opcode; + uint8_t Imm; + std::vector<yaml::Hex64> ULEBExtraData; + std::vector<int64_t> SLEBExtraData; + StringRef Symbol; +}; + +struct ExportEntry { + ExportEntry() + : TerminalSize(0), NodeOffset(0), Name(), Flags(0), Address(0), Other(0), + ImportName(), Children() {} + uint64_t TerminalSize; + uint64_t NodeOffset; + std::string Name; + llvm::yaml::Hex64 Flags; + llvm::yaml::Hex64 Address; + llvm::yaml::Hex64 Other; + std::string ImportName; + std::vector<MachOYAML::ExportEntry> Children; +}; + +struct LinkEditData { + std::vector<MachOYAML::RebaseOpcode> RebaseOpcodes; + std::vector<MachOYAML::BindOpcode> BindOpcodes; + std::vector<MachOYAML::BindOpcode> WeakBindOpcodes; + std::vector<MachOYAML::BindOpcode> LazyBindOpcodes; + MachOYAML::ExportEntry ExportTrie; + std::vector<NListEntry> NameList; + std::vector<StringRef> StringTable; +}; + +struct Object { + FileHeader Header; + std::vector<LoadCommand> LoadCommands; + std::vector<Section> Sections; + LinkEditData LinkEdit; +}; + +struct FatHeader { + llvm::yaml::Hex32 magic; + uint32_t nfat_arch; +}; + +struct FatArch { + llvm::yaml::Hex32 cputype; + llvm::yaml::Hex32 cpusubtype; + llvm::yaml::Hex64 offset; + uint64_t size; + uint32_t align; + llvm::yaml::Hex32 reserved; +}; + +struct UniversalBinary { + FatHeader Header; + std::vector<FatArch> FatArchs; + std::vector<Object> Slices; +}; + +} // namespace llvm::MachOYAML +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64) +LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::BindOpcode) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<MachOYAML::FileHeader> { + static void mapping(IO &IO, MachOYAML::FileHeader &FileHeader); +}; + +template <> struct MappingTraits<MachOYAML::Object> { + static void mapping(IO &IO, MachOYAML::Object &Object); +}; + +template <> struct MappingTraits<MachOYAML::FatHeader> { + static void mapping(IO &IO, MachOYAML::FatHeader &FatHeader); +}; + +template <> struct MappingTraits<MachOYAML::FatArch> { + static void mapping(IO &IO, MachOYAML::FatArch &FatArch); +}; + +template <> struct MappingTraits<MachOYAML::UniversalBinary> { + static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary); +}; + +template <> struct MappingTraits<MachOYAML::LoadCommand> { + static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand); +}; + +template <> struct MappingTraits<MachOYAML::LinkEditData> { + static void mapping(IO &IO, MachOYAML::LinkEditData &LinkEditData); +}; + +template <> struct MappingTraits<MachOYAML::RebaseOpcode> { + static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode); +}; + +template <> struct MappingTraits<MachOYAML::BindOpcode> { + static void mapping(IO &IO, MachOYAML::BindOpcode &BindOpcode); +}; + +template <> struct MappingTraits<MachOYAML::ExportEntry> { + static void mapping(IO &IO, MachOYAML::ExportEntry &ExportEntry); +}; + +template <> struct MappingTraits<MachOYAML::Section> { + static void mapping(IO &IO, MachOYAML::Section &Section); +}; + +template <> struct MappingTraits<MachOYAML::NListEntry> { + static void mapping(IO &IO, MachOYAML::NListEntry &NListEntry); +}; + +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + io.enumCase(value, #LCName, MachO::LCName); + +template <> struct ScalarEnumerationTraits<MachO::LoadCommandType> { + static void enumeration(IO &io, MachO::LoadCommandType &value) { +#include "llvm/Support/MachO.def" + io.enumFallback<Hex32>(value); + } +}; + +#define ENUM_CASE(Enum) io.enumCase(value, #Enum, MachO::Enum); + +template <> struct ScalarEnumerationTraits<MachO::RebaseOpcode> { + static void enumeration(IO &io, MachO::RebaseOpcode &value) { + ENUM_CASE(REBASE_OPCODE_DONE) + ENUM_CASE(REBASE_OPCODE_SET_TYPE_IMM) + ENUM_CASE(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_IMM_SCALED) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_IMM_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback<Hex8>(value); + } +}; + +template <> struct ScalarEnumerationTraits<MachO::BindOpcode> { + static void enumeration(IO &io, MachO::BindOpcode &value) { + ENUM_CASE(BIND_OPCODE_DONE) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) + ENUM_CASE(BIND_OPCODE_SET_TYPE_IMM) + ENUM_CASE(BIND_OPCODE_SET_ADDEND_SLEB) + ENUM_CASE(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(BIND_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED) + ENUM_CASE(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback<Hex8>(value); + } +}; + +// This trait is used for 16-byte chars in Mach structures used for strings +typedef char char_16[16]; + +template <> struct ScalarTraits<char_16> { + static void output(const char_16 &Val, void *, llvm::raw_ostream &Out); + + static StringRef input(StringRef Scalar, void *, char_16 &Val); + static bool mustQuote(StringRef S); +}; + +// This trait is used for UUIDs. It reads and writes them matching otool's +// formatting style. +typedef uint8_t uuid_t[16]; + +template <> struct ScalarTraits<uuid_t> { + static void output(const uuid_t &Val, void *, llvm::raw_ostream &Out); + + static StringRef input(StringRef Scalar, void *, uuid_t &Val); + static bool mustQuote(StringRef S); +}; + +// Load Command struct mapping traits + +#define LOAD_COMMAND_STRUCT(LCStruct) \ + template <> struct MappingTraits<MachO::LCStruct> { \ + static void mapping(IO &IO, MachO::LCStruct &LoadCommand); \ + }; + +#include "llvm/Support/MachO.def" + +// Extra structures used by load commands +template <> struct MappingTraits<MachO::dylib> { + static void mapping(IO &IO, MachO::dylib &LoadCommand); +}; + +template <> struct MappingTraits<MachO::fvmlib> { + static void mapping(IO &IO, MachO::fvmlib &LoadCommand); +}; + +template <> struct MappingTraits<MachO::section> { + static void mapping(IO &IO, MachO::section &LoadCommand); +}; + +template <> struct MappingTraits<MachO::section_64> { + static void mapping(IO &IO, MachO::section_64 &LoadCommand); +}; + +} // namespace llvm::yaml + +} // namespace llvm + +#endif diff --git a/include/llvm/ObjectYAML/ObjectYAML.h b/include/llvm/ObjectYAML/ObjectYAML.h new file mode 100644 index 000000000000..1d6462347770 --- /dev/null +++ b/include/llvm/ObjectYAML/ObjectYAML.h @@ -0,0 +1,35 @@ +//===- ObjectYAML.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_OBJECTYAML_H +#define LLVM_OBJECTYAML_OBJECTYAML_H + +#include "llvm/Support/YAMLTraits.h" +#include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/MachOYAML.h" + +namespace llvm { +namespace yaml { + +struct YamlObjectFile { + std::unique_ptr<ELFYAML::Object> Elf; + std::unique_ptr<COFFYAML::Object> Coff; + std::unique_ptr<MachOYAML::Object> MachO; + std::unique_ptr<MachOYAML::UniversalBinary> FatMachO; +}; + +template <> struct MappingTraits<YamlObjectFile> { + static void mapping(IO &IO, YamlObjectFile &ObjectFile); +}; + +} // namespace yaml +} // namespace llvm + +#endif diff --git a/include/llvm/MC/YAML.h b/include/llvm/ObjectYAML/YAML.h index 383cdc6785fa..7f6836809b6d 100644 --- a/include/llvm/MC/YAML.h +++ b/include/llvm/ObjectYAML/YAML.h @@ -1,5 +1,14 @@ -#ifndef LLVM_MC_YAML_H -#define LLVM_MC_YAML_H +//===- YAML.h ---------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_YAML_H +#define LLVM_OBJECTYAML_YAML_H #include "llvm/Support/YAMLTraits.h" diff --git a/include/llvm/Option/OptParser.td b/include/llvm/Option/OptParser.td index dbf240d74805..4da86f09750d 100644 --- a/include/llvm/Option/OptParser.td +++ b/include/llvm/Option/OptParser.td @@ -46,6 +46,9 @@ def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">; def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">; // An option which consumes all remaining arguments if there are any. def KIND_REMAINING_ARGS : OptionKind<"RemainingArgs">; +// An option which consumes an optional joined argument and any other remaining +// arguments. +def KIND_REMAINING_ARGS_JOINED : OptionKind<"RemainingArgsJoined">; // Define the option flags. diff --git a/include/llvm/Option/Option.h b/include/llvm/Option/Option.h index 494987a135ef..139f281b3c4c 100644 --- a/include/llvm/Option/Option.h +++ b/include/llvm/Option/Option.h @@ -51,6 +51,7 @@ public: JoinedClass, SeparateClass, RemainingArgsClass, + RemainingArgsJoinedClass, CommaJoinedClass, MultiArgClass, JoinedOrSeparateClass, @@ -150,6 +151,7 @@ public: case MultiArgClass: case JoinedOrSeparateClass: case RemainingArgsClass: + case RemainingArgsJoinedClass: return RenderSeparateStyle; } llvm_unreachable("Unexpected kind!"); diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index 99604cdbc9ca..2a21b82876bb 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -29,7 +29,6 @@ #ifndef LLVM_PASS_H #define LLVM_PASS_H -#include "llvm/Support/Compiler.h" #include <string> namespace llvm { @@ -251,6 +250,11 @@ public: explicit ModulePass(char &pid) : Pass(PT_Module, pid) {} // Force out-of-line virtual method. ~ModulePass() override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipModule(Module &M) const; }; @@ -310,9 +314,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - This function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Function &F) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipFunction(const Function &F) const; }; @@ -359,9 +364,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const BasicBlock &BB) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipBasicBlock(const BasicBlock &BB) const; }; /// If the user specifies the -time-passes argument on an LLVM tool command line diff --git a/include/llvm/PassAnalysisSupport.h b/include/llvm/PassAnalysisSupport.h index 492a4ef464f8..abd992938057 100644 --- a/include/llvm/PassAnalysisSupport.h +++ b/include/llvm/PassAnalysisSupport.h @@ -20,11 +20,11 @@ #define LLVM_PASSANALYSISSUPPORT_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Pass.h" #include <vector> namespace llvm { +class StringRef; //===----------------------------------------------------------------------===// /// Represent the analysis usage information of a pass. This tracks analyses @@ -153,9 +153,9 @@ public: /// Find pass that is implementing PI. Pass *findImplPass(AnalysisID PI) { Pass *ResultPass = nullptr; - for (unsigned i = 0; i < AnalysisImpls.size() ; ++i) { - if (AnalysisImpls[i].first == PI) { - ResultPass = AnalysisImpls[i].second; + for (const auto &AnalysisImpl : AnalysisImpls) { + if (AnalysisImpl.first == PI) { + ResultPass = AnalysisImpl.second; break; } } diff --git a/include/llvm/PassRegistry.h b/include/llvm/PassRegistry.h index e7fe1f53a4d4..4bb19675585e 100644 --- a/include/llvm/PassRegistry.h +++ b/include/llvm/PassRegistry.h @@ -20,7 +20,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" #include "llvm/PassInfo.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/RWMutex.h" @@ -28,6 +27,7 @@ namespace llvm { +class StringRef; class PassInfo; struct PassRegistrationListener; diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index 7c3d49f02e8f..ba6d84f04ba0 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -26,73 +26,57 @@ #include "llvm/PassInfo.h" #include "llvm/PassRegistry.h" #include "llvm/Support/Atomic.h" -#include "llvm/Support/Compiler.h" -#include <vector> +#include "llvm/Support/Threading.h" +#include <functional> namespace llvm { class TargetMachine; -#define CALL_ONCE_INITIALIZATION(function) \ - static volatile sys::cas_flag initialized = 0; \ - sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0); \ - if (old_val == 0) { \ - function(Registry); \ - sys::MemoryFence(); \ - TsanIgnoreWritesBegin(); \ - TsanHappensBefore(&initialized); \ - initialized = 2; \ - TsanIgnoreWritesEnd(); \ - } else { \ - sys::cas_flag tmp = initialized; \ - sys::MemoryFence(); \ - while (tmp != 2) { \ - tmp = initialized; \ - sys::MemoryFence(); \ - } \ - } \ - TsanHappensAfter(&initialized); - -#define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } -#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { - -#define INITIALIZE_PASS_DEPENDENCY(depName) \ - initialize##depName##Pass(Registry); -#define INITIALIZE_AG_DEPENDENCY(depName) \ - initialize##depName##AnalysisGroup(Registry); - -#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { + +#define INITIALIZE_PASS_DEPENDENCY(depName) initialize##depName##Pass(Registry); +#define INITIALIZE_AG_DEPENDENCY(depName) \ + initialize##depName##AnalysisGroup(Registry); + +#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } -#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \ - INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - PassName::registerOptions(); \ +#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \ + INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ + PassName::registerOptions(); \ INITIALIZE_PASS_END(PassName, Arg, Name, Cfg, Analysis) #define INITIALIZE_PASS_WITH_OPTIONS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - PassName::registerOptions(); \ + INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ + PassName::registerOptions(); -template<typename PassName> -Pass *callDefaultCtor() { return new PassName(); } +template <typename PassName> Pass *callDefaultCtor() { return new PassName(); } template <typename PassName> Pass *callTargetMachineCtor(TargetMachine *TM) { return new PassName(TM); @@ -115,20 +99,17 @@ template <typename PassName> Pass *callTargetMachineCtor(TargetMachine *TM) { /// /// static RegisterPass<PassClassName> tmp("passopt", "My Name"); /// -template<typename passName> -struct RegisterPass : public PassInfo { - +template <typename passName> struct RegisterPass : public PassInfo { // Register Pass using default constructor... RegisterPass(const char *PassArg, const char *Name, bool CFGOnly = false, bool is_analysis = false) - : PassInfo(Name, PassArg, &passName::ID, - PassInfo::NormalCtor_t(callDefaultCtor<passName>), - CFGOnly, is_analysis) { + : PassInfo(Name, PassArg, &passName::ID, + PassInfo::NormalCtor_t(callDefaultCtor<passName>), CFGOnly, + is_analysis) { PassRegistry::getPassRegistry()->registerPass(*this); } }; - /// RegisterAnalysisGroup - Register a Pass as a member of an analysis _group_. /// Analysis groups are used to define an interface (which need not derive from /// Pass) that is required by passes to do their job. Analysis Groups differ @@ -150,70 +131,73 @@ struct RegisterPass : public PassInfo { /// class RegisterAGBase : public PassInfo { public: - RegisterAGBase(const char *Name, - const void *InterfaceID, - const void *PassID = nullptr, - bool isDefault = false); + RegisterAGBase(const char *Name, const void *InterfaceID, + const void *PassID = nullptr, bool isDefault = false); }; -template<typename Interface, bool Default = false> +template <typename Interface, bool Default = false> struct RegisterAnalysisGroup : public RegisterAGBase { explicit RegisterAnalysisGroup(PassInfo &RPB) - : RegisterAGBase(RPB.getPassName(), - &Interface::ID, RPB.getTypeInfo(), - Default) { - } + : RegisterAGBase(RPB.getPassName(), &Interface::ID, RPB.getTypeInfo(), + Default) {} explicit RegisterAnalysisGroup(const char *Name) - : RegisterAGBase(Name, &Interface::ID) { - } + : RegisterAGBase(Name, &Interface::ID) {} }; -#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \ - static void* initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \ - initialize##defaultPass##Pass(Registry); \ - PassInfo *AI = new PassInfo(name, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, 0, *AI, false, true); \ - return AI; \ - } \ - void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##agName##AnalysisGroupOnce) \ +#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \ + static void *initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \ + initialize##defaultPass##Pass(Registry); \ + PassInfo *AI = new PassInfo(name, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, 0, *AI, false, true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##agName##AnalysisGroupFlag); \ + void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ + llvm::call_once(Initialize##agName##AnalysisGroupFlag, \ + initialize##agName##AnalysisGroupOnce, \ + std::ref(Registry)); \ } - -#define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - if (!def) initialize##agName##AnalysisGroup(Registry); \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - \ - PassInfo *AI = new PassInfo(name, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ - *AI, def, true); \ - return AI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) \ + initialize##agName##AnalysisGroup(Registry); \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(name, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, \ + true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } - #define INITIALIZE_AG_PASS_BEGIN(passName, agName, arg, n, cfg, analysis, def) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - if (!def) initialize##agName##AnalysisGroup(Registry); - -#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \ - PassInfo *PI = new PassInfo(n, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - \ - PassInfo *AI = new PassInfo(n, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ - *AI, def, true); \ - return AI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) \ + initialize##agName##AnalysisGroup(Registry); + +#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \ + PassInfo *PI = new PassInfo( \ + n, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(n, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } //===--------------------------------------------------------------------------- @@ -224,7 +208,6 @@ struct RegisterAnalysisGroup : public RegisterAGBase { /// loaded). /// struct PassRegistrationListener { - PassRegistrationListener() {} virtual ~PassRegistrationListener() {} @@ -244,7 +227,6 @@ struct PassRegistrationListener { virtual void passEnumerate(const PassInfo *) {} }; - } // End llvm namespace #endif diff --git a/include/llvm/Passes/PassBuilder.h b/include/llvm/Passes/PassBuilder.h index 1e605e374178..9f0a9c6e1380 100644 --- a/include/llvm/Passes/PassBuilder.h +++ b/include/llvm/Passes/PassBuilder.h @@ -16,11 +16,13 @@ #ifndef LLVM_PASSES_PASSBUILDER_H #define LLVM_PASSES_PASSBUILDER_H -#include "llvm/ADT/StringRef.h" #include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LoopPassManager.h" #include "llvm/IR/PassManager.h" namespace llvm { +class StringRef; +class AAManager; class TargetMachine; /// \brief This class provides access to building LLVM's passes. @@ -33,29 +35,164 @@ class PassBuilder { TargetMachine *TM; public: + /// \brief LLVM-provided high-level optimization levels. + /// + /// This enumerates the LLVM-provided high-level optimization levels. Each + /// level has a specific goal and rationale. + enum OptimizationLevel { + /// Disable as many optimizations as possible. This doesn't completely + /// disable the optimizer in all cases, for example always_inline functions + /// can be required to be inlined for correctness. + O0, + + /// Optimize quickly without destroying debuggability. + /// + /// FIXME: The current and historical behavior of this level does *not* + /// agree with this goal, but we would like to move toward this goal in the + /// future. + /// + /// This level is tuned to produce a result from the optimizer as quickly + /// as possible and to avoid destroying debuggability. This tends to result + /// in a very good development mode where the compiled code will be + /// immediately executed as part of testing. As a consequence, where + /// possible, we would like to produce efficient-to-execute code, but not + /// if it significantly slows down compilation or would prevent even basic + /// debugging of the resulting binary. + /// + /// As an example, complex loop transformations such as versioning, + /// vectorization, or fusion might not make sense here due to the degree to + /// which the executed code would differ from the source code, and the + /// potential compile time cost. + O1, + + /// Optimize for fast execution as much as possible without triggering + /// significant incremental compile time or code size growth. + /// + /// The key idea is that optimizations at this level should "pay for + /// themselves". So if an optimization increases compile time by 5% or + /// increases code size by 5% for a particular benchmark, that benchmark + /// should also be one which sees a 5% runtime improvement. If the compile + /// time or code size penalties happen on average across a diverse range of + /// LLVM users' benchmarks, then the improvements should as well. + /// + /// And no matter what, the compile time needs to not grow superlinearly + /// with the size of input to LLVM so that users can control the runtime of + /// the optimizer in this mode. + /// + /// This is expected to be a good default optimization level for the vast + /// majority of users. + O2, + + /// Optimize for fast execution as much as possible. + /// + /// This mode is significantly more aggressive in trading off compile time + /// and code size to get execution time improvements. The core idea is that + /// this mode should include any optimization that helps execution time on + /// balance across a diverse collection of benchmarks, even if it increases + /// code size or compile time for some benchmarks without corresponding + /// improvements to execution time. + /// + /// Despite being willing to trade more compile time off to get improved + /// execution time, this mode still tries to avoid superlinear growth in + /// order to make even significantly slower compile times at least scale + /// reasonably. This does not preclude very substantial constant factor + /// costs though. + O3, + + /// Similar to \c O2 but tries to optimize for small code size instead of + /// fast execution without triggering significant incremental execution + /// time slowdowns. + /// + /// The logic here is exactly the same as \c O2, but with code size and + /// execution time metrics swapped. + /// + /// A consequence of the different core goal is that this should in general + /// produce substantially smaller executables that still run in + /// a reasonable amount of time. + Os, + + /// A very specialized mode that will optimize for code size at any and all + /// costs. + /// + /// This is useful primarily when there are absolute size limitations and + /// any effort taken to reduce the size is worth it regardless of the + /// execution time impact. You should expect this level to produce rather + /// slow, but very small, code. + Oz + }; + explicit PassBuilder(TargetMachine *TM = nullptr) : TM(TM) {} + /// \brief Cross register the analysis managers through their proxies. + /// + /// This is an interface that can be used to cross register each + // AnalysisManager with all the others analysis managers. + void crossRegisterProxies(LoopAnalysisManager &LAM, + FunctionAnalysisManager &FAM, + CGSCCAnalysisManager &CGAM, + ModuleAnalysisManager &MAM); + /// \brief Registers all available module analysis passes. /// /// This is an interface that can be used to populate a \c /// ModuleAnalysisManager with all registered module analyses. Callers can - /// still manually register any additional analyses. + /// still manually register any additional analyses. Callers can also + /// pre-register analyses and this will not override those. void registerModuleAnalyses(ModuleAnalysisManager &MAM); /// \brief Registers all available CGSCC analysis passes. /// /// This is an interface that can be used to populate a \c CGSCCAnalysisManager /// with all registered CGSCC analyses. Callers can still manually register any - /// additional analyses. + /// additional analyses. Callers can also pre-register analyses and this will + /// not override those. void registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM); /// \brief Registers all available function analysis passes. /// /// This is an interface that can be used to populate a \c /// FunctionAnalysisManager with all registered function analyses. Callers can - /// still manually register any additional analyses. + /// still manually register any additional analyses. Callers can also + /// pre-register analyses and this will not override those. void registerFunctionAnalyses(FunctionAnalysisManager &FAM); + /// \brief Registers all available loop analysis passes. + /// + /// This is an interface that can be used to populate a \c LoopAnalysisManager + /// with all registered loop analyses. Callers can still manually register any + /// additional analyses. + void registerLoopAnalyses(LoopAnalysisManager &LAM); + + /// \brief Add a per-module default optimization pipeline to a pass manager. + /// + /// This provides a good default optimization pipeline for per-module + /// optimization and code generation without any link-time optimization. It + /// typically correspond to frontend "-O[123]" options for optimization + /// levels \c O1, \c O2 and \c O3 resp. + void addPerModuleDefaultPipeline(ModulePassManager &MPM, + OptimizationLevel Level, + bool DebugLogging = false); + + /// \brief Add a pre-link, LTO-targeting default optimization pipeline to + /// a pass manager. + /// + /// This adds the pre-link optimizations tuned to work well with a later LTO + /// run. It works to minimize the IR which needs to be analyzed without + /// making irreversible decisions which could be made better during the LTO + /// run. + void addLTOPreLinkDefaultPipeline(ModulePassManager &MPM, + OptimizationLevel Level, + bool DebugLogging = false); + + /// \brief Add an LTO default optimization pipeline to a pass manager. + /// + /// This provides a good default optimization pipeline for link-time + /// optimization and code generation. It is particularly tuned to fit well + /// when IR coming into the LTO phase was first run through \c + /// addPreLinkLTODefaultPipeline, and the two coordinate closely. + void addLTODefaultPipeline(ModulePassManager &MPM, OptimizationLevel Level, + bool DebugLogging = false); + /// \brief Parse a textual pass pipeline description into a \c ModulePassManager. /// /// The format of the textual pass pipeline description looks something like: @@ -87,10 +224,32 @@ public: bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool VerifyEachPass = true, bool DebugLogging = false); + /// Parse a textual alias analysis pipeline into the provided AA manager. + /// + /// The format of the textual AA pipeline is a comma separated list of AA + /// pass names: + /// + /// basic-aa,globals-aa,... + /// + /// The AA manager is set up such that the provided alias analyses are tried + /// in the order specified. See the \c AAManaager documentation for details + /// about the logic used. This routine just provides the textual mapping + /// between AA names and the analyses to register with the manager. + /// + /// Returns false if the text cannot be parsed cleanly. The specific state of + /// the \p AA manager is unspecified if such an error is encountered and this + /// returns false. + bool parseAAPipeline(AAManager &AA, StringRef PipelineText); + private: - bool parseModulePassName(ModulePassManager &MPM, StringRef Name); + bool parseModulePassName(ModulePassManager &MPM, StringRef Name, + bool DebugLogging); bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name); bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name); + bool parseLoopPassName(LoopPassManager &LPM, StringRef Name); + bool parseAAPassName(AAManager &AA, StringRef Name); + bool parseLoopPassPipeline(LoopPassManager &LPM, StringRef &PipelineText, + bool VerifyEachPass, bool DebugLogging); bool parseFunctionPassPipeline(FunctionPassManager &FPM, StringRef &PipelineText, bool VerifyEachPass, bool DebugLogging); @@ -99,7 +258,6 @@ private: bool parseModulePassPipeline(ModulePassManager &MPM, StringRef &PipelineText, bool VerifyEachPass, bool DebugLogging); }; - } #endif diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index 92a991eb39ba..6afde56122f0 100644 --- a/include/llvm/ProfileData/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -23,13 +23,13 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include <system_error> #include <tuple> namespace llvm { namespace coverage { + enum class coveragemap_error { success = 0, eof, @@ -38,14 +38,37 @@ enum class coveragemap_error { truncated, malformed }; -} // end of coverage namespace. + +const std::error_category &coveragemap_category(); + +inline std::error_code make_error_code(coveragemap_error E) { + return std::error_code(static_cast<int>(E), coveragemap_category()); } -namespace std { -template <> -struct is_error_code_enum<llvm::coverage::coveragemap_error> : std::true_type { +class CoverageMapError : public ErrorInfo<CoverageMapError> { +public: + CoverageMapError(coveragemap_error Err) : Err(Err) { + assert(Err != coveragemap_error::success && "Not an error"); + } + + std::string message() const override; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + coveragemap_error get() const { return Err; } + + static char ID; + +private: + coveragemap_error Err; }; -} + +} // end of coverage namespace. +} // end of llvm namespace namespace llvm { class IndexedInstrProfReader; @@ -265,7 +288,7 @@ public: /// \brief Return the number of times that a region of code associated with /// this counter was executed. - ErrorOr<int64_t> evaluate(const Counter &C) const; + Expected<int64_t> evaluate(const Counter &C) const; }; /// \brief Code coverage information for a single function. @@ -370,13 +393,6 @@ struct CoverageSegment { return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); } - - void setCount(uint64_t NewCount) { - Count = NewCount; - HasCount = true; - } - - void addCount(uint64_t NewCount) { setCount(Count + NewCount); } }; /// \brief Coverage information to be processed or displayed. @@ -400,14 +416,14 @@ public: Expansions(std::move(RHS.Expansions)) {} /// \brief Get the name of the file this data covers. - StringRef getFilename() { return Filename; } + StringRef getFilename() const { return Filename; } std::vector<CoverageSegment>::iterator begin() { return Segments.begin(); } std::vector<CoverageSegment>::iterator end() { return Segments.end(); } bool empty() { return Segments.empty(); } /// \brief Expansions that can be further processed. - std::vector<ExpansionRecord> getExpansions() { return Expansions; } + ArrayRef<ExpansionRecord> getExpansions() { return Expansions; } }; /// \brief The mapping of profile information to coverage data. @@ -422,12 +438,12 @@ class CoverageMapping { public: /// \brief Load the coverage mapping using the given readers. - static ErrorOr<std::unique_ptr<CoverageMapping>> + static Expected<std::unique_ptr<CoverageMapping>> load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader); /// \brief Load the coverage mapping from the given files. - static ErrorOr<std::unique_ptr<CoverageMapping>> + static Expected<std::unique_ptr<CoverageMapping>> load(StringRef ObjectFilename, StringRef ProfileFilename, StringRef Arch = StringRef()); @@ -445,7 +461,7 @@ public: /// The given filename must be the name as recorded in the coverage /// information. That is, only names returned from getUniqueSourceFiles will /// yield a result. - CoverageData getCoverageForFile(StringRef Filename); + CoverageData getCoverageForFile(StringRef Filename) const; /// \brief Gets all of the functions covered by this profile. iterator_range<FunctionRecordIterator> getCoveredFunctions() const { @@ -464,21 +480,16 @@ public: /// /// Functions that are instantiated more than once, such as C++ template /// specializations, have distinct coverage records for each instantiation. - std::vector<const FunctionRecord *> getInstantiations(StringRef Filename); + std::vector<const FunctionRecord *> + getInstantiations(StringRef Filename) const; /// \brief Get the coverage for a particular function. - CoverageData getCoverageForFunction(const FunctionRecord &Function); + CoverageData getCoverageForFunction(const FunctionRecord &Function) const; /// \brief Get the coverage for an expansion within a coverage set. - CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion); + CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; }; -const std::error_category &coveragemap_category(); - -inline std::error_code make_error_code(coveragemap_error E) { - return std::error_code(static_cast<int>(E), coveragemap_category()); -} - // Profile coverage map has the following layout: // [CoverageMapFileHeader] // [ArrayStart] @@ -488,9 +499,11 @@ inline std::error_code make_error_code(coveragemap_error E) { // [ArrayEnd] // [Encoded Region Mapping Data] LLVM_PACKED_START -template <class IntPtrT> struct CovMapFunctionRecord { +template <class IntPtrT> struct CovMapFunctionRecordV1 { +#define COVMAP_V1 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; #include "llvm/ProfileData/InstrProfData.inc" +#undef COVMAP_V1 // Return the structural hash associated with the function. template <support::endianness Endian> uint64_t getFuncHash() const { @@ -506,16 +519,41 @@ template <class IntPtrT> struct CovMapFunctionRecord { } // Return the PGO name of the function */ template <support::endianness Endian> - std::error_code getFuncName(InstrProfSymtab &ProfileNames, - StringRef &FuncName) const { + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { IntPtrT NameRef = getFuncNameRef<Endian>(); uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); FuncName = ProfileNames.getFuncName(NameRef, NameS); if (NameS && FuncName.empty()) - return coveragemap_error::malformed; - return std::error_code(); + return make_error<CoverageMapError>(coveragemap_error::malformed); + return Error::success(); + } +}; + +struct CovMapFunctionRecord { +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" + + // Return the structural hash associated with the function. + template <support::endianness Endian> uint64_t getFuncHash() const { + return support::endian::byte_swap<uint64_t, Endian>(FuncHash); + } + // Return the coverage map data size for the funciton. + template <support::endianness Endian> uint32_t getDataSize() const { + return support::endian::byte_swap<uint32_t, Endian>(DataSize); + } + // Return function lookup key. The value is consider opaque. + template <support::endianness Endian> uint64_t getFuncNameRef() const { + return support::endian::byte_swap<uint64_t, Endian>(NameRef); + } + // Return the PGO name of the function */ + template <support::endianness Endian> + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { + uint64_t NameRef = getFuncNameRef<Endian>(); + FuncName = ProfileNames.getFuncName(NameRef); + return Error::success(); } }; + // Per module coverage mapping data header, i.e. CoverageMapFileHeader // documented above. struct CovMapHeader { @@ -537,10 +575,24 @@ struct CovMapHeader { LLVM_PACKED_END -enum CoverageMappingVersion { - CoverageMappingVersion1 = 0, - // The current versin is Version1 - CoverageMappingCurrentVersion = INSTR_PROF_COVMAP_VERSION +enum CovMapVersion { + Version1 = 0, + // Function's name reference from CovMapFuncRecord is changed from raw + // name string pointer to MD5 to support name section compression. Name + // section is also compressed. + Version2 = 1, + // The current version is Version2 + CurrentVersion = INSTR_PROF_COVMAP_VERSION +}; + +template <int CovMapVersion, class IntPtrT> struct CovMapTraits { + typedef CovMapFunctionRecord CovMapFuncRecordType; + typedef uint64_t NameRefType; +}; + +template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> { + typedef CovMapFunctionRecordV1<IntPtrT> CovMapFuncRecordType; + typedef IntPtrT NameRefType; }; } // end namespace coverage diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index 38fb4680476b..db907f128d93 100644 --- a/include/llvm/ProfileData/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -19,7 +19,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -69,7 +69,7 @@ public: class CoverageMappingReader { public: - virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0; + virtual Error readNextRecord(CoverageMappingRecord &Record) = 0; CoverageMappingIterator begin() { return CoverageMappingIterator(this); } CoverageMappingIterator end() { return CoverageMappingIterator(); } virtual ~CoverageMappingReader() {} @@ -82,10 +82,10 @@ protected: RawCoverageReader(StringRef Data) : Data(Data) {} - std::error_code readULEB128(uint64_t &Result); - std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1); - std::error_code readSize(uint64_t &Result); - std::error_code readString(StringRef &Result); + Error readULEB128(uint64_t &Result); + Error readIntMax(uint64_t &Result, uint64_t MaxPlus1); + Error readSize(uint64_t &Result); + Error readString(StringRef &Result); }; /// \brief Reader for the raw coverage filenames. @@ -100,7 +100,17 @@ public: RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames) : RawCoverageReader(Data), Filenames(Filenames) {} - std::error_code read(); + Error read(); +}; + +/// \brief Checks if the given coverage mapping data is exported for +/// an unused function. +class RawCoverageMappingDummyChecker : public RawCoverageReader { +public: + RawCoverageMappingDummyChecker(StringRef MappingData) + : RawCoverageReader(MappingData) {} + + Expected<bool> isDummy(); }; /// \brief Reader for the raw coverage mapping data. @@ -125,12 +135,12 @@ public: Filenames(Filenames), Expressions(Expressions), MappingRegions(MappingRegions) {} - std::error_code read(); + Error read(); private: - std::error_code decodeCounter(unsigned Value, Counter &C); - std::error_code readCounter(Counter &C); - std::error_code + Error decodeCounter(unsigned Value, Counter &C); + Error readCounter(Counter &C); + Error readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID, size_t NumFileIDs); }; @@ -140,14 +150,14 @@ private: class BinaryCoverageReader : public CoverageMappingReader { public: struct ProfileMappingRecord { - CoverageMappingVersion Version; + CovMapVersion Version; StringRef FunctionName; uint64_t FunctionHash; StringRef CoverageMapping; size_t FilenamesBegin; size_t FilenamesSize; - ProfileMappingRecord(CoverageMappingVersion Version, StringRef FunctionName, + ProfileMappingRecord(CovMapVersion Version, StringRef FunctionName, uint64_t FunctionHash, StringRef CoverageMapping, size_t FilenamesBegin, size_t FilenamesSize) : Version(Version), FunctionName(FunctionName), @@ -158,6 +168,7 @@ public: private: std::vector<StringRef> Filenames; std::vector<ProfileMappingRecord> MappingRecords; + InstrProfSymtab ProfileNames; size_t CurrentRecord; std::vector<StringRef> FunctionsFilenames; std::vector<CounterExpression> Expressions; @@ -169,11 +180,11 @@ private: BinaryCoverageReader() : CurrentRecord(0) {} public: - static ErrorOr<std::unique_ptr<BinaryCoverageReader>> + static Expected<std::unique_ptr<BinaryCoverageReader>> create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, StringRef Arch); - std::error_code readNextRecord(CoverageMappingRecord &Record) override; + Error readNextRecord(CoverageMappingRecord &Record) override; }; } // end namespace coverage diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h index 2e3b0378d032..10269cc50f35 100644 --- a/include/llvm/ProfileData/CoverageMappingWriter.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -17,7 +17,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/Support/raw_ostream.h" namespace llvm { diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index c84d8d24f206..75646b761659 100644 --- a/include/llvm/ProfileData/InstrProf.h +++ b/include/llvm/ProfileData/InstrProf.h @@ -1,4 +1,4 @@ -//=-- InstrProf.h - Instrumented profiling format support ---------*- C++ -*-=// +//===-- InstrProf.h - Instrumented profiling format support -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -13,18 +13,20 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_INSTRPROF_H_ -#define LLVM_PROFILEDATA_INSTRPROF_H_ +#ifndef LLVM_PROFILEDATA_INSTRPROF_H +#define LLVM_PROFILEDATA_INSTRPROF_H #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Metadata.h" #include "llvm/ProfileData/InstrProfData.inc" +#include "llvm/ProfileData/ProfileCommon.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MD5.h" +#include "llvm/Support/MathExtras.h" #include <cstdint> #include <list> #include <system_error> @@ -56,6 +58,20 @@ inline StringRef getInstrProfDataSectionName(bool AddSegment) { : INSTR_PROF_DATA_SECT_NAME_STR; } +/// Return the name of data section containing pointers to value profile +/// counters/nodes. +inline StringRef getInstrProfValuesSectionName(bool AddSegment) { + return AddSegment ? "__DATA," INSTR_PROF_VALS_SECT_NAME_STR + : INSTR_PROF_VALS_SECT_NAME_STR; +} + +/// Return the name of data section containing nodes holdling value +/// profiling data. +inline StringRef getInstrProfVNodesSectionName(bool AddSegment) { + return AddSegment ? "__DATA," INSTR_PROF_VNODES_SECT_NAME_STR + : INSTR_PROF_VNODES_SECT_NAME_STR; +} + /// Return the name profile runtime entry point to do value profiling /// for a given site. inline StringRef getInstrProfValueProfFuncName() { @@ -78,10 +94,22 @@ inline StringRef getInstrProfDataVarPrefix() { return "__profd_"; } /// Return the name prefix of profile counter variables. inline StringRef getInstrProfCountersVarPrefix() { return "__profc_"; } +/// Return the name prefix of value profile variables. +inline StringRef getInstrProfValuesVarPrefix() { return "__profvp_"; } + +/// Return the name of value profile node array variables: +inline StringRef getInstrProfVNodesVarName() { return "__llvm_prf_vnodes"; } + /// Return the name prefix of the COMDAT group for instrumentation variables /// associated with a COMDAT function. inline StringRef getInstrProfComdatPrefix() { return "__profv_"; } +/// Return the name of the variable holding the strings (possibly compressed) +/// of all function's PGO names. +inline StringRef getInstrProfNamesVarName() { + return "__llvm_prf_nm"; +} + /// Return the name of a covarage mapping variable (internal linkage) /// for each instrumented source module. Such variables are allocated /// in the __llvm_covmap section. @@ -90,10 +118,12 @@ inline StringRef getCoverageMappingVarName() { } /// Return the name of the internal variable recording the array -/// of PGO name vars referenced by the coverage mapping, The owning +/// of PGO name vars referenced by the coverage mapping. The owning /// functions of those names are not emitted by FE (e.g, unused inline /// functions.) -inline StringRef getCoverageNamesVarName() { return "__llvm_coverage_names"; } +inline StringRef getCoverageUnusedNamesVarName() { + return "__llvm_coverage_names"; +} /// Return the name of function that registers all the per-function control /// data at program startup time by calling __llvm_register_function. This @@ -110,6 +140,11 @@ inline StringRef getInstrProfRegFuncName() { return "__llvm_profile_register_function"; } +/// Return the name of the runtime interface that registers the PGO name strings. +inline StringRef getInstrProfNamesRegFuncName() { + return "__llvm_profile_register_names_function"; +} + /// Return the name of the runtime initialization method that is generated by /// the compiler. The function calls __llvm_profile_register_functions and /// __llvm_profile_override_default_filename functions if needed. This function @@ -135,9 +170,13 @@ inline StringRef getInstrProfFileOverriderFuncName() { return "__llvm_profile_override_default_filename"; } +/// Return the marker used to separate PGO names during serialization. +inline StringRef getInstrProfNameSeparator() { return "\01"; } + /// Return the modified name for function \c F suitable to be -/// used the key for profile lookup. -std::string getPGOFuncName(const Function &F, +/// used the key for profile lookup. Variable \c InLTO indicates if this +/// is called in LTO optimization passes. +std::string getPGOFuncName(const Function &F, bool InLTO = false, uint64_t Version = INSTR_PROF_INDEX_VERSION); /// Return the modified name for a function suitable to be @@ -149,10 +188,16 @@ std::string getPGOFuncName(StringRef RawFuncName, StringRef FileName, uint64_t Version = INSTR_PROF_INDEX_VERSION); +/// Return the name of the global variable used to store a function +/// name in PGO instrumentation. \c FuncName is the name of the function +/// returned by the \c getPGOFuncName call. +std::string getPGOFuncNameVarName(StringRef FuncName, + GlobalValue::LinkageTypes Linkage); + /// Create and return the global variable for function name used in PGO /// instrumentation. \c FuncName is the name of the function returned /// by \c getPGOFuncName call. -GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName); +GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName); /// Create and return the global variable for function name used in PGO /// instrumentation. /// \c FuncName is the name of the function @@ -160,13 +205,14 @@ GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName); /// and \c Linkage is the linkage of the instrumented function. GlobalVariable *createPGOFuncNameVar(Module &M, GlobalValue::LinkageTypes Linkage, - StringRef FuncName); + StringRef PGOFuncName); /// Return the initializer in string of the PGO name var \c NameVar. StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar); /// Given a PGO function name, remove the filename prefix and return /// the original (static) function name. -StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName); +StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, + StringRef FileName = "<unknown>"); /// Given a vector of strings (function PGO names) \c NameStrs, the /// method generates a combined string \c Result thatis ready to be @@ -174,22 +220,59 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName); /// The first field is the legnth of the uncompressed strings, and the /// the second field is the length of the zlib-compressed string. /// Both fields are encoded in ULEB128. If \c doCompress is false, the -/// third field is the uncompressed strings; otherwise it is the -/// compressed string. When the string compression is off, the +/// third field is the uncompressed strings; otherwise it is the +/// compressed string. When the string compression is off, the /// second field will have value zero. -int collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs, - bool doCompression, std::string &Result); +Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs, + bool doCompression, std::string &Result); /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. -int collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars, - std::string &Result); +Error collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars, + std::string &Result, bool doCompression = true); class InstrProfSymtab; /// \c NameStrings is a string composed of one of more sub-strings encoded in -/// the -/// format described above. The substrings are seperated by 0 or more zero -/// bytes. -/// This method decodes the string and populates the \c Symtab. -int readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab); +/// the format described above. The substrings are seperated by 0 or more zero +/// bytes. This method decodes the string and populates the \c Symtab. +Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab); + +enum InstrProfValueKind : uint32_t { +#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, +#include "llvm/ProfileData/InstrProfData.inc" +}; + +struct InstrProfRecord; + +/// Get the value profile data for value site \p SiteIdx from \p InstrProfR +/// and annotate the instruction \p Inst with the value profile meta data. +/// Annotate up to \p MaxMDCount (default 3) number of records per value site. +void annotateValueSite(Module &M, Instruction &Inst, + const InstrProfRecord &InstrProfR, + InstrProfValueKind ValueKind, uint32_t SiteIndx, + uint32_t MaxMDCount = 3); +/// Same as the above interface but using an ArrayRef, as well as \p Sum. +void annotateValueSite(Module &M, Instruction &Inst, + ArrayRef<InstrProfValueData> VDs, + uint64_t Sum, InstrProfValueKind ValueKind, + uint32_t MaxMDCount); + +/// Extract the value profile data from \p Inst which is annotated with +/// value profile meta data. Return false if there is no value data annotated, +/// otherwise return true. +bool getValueProfDataFromInst(const Instruction &Inst, + InstrProfValueKind ValueKind, + uint32_t MaxNumValueData, + InstrProfValueData ValueData[], + uint32_t &ActualNumValueData, uint64_t &TotalC); + +inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; } + +/// Return the PGOFuncName meta data associated with a function. +MDNode *getPGOFuncNameMetadata(const Function &F); + +/// Create the PGOFuncName meta data if PGOFuncName is different from +/// function's raw name. This should only apply to internal linkage functions +/// declared by users only. +void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName); const std::error_category &instrprof_category(); @@ -208,26 +291,104 @@ enum class instrprof_error { hash_mismatch, count_mismatch, counter_overflow, - value_site_count_mismatch + value_site_count_mismatch, + compress_failed, + uncompress_failed }; inline std::error_code make_error_code(instrprof_error E) { return std::error_code(static_cast<int>(E), instrprof_category()); } -inline instrprof_error MergeResult(instrprof_error &Accumulator, - instrprof_error Result) { - // Prefer first error encountered as later errors may be secondary effects of - // the initial problem. - if (Accumulator == instrprof_error::success && - Result != instrprof_error::success) - Accumulator = Result; - return Accumulator; -} +class InstrProfError : public ErrorInfo<InstrProfError> { +public: + InstrProfError(instrprof_error Err) : Err(Err) { + assert(Err != instrprof_error::success && "Not an error"); + } -enum InstrProfValueKind : uint32_t { -#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, -#include "llvm/ProfileData/InstrProfData.inc" + std::string message() const override; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + instrprof_error get() const { return Err; } + + /// Consume an Error and return the raw enum value contained within it. The + /// Error must either be a success value, or contain a single InstrProfError. + static instrprof_error take(Error E) { + auto Err = instrprof_error::success; + handleAllErrors(std::move(E), [&Err](const InstrProfError &IPE) { + assert(Err == instrprof_error::success && "Multiple errors encountered"); + Err = IPE.get(); + }); + return Err; + } + + static char ID; + +private: + instrprof_error Err; +}; + +class SoftInstrProfErrors { + /// Count the number of soft instrprof_errors encountered and keep track of + /// the first such error for reporting purposes. + + /// The first soft error encountered. + instrprof_error FirstError; + + /// The number of hash mismatches. + unsigned NumHashMismatches; + + /// The number of count mismatches. + unsigned NumCountMismatches; + + /// The number of counter overflows. + unsigned NumCounterOverflows; + + /// The number of value site count mismatches. + unsigned NumValueSiteCountMismatches; + +public: + SoftInstrProfErrors() + : FirstError(instrprof_error::success), NumHashMismatches(0), + NumCountMismatches(0), NumCounterOverflows(0), + NumValueSiteCountMismatches(0) {} + + ~SoftInstrProfErrors() { + assert(FirstError == instrprof_error::success && + "Unchecked soft error encountered"); + } + + /// Track a soft error (\p IE) and increment its associated counter. + void addError(instrprof_error IE); + + /// Get the number of hash mismatches. + unsigned getNumHashMismatches() const { return NumHashMismatches; } + + /// Get the number of count mismatches. + unsigned getNumCountMismatches() const { return NumCountMismatches; } + + /// Get the number of counter overflows. + unsigned getNumCounterOverflows() const { return NumCounterOverflows; } + + /// Get the number of value site count mismatches. + unsigned getNumValueSiteCountMismatches() const { + return NumValueSiteCountMismatches; + } + + /// Return the first encountered error and reset FirstError to a success + /// value. + Error takeError() { + if (FirstError == instrprof_error::success) + return Error::success(); + auto E = make_error<InstrProfError>(FirstError); + FirstError = instrprof_error::success; + return E; + } }; namespace object { @@ -250,27 +411,41 @@ public: private: StringRef Data; uint64_t Address; - // A map from MD5 hash keys to function name strings. - std::vector<std::pair<uint64_t, std::string>> HashNameMap; + // Unique name strings. + StringSet<> NameTab; + // A map from MD5 keys to function name strings. + std::vector<std::pair<uint64_t, StringRef>> MD5NameMap; + // A map from MD5 keys to function define. We only populate this map + // when build the Symtab from a Module. + std::vector<std::pair<uint64_t, Function *>> MD5FuncMap; // A map from function runtime address to function name MD5 hash. // This map is only populated and used by raw instr profile reader. AddrHashMap AddrToMD5Map; public: - InstrProfSymtab() : Data(), Address(0), HashNameMap(), AddrToMD5Map() {} + InstrProfSymtab() + : Data(), Address(0), NameTab(), MD5NameMap(), MD5FuncMap(), + AddrToMD5Map() {} /// Create InstrProfSymtab from an object file section which - /// contains function PGO names that are uncompressed. - /// This interface is used by CoverageMappingReader. - std::error_code create(object::SectionRef &Section); + /// contains function PGO names. When section may contain raw + /// string data or string data in compressed form. This method + /// only initialize the symtab with reference to the data and + /// the section base address. The decompression will be delayed + /// until before it is used. See also \c create(StringRef) method. + Error create(object::SectionRef &Section); /// This interface is used by reader of CoverageMapping test /// format. - inline std::error_code create(StringRef D, uint64_t BaseAddr); + inline Error create(StringRef D, uint64_t BaseAddr); /// \c NameStrings is a string composed of one of more sub-strings - /// encoded in the format described above. The substrings are - /// seperated by 0 or more zero bytes. This method decodes the - /// string and populates the \c Symtab. - inline std::error_code create(StringRef NameStrings); + /// encoded in the format described in \c collectPGOFuncNameStrings. + /// This method is a wrapper to \c readPGOFuncNameStrings method. + inline Error create(StringRef NameStrings); + /// A wrapper interface to populate the PGO symtab with functions + /// decls from module \c M. This interface is used by transformation + /// passes such as indirect function call promotion. Variable \c InLTO + /// indicates if this is called from LTO optimization passes. + void create(Module &M, bool InLTO = false); /// Create InstrProfSymtab from a set of names iteratable from /// \p IterRange. This interface is used by IndexedProfReader. template <typename NameIterRange> void create(const NameIterRange &IterRange); @@ -282,8 +457,10 @@ public: /// Update the symtab by adding \p FuncName to the table. This interface /// is used by the raw and text profile readers. void addFuncName(StringRef FuncName) { - HashNameMap.push_back(std::make_pair( - IndexedInstrProf::ComputeHash(FuncName), FuncName.str())); + auto Ins = NameTab.insert(FuncName); + if (Ins.second) + MD5NameMap.push_back(std::make_pair( + IndexedInstrProf::ComputeHash(FuncName), Ins.first->getKey())); } /// Map a function address to its name's MD5 hash. This interface /// is only used by the raw profiler reader. @@ -298,32 +475,37 @@ public: /// Return function's PGO name from the name's md5 hash value. /// If not found, return an empty string. inline StringRef getFuncName(uint64_t FuncMD5Hash); + /// Return function from the name's md5 hash. Return nullptr if not found. + inline Function *getFunction(uint64_t FuncMD5Hash); + /// Return the function's original assembly name by stripping off + /// the prefix attached (to symbols with priviate linkage). For + /// global functions, it returns the same string as getFuncName. + inline StringRef getOrigFuncName(uint64_t FuncMD5Hash); + /// Return the name section data. + inline StringRef getNameData() const { return Data; } }; -std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { +Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { Data = D; Address = BaseAddr; - return std::error_code(); + return Error::success(); } -std::error_code InstrProfSymtab::create(StringRef NameStrings) { - if (readPGOFuncNameStrings(NameStrings, *this)) - return make_error_code(instrprof_error::malformed); - return std::error_code(); +Error InstrProfSymtab::create(StringRef NameStrings) { + return readPGOFuncNameStrings(NameStrings, *this); } template <typename NameIterRange> void InstrProfSymtab::create(const NameIterRange &IterRange) { for (auto Name : IterRange) - HashNameMap.push_back( - std::make_pair(IndexedInstrProf::ComputeHash(Name), Name.str())); + addFuncName(Name); + finalizeSymtab(); } void InstrProfSymtab::finalizeSymtab() { - std::sort(HashNameMap.begin(), HashNameMap.end(), less_first()); - HashNameMap.erase(std::unique(HashNameMap.begin(), HashNameMap.end()), - HashNameMap.end()); + std::sort(MD5NameMap.begin(), MD5NameMap.end(), less_first()); + std::sort(MD5FuncMap.begin(), MD5FuncMap.end(), less_first()); std::sort(AddrToMD5Map.begin(), AddrToMD5Map.end(), less_first()); AddrToMD5Map.erase(std::unique(AddrToMD5Map.begin(), AddrToMD5Map.end()), AddrToMD5Map.end()); @@ -331,14 +513,34 @@ void InstrProfSymtab::finalizeSymtab() { StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) { auto Result = - std::lower_bound(HashNameMap.begin(), HashNameMap.end(), FuncMD5Hash, + std::lower_bound(MD5NameMap.begin(), MD5NameMap.end(), FuncMD5Hash, [](const std::pair<uint64_t, std::string> &LHS, uint64_t RHS) { return LHS.first < RHS; }); - if (Result != HashNameMap.end()) + if (Result != MD5NameMap.end() && Result->first == FuncMD5Hash) return Result->second; return StringRef(); } +Function* InstrProfSymtab::getFunction(uint64_t FuncMD5Hash) { + auto Result = + std::lower_bound(MD5FuncMap.begin(), MD5FuncMap.end(), FuncMD5Hash, + [](const std::pair<uint64_t, Function*> &LHS, + uint64_t RHS) { return LHS.first < RHS; }); + if (Result != MD5FuncMap.end() && Result->first == FuncMD5Hash) + return Result->second; + return nullptr; +} + +// See also getPGOFuncName implementation. These two need to be +// matched. +StringRef InstrProfSymtab::getOrigFuncName(uint64_t FuncMD5Hash) { + StringRef PGOName = getFuncName(FuncMD5Hash); + size_t S = PGOName.find_first_of(':'); + if (S == StringRef::npos) + return PGOName; + return PGOName.drop_front(S + 1); +} + struct InstrProfValueSiteRecord { /// Value profiling data pairs at a given value site. std::list<InstrProfValueData> ValueData; @@ -360,19 +562,21 @@ struct InstrProfValueSiteRecord { /// Merge data from another InstrProfValueSiteRecord /// Optionally scale merged counts by \p Weight. - instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1); + void merge(SoftInstrProfErrors &SIPE, InstrProfValueSiteRecord &Input, + uint64_t Weight = 1); /// Scale up value profile data counts. - instrprof_error scale(uint64_t Weight); + void scale(SoftInstrProfErrors &SIPE, uint64_t Weight); }; /// Profiling information for a single function. struct InstrProfRecord { - InstrProfRecord() {} + InstrProfRecord() : SIPE() {} InstrProfRecord(StringRef Name, uint64_t Hash, std::vector<uint64_t> Counts) - : Name(Name), Hash(Hash), Counts(std::move(Counts)) {} + : Name(Name), Hash(Hash), Counts(std::move(Counts)), SIPE() {} StringRef Name; uint64_t Hash; std::vector<uint64_t> Counts; + SoftInstrProfErrors SIPE; typedef std::vector<std::pair<uint64_t, uint64_t>> ValueMapType; @@ -387,13 +591,17 @@ struct InstrProfRecord { /// site: Site. inline uint32_t getNumValueDataForSite(uint32_t ValueKind, uint32_t Site) const; - /// Return the array of profiled values at \p Site. + /// Return the array of profiled values at \p Site. If \p TotalC + /// is not null, the total count of all target values at this site + /// will be stored in \c *TotalC. inline std::unique_ptr<InstrProfValueData[]> getValueForSite(uint32_t ValueKind, uint32_t Site, - uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const; - inline void - getValueForSite(InstrProfValueData Dest[], uint32_t ValueKind, uint32_t Site, - uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const; + uint64_t *TotalC = 0) const; + /// Get the target value/counts of kind \p ValueKind collected at site + /// \p Site and store the result in array \p Dest. Return the total + /// counts of all target values at this site. + inline uint64_t getValueForSite(InstrProfValueData Dest[], uint32_t ValueKind, + uint32_t Site) const; /// Reserve space for NumValueSites sites. inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites); /// Add ValueData for ValueKind at value Site. @@ -403,11 +611,11 @@ struct InstrProfRecord { /// Merge the counts in \p Other into this one. /// Optionally scale merged counts by \p Weight. - instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1); + void merge(InstrProfRecord &Other, uint64_t Weight = 1); /// Scale up profile counts (including value profile data) by /// \p Weight. - instrprof_error scale(uint64_t Weight); + void scale(uint64_t Weight); /// Sort value profile data (per site) by count. void sortValueData() { @@ -424,6 +632,9 @@ struct InstrProfRecord { getValueSitesForKind(Kind).clear(); } + /// Get the error contained within the record's soft error counter. + Error takeError() { return SIPE.takeError(); } + private: std::vector<InstrProfValueSiteRecord> IndirectCallSites; const std::vector<InstrProfValueSiteRecord> & @@ -450,10 +661,10 @@ private: // Merge Value Profile data from Src record to this record for ValueKind. // Scale merged value counts by \p Weight. - instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src, - uint64_t Weight); + void mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src, + uint64_t Weight); // Scale up value profile data count. - instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight); + void scaleValueProfData(uint32_t ValueKind, uint64_t Weight); }; uint32_t InstrProfRecord::getNumValueKinds() const { @@ -482,29 +693,35 @@ uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind, return getValueSitesForKind(ValueKind)[Site].ValueData.size(); } -std::unique_ptr<InstrProfValueData[]> InstrProfRecord::getValueForSite( - uint32_t ValueKind, uint32_t Site, - uint64_t (*ValueMapper)(uint32_t, uint64_t)) const { +std::unique_ptr<InstrProfValueData[]> +InstrProfRecord::getValueForSite(uint32_t ValueKind, uint32_t Site, + uint64_t *TotalC) const { + uint64_t Dummy; + uint64_t &TotalCount = (TotalC == 0 ? Dummy : *TotalC); uint32_t N = getNumValueDataForSite(ValueKind, Site); - if (N == 0) + if (N == 0) { + TotalCount = 0; return std::unique_ptr<InstrProfValueData[]>(nullptr); + } auto VD = llvm::make_unique<InstrProfValueData[]>(N); - getValueForSite(VD.get(), ValueKind, Site, ValueMapper); + TotalCount = getValueForSite(VD.get(), ValueKind, Site); return VD; } -void InstrProfRecord::getValueForSite(InstrProfValueData Dest[], - uint32_t ValueKind, uint32_t Site, - uint64_t (*ValueMapper)(uint32_t, - uint64_t)) const { +uint64_t InstrProfRecord::getValueForSite(InstrProfValueData Dest[], + uint32_t ValueKind, + uint32_t Site) const { uint32_t I = 0; + uint64_t TotalCount = 0; for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) { - Dest[I].Value = ValueMapper ? ValueMapper(ValueKind, V.Value) : V.Value; + Dest[I].Value = V.Value; Dest[I].Count = V.Count; + TotalCount = SaturatingAdd(TotalCount, V.Count); I++; } + return TotalCount; } void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) { @@ -532,27 +749,6 @@ void InstrProfValueSiteRecord::sortByCount() { ValueData.resize(max_s); } -/* -* Initialize the record for runtime value profile data. -* Return 0 if the initialization is successful, otherwise -* return 1. -*/ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes); - -/* Release memory allocated for the runtime record. */ -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord); - -/* Return the size of ValueProfData structure that can be used to store - the value profile data collected at runtime. */ -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record); - -/* Return a ValueProfData instance that stores the data collected at runtime. */ -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *Dst); - namespace IndexedInstrProf { enum class HashT : uint32_t { @@ -561,27 +757,38 @@ enum class HashT : uint32_t { Last = MD5 }; -static inline uint64_t MD5Hash(StringRef Str) { - MD5 Hash; - Hash.update(Str); - llvm::MD5::MD5Result Result; - Hash.final(Result); - // Return the least significant 8 bytes. Our MD5 implementation returns the - // result in little endian, so we may need to swap bytes. - using namespace llvm::support; - return endian::read<uint64_t, little, unaligned>(Result); -} - inline uint64_t ComputeHash(HashT Type, StringRef K) { switch (Type) { case HashT::MD5: - return IndexedInstrProf::MD5Hash(K); + return MD5Hash(K); } llvm_unreachable("Unhandled hash type"); } const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" -const uint64_t Version = INSTR_PROF_INDEX_VERSION; + +enum ProfVersion { + // Version 1 is the first version. In this version, the value of + // a key/value pair can only include profile data of a single function. + // Due to this restriction, the number of block counters for a given + // function is not recorded but derived from the length of the value. + Version1 = 1, + // The version 2 format supports recording profile data of multiple + // functions which share the same key in one value field. To support this, + // the number block counters is recorded as an uint64_t field right after the + // function structural hash. + Version2 = 2, + // Version 3 supports value profile data. The value profile data is expected + // to follow the block counter profile data. + Version3 = 3, + // In this version, profile summary data \c IndexedInstrProf::Summary is + // stored after the profile header. + Version4 = 4, + // The current version is 4. + CurrentVersion = INSTR_PROF_INDEX_VERSION +}; +const uint64_t Version = ProfVersion::CurrentVersion; + const HashT HashType = HashT::MD5; inline uint64_t ComputeHash(StringRef K) { return ComputeHash(HashType, K); } @@ -591,15 +798,104 @@ inline uint64_t ComputeHash(StringRef K) { return ComputeHash(HashType, K); } struct Header { uint64_t Magic; uint64_t Version; - uint64_t MaxFunctionCount; + uint64_t Unused; // Becomes unused since version 4 uint64_t HashType; uint64_t HashOffset; }; +// Profile summary data recorded in the profile data file in indexed +// format. It is introduced in version 4. The summary data follows +// right after the profile file header. +struct Summary { + + struct Entry { + uint64_t Cutoff; ///< The required percentile of total execution count. + uint64_t + MinBlockCount; ///< The minimum execution count for this percentile. + uint64_t NumBlocks; ///< Number of blocks >= the minumum execution count. + }; + // The field kind enumerator to assigned value mapping should remain + // unchanged when a new kind is added or an old kind gets deleted in + // the future. + enum SummaryFieldKind { + /// The total number of functions instrumented. + TotalNumFunctions = 0, + /// Total number of instrumented blocks/edges. + TotalNumBlocks = 1, + /// The maximal execution count among all functions. + /// This field does not exist for profile data from IR based + /// instrumentation. + MaxFunctionCount = 2, + /// Max block count of the program. + MaxBlockCount = 3, + /// Max internal block count of the program (excluding entry blocks). + MaxInternalBlockCount = 4, + /// The sum of all instrumented block counts. + TotalBlockCount = 5, + NumKinds = TotalBlockCount + 1 + }; + + // The number of summmary fields following the summary header. + uint64_t NumSummaryFields; + // The number of Cutoff Entries (Summary::Entry) following summary fields. + uint64_t NumCutoffEntries; + + static uint32_t getSize(uint32_t NumSumFields, uint32_t NumCutoffEntries) { + return sizeof(Summary) + NumCutoffEntries * sizeof(Entry) + + NumSumFields * sizeof(uint64_t); + } + + const uint64_t *getSummaryDataBase() const { + return reinterpret_cast<const uint64_t *>(this + 1); + } + uint64_t *getSummaryDataBase() { + return reinterpret_cast<uint64_t *>(this + 1); + } + const Entry *getCutoffEntryBase() const { + return reinterpret_cast<const Entry *>( + &getSummaryDataBase()[NumSummaryFields]); + } + Entry *getCutoffEntryBase() { + return reinterpret_cast<Entry *>(&getSummaryDataBase()[NumSummaryFields]); + } + + uint64_t get(SummaryFieldKind K) const { + return getSummaryDataBase()[K]; + } + + void set(SummaryFieldKind K, uint64_t V) { + getSummaryDataBase()[K] = V; + } + + const Entry &getEntry(uint32_t I) const { return getCutoffEntryBase()[I]; } + void setEntry(uint32_t I, const ProfileSummaryEntry &E) { + Entry &ER = getCutoffEntryBase()[I]; + ER.Cutoff = E.Cutoff; + ER.MinBlockCount = E.MinCount; + ER.NumBlocks = E.NumCounts; + } + + Summary(uint32_t Size) { memset(this, 0, Size); } + void operator delete(void *ptr) { ::operator delete(ptr); } + + Summary() = delete; +}; + +inline std::unique_ptr<Summary> allocSummary(uint32_t TotalSize) { + return std::unique_ptr<Summary>(new (::operator new(TotalSize)) + Summary(TotalSize)); +} } // end namespace IndexedInstrProf namespace RawInstrProf { +// Version 1: First version +// Version 2: Added value profile data section. Per-function control data +// struct has more fields to describe value profile information. +// Version 3: Compressed name section support. Function PGO name reference +// from control data struct is changed from raw pointer to Name's MD5 value. +// Version 4: ValueDataBegin and ValueDataSizes fields are removed from the +// raw header. const uint64_t Version = INSTR_PROF_RAW_VERSION; template <class IntPtrT> inline uint64_t getMagic(); @@ -630,13 +926,8 @@ struct Header { #include "llvm/ProfileData/InstrProfData.inc" }; -} // end namespace RawInstrProf +} // end namespace RawInstrProf } // end namespace llvm -namespace std { -template <> -struct is_error_code_enum<llvm::instrprof_error> : std::true_type {}; -} - -#endif // LLVM_PROFILEDATA_INSTRPROF_H_ +#endif // LLVM_PROFILEDATA_INSTRPROF_H diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc index 33c7d94aea2a..4138e18fa22f 100644 --- a/include/llvm/ProfileData/InstrProfData.inc +++ b/include/llvm/ProfileData/InstrProfData.inc @@ -57,6 +57,12 @@ * \*===----------------------------------------------------------------------===*/ +/* Functions marked with INSTR_PROF_VISIBILITY must have hidden visibility in + * the compiler runtime. */ +#ifndef INSTR_PROF_VISIBILITY +#define INSTR_PROF_VISIBILITY +#endif + /* INSTR_PROF_DATA start. */ /* Definition of member fields of the per-function control structure. */ #ifndef INSTR_PROF_DATA @@ -64,29 +70,57 @@ #else #define INSTR_PROF_DATA_DEFINED #endif - -INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ - ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \ - NamePtr->getType()->getPointerElementType()->getArrayNumElements())) -INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ - ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) +INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ + ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ + IndexedInstrProf::ComputeHash(getPGOFuncNameVarInitializer(Inc->getName())))) INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) -INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \ - ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx))) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ ConstantExpr::getBitCast(CounterPtr, \ llvm::Type::getInt64PtrTy(Ctx))) +/* This is used to map function pointers for the indirect call targets to + * function name hashes during the conversion from raw to merged profile + * data. + */ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ FunctionAddr) INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ - ConstantPointerNull::get(Int8PtrTy)) + ValuesPtrExpr) +INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ + ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) #undef INSTR_PROF_DATA /* INSTR_PROF_DATA end. */ + +/* This is an internal data structure used by value profiler. It + * is defined here to allow serialization code sharing by LLVM + * to be used in unit test. + * + * typedef struct ValueProfNode { + * // InstrProfValueData VData; + * uint64_t Value; + * uint64_t Count; + * struct ValueProfNode *Next; + * } ValueProfNode; + */ +/* INSTR_PROF_VALUE_NODE start. */ +#ifndef INSTR_PROF_VALUE_NODE +#define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) +#else +#define INSTR_PROF_DATA_DEFINED +#endif +INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Value, \ + ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) +INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Count, \ + ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) +INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \ + ConstantInt::get(llvm::Type::GetInt8PtrTy(Ctx), 0)) +#undef INSTR_PROF_VALUE_NODE +/* INSTR_PROF_VALUE_NODE end. */ + /* INSTR_PROF_RAW_HEADER start */ /* Definition of member fields of the raw profile header data structure. */ #ifndef INSTR_PROF_RAW_HEADER @@ -102,8 +136,6 @@ INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) -INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize) -INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ @@ -132,6 +164,15 @@ VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) #else #define INSTR_PROF_DATA_DEFINED #endif +/* For indirect function call value profiling, the addresses of the target + * functions are profiled by the instrumented code. The target addresses are + * written in the raw profile data and converted to target function name's MD5 + * hash by the profile reader during deserialization. Typically, this happens + * when the the raw profile data is read during profile merging. + * + * For this remapping the ProfData is used. ProfData contains both the function + * name hash and the function address. + */ VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) /* These two kinds must be the last to be * declared. This is to make sure the string @@ -153,12 +194,18 @@ VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) #else #define INSTR_PROF_DATA_DEFINED #endif +#ifdef COVMAP_V1 COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \ llvm::Type::getInt8PtrTy(Ctx))) COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ - llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ + llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \ NameValue.size())) +#else +COVMAP_FUNC_RECORD(const int64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ + llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ + llvm::IndexedInstrProf::ComputeHash(NameValue))) +#endif COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ CoverageMapping.size())) @@ -182,7 +229,7 @@ COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \ COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize)) COVMAP_HEADER(uint32_t, Int32Ty, Version, \ - llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion)) + llvm::ConstantInt::get(Int32Ty, CovMapVersion::CurrentVersion)) #undef COVMAP_HEADER /* COVMAP_HEADER end. */ @@ -281,16 +328,15 @@ typedef struct ValueProfData { static std::unique_ptr<ValueProfData> serializeFrom(const InstrProfRecord &Record); /*! - * Check the integrity of the record. Return the error code when - * an error is detected, otherwise return instrprof_error::success. + * Check the integrity of the record. */ - instrprof_error checkIntegrity(); + Error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ - static ErrorOr<std::unique_ptr<ValueProfData>> + static Expected<std::unique_ptr<ValueProfData>> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); @@ -343,46 +389,18 @@ typedef struct ValueProfRecordClosure { */ uint64_t (*RemapValueData)(uint32_t, uint64_t Value); void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K, - uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)); + uint32_t S); ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); } ValueProfRecordClosure; -/* - * A wrapper struct that represents value profile runtime data. - * Like InstrProfRecord class which is used by profiling host tools, - * ValueProfRuntimeRecord also implements the abstract intefaces defined in - * ValueProfRecordClosure so that the runtime data can be serialized using - * shared C implementation. In this structure, NumValueSites and Nodes - * members are the primary fields while other fields hold the derived - * information for fast implementation of closure interfaces. - */ -typedef struct ValueProfRuntimeRecord { - /* Number of sites for each value profile kind. */ - const uint16_t *NumValueSites; - /* An array of linked-list headers. The size of of the array is the - * total number of value profile sites : sum(NumValueSites[*])). Each - * linked-list stores the values profiled for a value profile site. */ - ValueProfNode **Nodes; - - /* Total number of value profile kinds which have at least one - * value profile sites. */ - uint32_t NumValueKinds; - /* An array recording the number of values tracked at each site. - * The size of the array is TotalNumValueSites. */ - uint8_t *SiteCountArray[IPVK_Last + 1]; - ValueProfNode **NodesKind[IPVK_Last + 1]; -} ValueProfRuntimeRecord; - -/* Forward declarations of C interfaces. */ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes); -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord); -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record); -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *Dst); -uint32_t getNumValueKindsRT(const void *R); +INSTR_PROF_VISIBILITY ValueProfRecord * +getFirstValueProfRecord(ValueProfData *VPD); +INSTR_PROF_VISIBILITY ValueProfRecord * +getValueProfRecordNext(ValueProfRecord *VPR); +INSTR_PROF_VISIBILITY InstrProfValueData * +getValueProfRecordValueData(ValueProfRecord *VPR); +INSTR_PROF_VISIBILITY uint32_t +getValueProfRecordHeaderSize(uint32_t NumValueSites); #undef INSTR_PROF_VALUE_PROF_DATA #endif /* INSTR_PROF_VALUE_PROF_DATA */ @@ -392,8 +410,10 @@ uint32_t getNumValueKindsRT(const void *R); #define INSTR_PROF_DATA_DEFINED #ifdef __cplusplus #define INSTR_PROF_INLINE inline +#define INSTR_PROF_NULLPTR nullptr #else #define INSTR_PROF_INLINE +#define INSTR_PROF_NULLPTR NULL #endif #ifndef offsetof @@ -404,7 +424,7 @@ uint32_t getNumValueKindsRT(const void *R); * \brief Return the \c ValueProfRecord header size including the * padding bytes. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + sizeof(uint8_t) * NumValueSites; @@ -417,7 +437,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { * \brief Return the total size of the value profile record including the * header and the value data. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData) { return getValueProfRecordHeaderSize(NumValueSites) + @@ -427,7 +447,7 @@ uint32_t getValueProfRecordSize(uint32_t NumValueSites, /*! * \brief Return the pointer to the start of value data array. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( This->NumValueSites)); @@ -436,7 +456,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { /*! * \brief Return the total number of value data for \c This record. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t NumValueData = 0; uint32_t I; @@ -448,7 +468,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { /*! * \brief Use this method to advance to the next \c This \c ValueProfRecord. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { uint32_t NumValueData = getValueProfRecordNumValueData(This); return (ValueProfRecord *)((char *)This + @@ -459,7 +479,7 @@ ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { /*! * \brief Return the first \c ValueProfRecord instance. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); } @@ -470,13 +490,11 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ -uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { +INSTR_PROF_VISIBILITY uint32_t +getValueProfDataSize(ValueProfRecordClosure *Closure) { uint32_t Kind; uint32_t TotalSize = sizeof(ValueProfData); const void *Record = Closure->Record; - uint32_t NumValueKinds = Closure->GetNumValueKinds(Record); - if (NumValueKinds == 0) - return TotalSize; for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind); @@ -492,9 +510,10 @@ uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { * Extract value profile data of a function for the profile kind \c ValueKind * from the \c Closure and serialize the data into \c This record instance. */ -void serializeValueProfRecordFrom(ValueProfRecord *This, - ValueProfRecordClosure *Closure, - uint32_t ValueKind, uint32_t NumValueSites) { +INSTR_PROF_VISIBILITY void +serializeValueProfRecordFrom(ValueProfRecord *This, + ValueProfRecordClosure *Closure, + uint32_t ValueKind, uint32_t NumValueSites) { uint32_t S; const void *Record = Closure->Record; This->Kind = ValueKind; @@ -504,8 +523,7 @@ void serializeValueProfRecordFrom(ValueProfRecord *This, for (S = 0; S < NumValueSites; S++) { uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S); This->SiteCountArray[S] = ND; - Closure->GetValueForSite(Record, DstVD, ValueKind, S, - Closure->RemapValueData); + Closure->GetValueForSite(Record, DstVD, ValueKind, S); DstVD += ND; } } @@ -513,12 +531,16 @@ void serializeValueProfRecordFrom(ValueProfRecord *This, /*! * Extract value profile data of a function from the \c Closure * and serialize the data into \c DstData if it is not NULL or heap - * memory allocated by the \c Closure's allocator method. + * memory allocated by the \c Closure's allocator method. If \c + * DstData is not null, the caller is expected to set the TotalSize + * in DstData. */ -ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, - ValueProfData *DstData) { +INSTR_PROF_VISIBILITY ValueProfData * +serializeValueProfDataFrom(ValueProfRecordClosure *Closure, + ValueProfData *DstData) { uint32_t Kind; - uint32_t TotalSize = getValueProfDataSize(Closure); + uint32_t TotalSize = + DstData ? DstData->TotalSize : getValueProfDataSize(Closure); ValueProfData *VPD = DstData ? DstData : Closure->AllocValueProfData(TotalSize); @@ -536,144 +558,15 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, return VPD; } -/* - * The value profiler runtime library stores the value profile data - * for a given function in \c NumValueSites and \c Nodes structures. - * \c ValueProfRuntimeRecord class is used to encapsulate the runtime - * profile data and provides fast interfaces to retrieve the profile - * information. This interface is used to initialize the runtime record - * and pre-compute the information needed for efficient implementation - * of callbacks required by ValueProfRecordClosure class. - */ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes) { - unsigned I, J, S = 0, NumValueKinds = 0; - RuntimeRecord->NumValueSites = NumValueSites; - RuntimeRecord->Nodes = Nodes; - for (I = 0; I <= IPVK_Last; I++) { - uint16_t N = NumValueSites[I]; - if (!N) { - RuntimeRecord->SiteCountArray[I] = 0; - continue; - } - NumValueKinds++; - RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1); - if (!RuntimeRecord->SiteCountArray[I]) - return 1; - RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : NULL; - for (J = 0; J < N; J++) { - /* Compute value count for each site. */ - uint32_t C = 0; - ValueProfNode *Site = Nodes ? RuntimeRecord->NodesKind[I][J] : NULL; - while (Site) { - C++; - Site = Site->Next; - } - if (C > UCHAR_MAX) - C = UCHAR_MAX; - RuntimeRecord->SiteCountArray[I][J] = C; - } - S += N; - } - RuntimeRecord->NumValueKinds = NumValueKinds; - return 0; -} - -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) { - unsigned I; - for (I = 0; I <= IPVK_Last; I++) { - if (RuntimeRecord->SiteCountArray[I]) - free(RuntimeRecord->SiteCountArray[I]); - } -} - -/* ValueProfRecordClosure Interface implementation for - * ValueProfDataRuntimeRecord. */ -uint32_t getNumValueKindsRT(const void *R) { - return ((const ValueProfRuntimeRecord *)R)->NumValueKinds; -} - -uint32_t getNumValueSitesRT(const void *R, uint32_t VK) { - return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK]; -} - -uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) { - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - return Record->SiteCountArray[VK][S]; -} - -uint32_t getNumValueDataRT(const void *R, uint32_t VK) { - unsigned I, S = 0; - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - if (Record->SiteCountArray[VK] == 0) - return 0; - for (I = 0; I < Record->NumValueSites[VK]; I++) - S += Record->SiteCountArray[VK][I]; - return S; -} - -void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK, - uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)) { - unsigned I, N = 0; - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - N = getNumValueDataForSiteRT(R, VK, S); - if (N == 0) - return; - ValueProfNode *VNode = Record->NodesKind[VK][S]; - for (I = 0; I < N; I++) { - Dst[I] = VNode->VData; - VNode = VNode->Next; - } -} - -ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) { - return (ValueProfData *)calloc(TotalSizeInBytes, 1); -} - -static ValueProfRecordClosure RTRecordClosure = {0, - getNumValueKindsRT, - getNumValueSitesRT, - getNumValueDataRT, - getNumValueDataForSiteRT, - 0, - getValueForSiteRT, - allocValueProfDataRT}; - -/* - * Return the size of ValueProfData structure to store data - * recorded in the runtime record. - */ -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) { - RTRecordClosure.Record = Record; - return getValueProfDataSize(&RTRecordClosure); -} - -/* - * Return a ValueProfData instance that stores the data collected - * from runtime. If \c DstData is provided by the caller, the value - * profile data will be store in *DstData and DstData is returned, - * otherwise the method will allocate space for the value data and - * return pointer to the newly allocated space. - */ -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *DstData) { - RTRecordClosure.Record = Record; - return serializeValueProfDataFrom(&RTRecordClosure, DstData); -} - - #undef INSTR_PROF_COMMON_API_IMPL #endif /* INSTR_PROF_COMMON_API_IMPL */ /*============================================================================*/ - #ifndef INSTR_PROF_DATA_DEFINED -#ifndef INSTR_PROF_DATA_INC_ -#define INSTR_PROF_DATA_INC_ +#ifndef INSTR_PROF_DATA_INC +#define INSTR_PROF_DATA_INC /* Helper macros. */ #define INSTR_PROF_SIMPLE_QUOTE(x) #x @@ -695,23 +588,33 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 -/* Raw profile format version. */ -#define INSTR_PROF_RAW_VERSION 2 -#define INSTR_PROF_INDEX_VERSION 3 -#define INSTR_PROF_COVMAP_VERSION 0 +/* Raw profile format version (start from 1). */ +#define INSTR_PROF_RAW_VERSION 4 +/* Indexed profile format version (start from 1). */ +#define INSTR_PROF_INDEX_VERSION 4 +/* Coverage mapping format vresion (start from 0). */ +#define INSTR_PROF_COVMAP_VERSION 1 -/* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the +/* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton * generated profile, and 0 if this is a Clang FE generated profile. -*/ + */ #define VARIANT_MASKS_ALL 0xff00000000000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) +#define VARIANT_MASK_IR_PROF (0x1ULL << 56) +#define IR_LEVEL_PROF_VERSION_VAR __llvm_profile_raw_version /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts +/* Array of pointers. Each pointer points to a list + * of value nodes associated with one value site. + */ +#define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals +/* Value profile nodes section. */ +#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_DATA_SECT_NAME_STR \ @@ -722,6 +625,10 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) #define INSTR_PROF_COVMAP_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) +#define INSTR_PROF_VALS_SECT_NAME_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) +#define INSTR_PROF_VNODES_SECT_NAME_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) /* Macros to define start/stop section symbol for a given * section on Linux. For instance @@ -751,16 +658,7 @@ typedef struct InstrProfValueData { uint64_t Count; } InstrProfValueData; -/* This is an internal data structure used by value profiler. It - * is defined here to allow serialization code sharing by LLVM - * to be used in unit test. - */ -typedef struct ValueProfNode { - InstrProfValueData VData; - struct ValueProfNode *Next; -} ValueProfNode; - -#endif /* INSTR_PROF_DATA_INC_ */ +#endif /* INSTR_PROF_DATA_INC */ #else #undef INSTR_PROF_DATA_DEFINED diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index fed3e693e7a0..65b11f61d10b 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -19,7 +19,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" @@ -51,19 +50,20 @@ public: /// Base class and interface for reading profiling data of any known instrprof /// format. Provides an iterator over InstrProfRecords. class InstrProfReader { - std::error_code LastError; + instrprof_error LastError; public: InstrProfReader() : LastError(instrprof_error::success), Symtab() {} virtual ~InstrProfReader() {} /// Read the header. Required before reading first record. - virtual std::error_code readHeader() = 0; + virtual Error readHeader() = 0; /// Read a single record. - virtual std::error_code readNextRecord(InstrProfRecord &Record) = 0; + virtual Error readNextRecord(InstrProfRecord &Record) = 0; /// Iterator over profile data. InstrProfIterator begin() { return InstrProfIterator(this); } InstrProfIterator end() { return InstrProfIterator(); } + virtual bool isIRLevelProfile() const = 0; /// Return the PGO symtab. There are three different readers: /// Raw, Text, and Indexed profile readers. The first two types @@ -79,28 +79,35 @@ public: protected: std::unique_ptr<InstrProfSymtab> Symtab; - /// Set the current std::error_code and return same. - std::error_code error(std::error_code EC) { - LastError = EC; - return EC; + /// Set the current error and return same. + Error error(instrprof_error Err) { + LastError = Err; + if (Err == instrprof_error::success) + return Error::success(); + return make_error<InstrProfError>(Err); } + Error error(Error E) { return error(InstrProfError::take(std::move(E))); } - /// Clear the current error code and return a successful one. - std::error_code success() { return error(instrprof_error::success); } + /// Clear the current error and return a successful one. + Error success() { return error(instrprof_error::success); } public: /// Return true if the reader has finished reading the profile data. bool isEOF() { return LastError == instrprof_error::eof; } /// Return true if the reader encountered an error reading profiling data. - bool hasError() { return LastError && !isEOF(); } - /// Get the current error code. - std::error_code getError() { return LastError; } + bool hasError() { return LastError != instrprof_error::success && !isEOF(); } + /// Get the current error. + Error getError() { + if (hasError()) + return make_error<InstrProfError>(LastError); + return Error::success(); + } /// Factory method to create an appropriately typed reader for the given /// instrprof file. - static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path); + static Expected<std::unique_ptr<InstrProfReader>> create(const Twine &Path); - static ErrorOr<std::unique_ptr<InstrProfReader>> + static Expected<std::unique_ptr<InstrProfReader>> create(std::unique_ptr<MemoryBuffer> Buffer); }; @@ -118,22 +125,26 @@ private: std::unique_ptr<MemoryBuffer> DataBuffer; /// Iterator over the profile data. line_iterator Line; + bool IsIRLevelProfile; TextInstrProfReader(const TextInstrProfReader &) = delete; TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; - std::error_code readValueProfileData(InstrProfRecord &Record); + Error readValueProfileData(InstrProfRecord &Record); public: TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_) - : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {} + : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#'), + IsIRLevelProfile(false) {} /// Return true if the given buffer is in text instrprof format. static bool hasFormat(const MemoryBuffer &Buffer); + bool isIRLevelProfile() const override { return IsIRLevelProfile; } + /// Read the header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; InstrProfSymtab &getSymtab() override { assert(Symtab.get()); @@ -154,14 +165,20 @@ private: /// The profile data file contents. std::unique_ptr<MemoryBuffer> DataBuffer; bool ShouldSwapBytes; + // The value of the version field of the raw profile data header. The lower 56 + // bits specifies the format version and the most significant 8 bits specify + // the variant types of the profile. + uint64_t Version; uint64_t CountersDelta; uint64_t NamesDelta; const RawInstrProf::ProfileData<IntPtrT> *Data; const RawInstrProf::ProfileData<IntPtrT> *DataEnd; const uint64_t *CountersStart; const char *NamesStart; + uint64_t NamesSize; + // After value profile is all read, this pointer points to + // the header of next profile data (if exists) const uint8_t *ValueDataStart; - const char *ProfileEnd; uint32_t ValueKindLast; uint32_t CurValueDataSize; @@ -174,8 +191,11 @@ public: : DataBuffer(std::move(DataBuffer)) { } static bool hasFormat(const MemoryBuffer &DataBuffer); - std::error_code readHeader() override; - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readHeader() override; + Error readNextRecord(InstrProfRecord &Record) override; + bool isIRLevelProfile() const override { + return (Version & VARIANT_MASK_IR_PROF) != 0; + } InstrProfSymtab &getSymtab() override { assert(Symtab.get()); @@ -183,9 +203,9 @@ public: } private: - void createSymtab(InstrProfSymtab &Symtab); - std::error_code readNextHeader(const char *CurrentPos); - std::error_code readHeader(const RawInstrProf::Header &Header); + Error createSymtab(InstrProfSymtab &Symtab); + Error readNextHeader(const char *CurrentPos); + Error readHeader(const RawInstrProf::Header &Header); template <class IntT> IntT swap(IntT Int) const { return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int; } @@ -202,23 +222,26 @@ private: inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } - std::error_code readName(InstrProfRecord &Record); - std::error_code readFuncHash(InstrProfRecord &Record); - std::error_code readRawCounts(InstrProfRecord &Record); - std::error_code readValueProfilingData(InstrProfRecord &Record); + Error readName(InstrProfRecord &Record); + Error readFuncHash(InstrProfRecord &Record); + Error readRawCounts(InstrProfRecord &Record); + Error readValueProfilingData(InstrProfRecord &Record); bool atEnd() const { return Data == DataEnd; } void advanceData() { Data++; ValueDataStart += CurValueDataSize; } + const char *getNextHeaderPos() const { + assert(atEnd()); + return (const char *)ValueDataStart; + } const uint64_t *getCounter(IntPtrT CounterPtr) const { ptrdiff_t Offset = (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t); return CountersStart + Offset; } - const char *getName(IntPtrT NamePtr) const { - ptrdiff_t Offset = (swap(NamePtr) - NamesDelta) / sizeof(char); - return NamesStart + Offset; + StringRef getName(uint64_t NameRef) const { + return Symtab->getFuncName(swap(NameRef)); } }; @@ -283,15 +306,16 @@ public: struct InstrProfReaderIndexBase { // Read all the profile records with the same key pointed to the current // iterator. - virtual std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) = 0; + virtual Error getRecords(ArrayRef<InstrProfRecord> &Data) = 0; // Read all the profile records with the key equal to FuncName - virtual std::error_code getRecords(StringRef FuncName, + virtual Error getRecords(StringRef FuncName, ArrayRef<InstrProfRecord> &Data) = 0; virtual void advanceToNextKey() = 0; virtual bool atEnd() const = 0; virtual void setValueProfDataEndianness(support::endianness Endianness) = 0; virtual ~InstrProfReaderIndexBase() {} virtual uint64_t getVersion() const = 0; + virtual bool isIRLevelProfile() const = 0; virtual void populateSymtab(InstrProfSymtab &) = 0; }; @@ -312,9 +336,9 @@ public: const unsigned char *const Base, IndexedInstrProf::HashT HashType, uint64_t Version); - std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) override; - std::error_code getRecords(StringRef FuncName, - ArrayRef<InstrProfRecord> &Data) override; + Error getRecords(ArrayRef<InstrProfRecord> &Data) override; + Error getRecords(StringRef FuncName, + ArrayRef<InstrProfRecord> &Data) override; void advanceToNextKey() override { RecordIterator++; } bool atEnd() const override { return RecordIterator == HashTable->data_end(); @@ -323,7 +347,10 @@ public: HashTable->getInfoObj().setValueProfDataEndianness(Endianness); } ~InstrProfReaderIndex() override {} - uint64_t getVersion() const override { return FormatVersion; } + uint64_t getVersion() const override { return GET_VERSION(FormatVersion); } + bool isIRLevelProfile() const override { + return (FormatVersion & VARIANT_MASK_IR_PROF) != 0; + } void populateSymtab(InstrProfSymtab &Symtab) override { Symtab.create(HashTable->keys()); } @@ -336,14 +363,21 @@ private: std::unique_ptr<MemoryBuffer> DataBuffer; /// The index into the profile data. std::unique_ptr<InstrProfReaderIndexBase> Index; - /// The maximal execution count among all functions. - uint64_t MaxFunctionCount; + /// Profile summary data. + std::unique_ptr<ProfileSummary> Summary; IndexedInstrProfReader(const IndexedInstrProfReader &) = delete; IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete; + // Read the profile summary. Return a pointer pointing to one byte past the + // end of the summary data if it exists or the input \c Cur. + const unsigned char *readSummary(IndexedInstrProf::ProfVersion Version, + const unsigned char *Cur); + public: + /// Return the profile version. uint64_t getVersion() const { return Index->getVersion(); } + bool isIRLevelProfile() const override { return Index->isIRLevelProfile(); } IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer) : DataBuffer(std::move(DataBuffer)), Index(nullptr) {} @@ -351,27 +385,27 @@ public: static bool hasFormat(const MemoryBuffer &DataBuffer); /// Read the file header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; /// Return the pointer to InstrProfRecord associated with FuncName /// and FuncHash - ErrorOr<InstrProfRecord> getInstrProfRecord(StringRef FuncName, - uint64_t FuncHash); + Expected<InstrProfRecord> getInstrProfRecord(StringRef FuncName, + uint64_t FuncHash); /// Fill Counts with the profile data for the given function name. - std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash, - std::vector<uint64_t> &Counts); + Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, + std::vector<uint64_t> &Counts); /// Return the maximum of all known function counts. - uint64_t getMaximumFunctionCount() { return MaxFunctionCount; } + uint64_t getMaximumFunctionCount() { return Summary->getMaxFunctionCount(); } /// Factory method to create an indexed reader. - static ErrorOr<std::unique_ptr<IndexedInstrProfReader>> - create(std::string Path); + static Expected<std::unique_ptr<IndexedInstrProfReader>> + create(const Twine &Path); - static ErrorOr<std::unique_ptr<IndexedInstrProfReader>> + static Expected<std::unique_ptr<IndexedInstrProfReader>> create(std::unique_ptr<MemoryBuffer> Buffer); // Used for testing purpose only. @@ -383,6 +417,7 @@ public: // to be used by llvm-profdata (for dumping). Avoid using this when // the client is the compiler. InstrProfSymtab &getSymtab() override; + ProfileSummary &getSummary() { return *(Summary.get()); } }; } // end namespace llvm diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index e7f53de051c3..7d292731cccb 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -24,21 +24,29 @@ namespace llvm { /// Writer for instrumentation based profile data. +class ProfOStream; +class InstrProfRecordWriterTrait; + class InstrProfWriter { public: typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData; + enum ProfKind { PF_Unknown = 0, PF_FE, PF_IRLevel }; private: + bool Sparse; StringMap<ProfilingData> FunctionData; - uint64_t MaxFunctionCount; + ProfKind ProfileKind; + // Use raw pointer here for the incomplete type object. + InstrProfRecordWriterTrait *InfoObj; public: - InstrProfWriter() : MaxFunctionCount(0) {} + InstrProfWriter(bool Sparse = false); + ~InstrProfWriter(); /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is /// summed. Optionally scale counts by \p Weight. - std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1); + Error addRecord(InstrProfRecord &&I, uint64_t Weight = 1); /// Write the profile to \c OS void write(raw_fd_ostream &OS); /// Write the profile in text format to \c OS @@ -49,11 +57,25 @@ public: /// Write the profile, returning the raw data. For testing. std::unique_ptr<MemoryBuffer> writeBuffer(); + /// Set the ProfileKind. Report error if mixing FE and IR level profiles. + Error setIsIRLevelProfile(bool IsIRLevel) { + if (ProfileKind == PF_Unknown) { + ProfileKind = IsIRLevel ? PF_IRLevel: PF_FE; + return Error::success(); + } + return (IsIRLevel == (ProfileKind == PF_IRLevel)) + ? Error::success() + : make_error<InstrProfError>( + instrprof_error::unsupported_version); + } + // Internal interface for testing purpose only. void setValueProfDataEndianness(support::endianness Endianness); + void setOutputSparse(bool Sparse); private: - std::pair<uint64_t, uint64_t> writeImpl(raw_ostream &OS); + bool shouldEncodeData(const ProfilingData &PD); + void writeImpl(ProfOStream &OS); }; } // end namespace llvm diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h new file mode 100644 index 000000000000..ecb228ca59c4 --- /dev/null +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -0,0 +1,102 @@ +//===-- ProfileCommon.h - Common profiling APIs. ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains data structures and functions common to both instrumented +// and sample profiling. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROFILEDATA_PROFILE_COMMON_H +#define LLVM_PROFILEDATA_PROFILE_COMMON_H + +#include <cstdint> +#include <functional> +#include <map> +#include <utility> +#include <vector> + +#include "llvm/IR/ProfileSummary.h" +#include "llvm/Support/Error.h" +#include "llvm/ADT/ArrayRef.h" + +namespace llvm { +class Function; +namespace IndexedInstrProf { +struct Summary; +} +namespace sampleprof { +class FunctionSamples; +} +struct InstrProfRecord; +class LLVMContext; +class Metadata; +class MDTuple; +class MDNode; + +inline const char *getHotSectionPrefix() { return ".hot"; } +inline const char *getUnlikelySectionPrefix() { return ".unlikely"; } + +class ProfileSummaryBuilder { + +private: + // We keep track of the number of times a count (block count or samples) + // appears in the profile. The map is kept sorted in the descending order of + // counts. + std::map<uint64_t, uint32_t, std::greater<uint64_t>> CountFrequencies; + std::vector<uint32_t> DetailedSummaryCutoffs; + +protected: + SummaryEntryVector DetailedSummary; + ProfileSummaryBuilder(std::vector<uint32_t> Cutoffs) + : DetailedSummaryCutoffs(std::move(Cutoffs)), TotalCount(0), MaxCount(0), + MaxFunctionCount(0), NumCounts(0), NumFunctions(0) {} + inline void addCount(uint64_t Count); + ~ProfileSummaryBuilder() = default; + void computeDetailedSummary(); + uint64_t TotalCount, MaxCount, MaxFunctionCount; + uint32_t NumCounts, NumFunctions; + +public: + /// \brief A vector of useful cutoff values for detailed summary. + static const ArrayRef<uint32_t> DefaultCutoffs; +}; + +class InstrProfSummaryBuilder final : public ProfileSummaryBuilder { + uint64_t MaxInternalBlockCount; + inline void addEntryCount(uint64_t Count); + inline void addInternalCount(uint64_t Count); + +public: + InstrProfSummaryBuilder(std::vector<uint32_t> Cutoffs) + : ProfileSummaryBuilder(std::move(Cutoffs)), MaxInternalBlockCount(0) {} + void addRecord(const InstrProfRecord &); + std::unique_ptr<ProfileSummary> getSummary(); +}; + +class SampleProfileSummaryBuilder final : public ProfileSummaryBuilder { + +public: + void addRecord(const sampleprof::FunctionSamples &FS); + SampleProfileSummaryBuilder(std::vector<uint32_t> Cutoffs) + : ProfileSummaryBuilder(std::move(Cutoffs)) {} + std::unique_ptr<ProfileSummary> getSummary(); +}; + +// This is called when a count is seen in the profile. +void ProfileSummaryBuilder::addCount(uint64_t Count) { + TotalCount += Count; + if (Count > MaxCount) + MaxCount = Count; + NumCounts++; + CountFrequencies[Count]++; +} + + +} // end namespace llvm +#endif diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h index 6c39cf9458dc..9fefefa627b1 100644 --- a/include/llvm/ProfileData/SampleProf.h +++ b/include/llvm/ProfileData/SampleProf.h @@ -74,7 +74,7 @@ static inline uint64_t SPMagic() { uint64_t('2') << (64 - 56) | uint64_t(0xff); } -static inline uint64_t SPVersion() { return 102; } +static inline uint64_t SPVersion() { return 103; } /// Represents the relative location of an instruction. /// @@ -100,23 +100,6 @@ struct LineLocation { raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc); -/// Represents the relative location of a callsite. -/// -/// Callsite locations are specified by the line offset from the -/// beginning of the function (marked by the line where the function -/// head is), the discriminator value within that line, and the callee -/// function name. -struct CallsiteLocation : public LineLocation { - CallsiteLocation(uint32_t L, uint32_t D, StringRef N) - : LineLocation(L, D), CalleeName(N) {} - void print(raw_ostream &OS) const; - void dump() const; - - StringRef CalleeName; -}; - -raw_ostream &operator<<(raw_ostream &OS, const CallsiteLocation &Loc); - /// Representation of a single sample record. /// /// A sample record is represented by a positive integer value, which @@ -188,7 +171,7 @@ raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample); typedef std::map<LineLocation, SampleRecord> BodySampleMap; class FunctionSamples; -typedef std::map<CallsiteLocation, FunctionSamples> CallsiteSampleMap; +typedef std::map<LineLocation, FunctionSamples> CallsiteSampleMap; /// Representation of the samples collected for a function. /// @@ -197,7 +180,7 @@ typedef std::map<CallsiteLocation, FunctionSamples> CallsiteSampleMap; /// within the body of the function. class FunctionSamples { public: - FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {} + FunctionSamples() : Name(), TotalSamples(0), TotalHeadSamples(0) {} void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const; void dump() const; sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) { @@ -221,8 +204,8 @@ public: } sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, - std::string FName, uint64_t Num, - uint64_t Weight = 1) { + const std::string &FName, + uint64_t Num, uint64_t Weight = 1) { return BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget( FName, Num, Weight); } @@ -240,13 +223,12 @@ public: } /// Return the function samples at the given callsite location. - FunctionSamples &functionSamplesAt(const CallsiteLocation &Loc) { + FunctionSamples &functionSamplesAt(const LineLocation &Loc) { return CallsiteSamples[Loc]; } /// Return a pointer to function samples at the given callsite location. - const FunctionSamples * - findFunctionSamplesAt(const CallsiteLocation &Loc) const { + const FunctionSamples *findFunctionSamplesAt(const LineLocation &Loc) const { auto iter = CallsiteSamples.find(Loc); if (iter == CallsiteSamples.end()) { return nullptr; @@ -276,6 +258,7 @@ public: /// Optionally scale samples by \p Weight. sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) { sampleprof_error Result = sampleprof_error::success; + Name = Other.getName(); MergeResult(Result, addTotalSamples(Other.getTotalSamples(), Weight)); MergeResult(Result, addHeadSamples(Other.getHeadSamples(), Weight)); for (const auto &I : Other.getBodySamples()) { @@ -284,14 +267,23 @@ public: MergeResult(Result, BodySamples[Loc].merge(Rec, Weight)); } for (const auto &I : Other.getCallsiteSamples()) { - const CallsiteLocation &Loc = I.first; + const LineLocation &Loc = I.first; const FunctionSamples &Rec = I.second; MergeResult(Result, functionSamplesAt(Loc).merge(Rec, Weight)); } return Result; } + /// Set the name of the function. + void setName(StringRef FunctionName) { Name = FunctionName; } + + /// Return the function name. + const StringRef &getName() const { return Name; } + private: + /// Mangled name of the function. + StringRef Name; + /// Total number of samples collected inside this function. /// /// Samples are cumulative, they include all the samples collected diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h index 6db0fbb0e7ab..bf86721709c7 100644 --- a/include/llvm/ProfileData/SampleProfReader.h +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -129,6 +129,30 @@ // VERSION (uint32_t) // File format version number computed by SPVersion() // +// SUMMARY +// TOTAL_COUNT (uint64_t) +// Total number of samples in the profile. +// MAX_COUNT (uint64_t) +// Maximum value of samples on a line. +// MAX_FUNCTION_COUNT (uint64_t) +// Maximum number of samples at function entry (head samples). +// NUM_COUNTS (uint64_t) +// Number of lines with samples. +// NUM_FUNCTIONS (uint64_t) +// Number of functions with samples. +// NUM_DETAILED_SUMMARY_ENTRIES (size_t) +// Number of entries in detailed summary +// DETAILED_SUMMARY +// A list of detailed summary entry. Each entry consists of +// CUTOFF (uint32_t) +// Required percentile of total sample count expressed as a fraction +// multiplied by 1000000. +// MIN_COUNT (uint64_t) +// The minimum number of samples required to reach the target +// CUTOFF. +// NUM_COUNTS (uint64_t) +// Number of samples to get to the desrired percentile. +// // NAME TABLE // SIZE (uint32_t) // Number of entries in the name table. @@ -190,6 +214,7 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/ProfileData/ProfileCommon.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -264,12 +289,15 @@ public: /// \brief Create a sample profile reader appropriate to the file format. static ErrorOr<std::unique_ptr<SampleProfileReader>> - create(StringRef Filename, LLVMContext &C); + create(const Twine &Filename, LLVMContext &C); /// \brief Create a sample profile reader from the supplied memory buffer. static ErrorOr<std::unique_ptr<SampleProfileReader>> create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C); + /// \brief Return the profile summary. + ProfileSummary &getSummary() { return *(Summary.get()); } + protected: /// \brief Map every function to its associated profile. /// @@ -283,6 +311,12 @@ protected: /// \brief Memory buffer holding the profile file. std::unique_ptr<MemoryBuffer> Buffer; + + /// \brief Profile summary information. + std::unique_ptr<ProfileSummary> Summary; + + /// \brief Compute summary for this profile. + void computeSummary(); }; class SampleProfileReaderText : public SampleProfileReader { @@ -348,6 +382,12 @@ protected: /// Function name table. std::vector<StringRef> NameTable; + +private: + std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries); + + /// \brief Read profile summary. + std::error_code readSummary(); }; typedef SmallVector<FunctionSamples *, 10> InlineCallStack; diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h index 029dd2ebacb0..f6f2e2702e31 100644 --- a/include/llvm/ProfileData/SampleProfWriter.h +++ b/include/llvm/ProfileData/SampleProfWriter.h @@ -15,6 +15,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ProfileData/ProfileCommon.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" @@ -31,10 +32,10 @@ class SampleProfileWriter { public: virtual ~SampleProfileWriter() {} - /// Write sample profiles in \p S for function \p FName. + /// Write sample profiles in \p S. /// /// \returns status code of the file update operation. - virtual std::error_code write(StringRef FName, const FunctionSamples &S) = 0; + virtual std::error_code write(const FunctionSamples &S) = 0; /// Write all the sample profiles in the given map of samples. /// @@ -42,11 +43,9 @@ public: std::error_code write(const StringMap<FunctionSamples> &ProfileMap) { if (std::error_code EC = writeHeader(ProfileMap)) return EC; - for (const auto &I : ProfileMap) { - StringRef FName = I.first(); const FunctionSamples &Profile = I.second; - if (std::error_code EC = write(FName, Profile)) + if (std::error_code EC = write(Profile)) return EC; } return sampleprof_error::success; @@ -75,12 +74,18 @@ protected: /// \brief Output stream where to emit the profile to. std::unique_ptr<raw_ostream> OutputStream; + + /// \brief Profile summary. + std::unique_ptr<ProfileSummary> Summary; + + /// \brief Compute summary for this profile. + void computeSummary(const StringMap<FunctionSamples> &ProfileMap); }; /// \brief Sample-based profile writer (text format). class SampleProfileWriterText : public SampleProfileWriter { public: - std::error_code write(StringRef FName, const FunctionSamples &S) override; + std::error_code write(const FunctionSamples &S) override; protected: SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS) @@ -105,7 +110,7 @@ private: /// \brief Sample-based profile writer (binary format). class SampleProfileWriterBinary : public SampleProfileWriter { public: - std::error_code write(StringRef F, const FunctionSamples &S) override; + std::error_code write(const FunctionSamples &S) override; protected: SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS) @@ -113,8 +118,9 @@ protected: std::error_code writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; + std::error_code writeSummary(); std::error_code writeNameIdx(StringRef FName); - std::error_code writeBody(StringRef FName, const FunctionSamples &S); + std::error_code writeBody(const FunctionSamples &S); private: void addName(StringRef FName); diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def new file mode 100644 index 000000000000..67f981b8f2fa --- /dev/null +++ b/include/llvm/Support/AArch64TargetParser.def @@ -0,0 +1,72 @@ +//===- AARCH64TargetParser.def - AARCH64 target parsing defines ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides defines to build up the AARCH64 target parser's logic. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +#ifndef AARCH64_ARCH +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) +#endif +AARCH64_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, + FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE)) +AARCH64_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE)) +AARCH64_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE | + AArch64::AEK_RAS)) +#undef AARCH64_ARCH + +#ifndef AARCH64_ARCH_EXT_NAME +#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) +#endif +// FIXME: This would be nicer were it tablegen +AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") +AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") +AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") +AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") +AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") +AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") +AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") +#undef AARCH64_ARCH_EXT_NAME + +#ifndef AARCH64_CPU_NAME +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) +#endif +AARCH64_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, + ( AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("vulcan", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +// Invalid CPU +AARCH64_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AArch64::AEK_INVALID) +#undef AARCH64_CPU_NAME diff --git a/include/llvm/Support/AIXDataTypesFix.h b/include/llvm/Support/AIXDataTypesFix.h deleted file mode 100644 index a9a9147de294..000000000000 --- a/include/llvm/Support/AIXDataTypesFix.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- llvm/Support/AIXDataTypesFix.h - Fix datatype defs ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file overrides default system-defined types and limits which cannot be -// done in DataTypes.h.in because it is processed by autoheader first, which -// comments out any #undef statement -// -//===----------------------------------------------------------------------===// - -// No include guards desired! - -#ifndef SUPPORT_DATATYPES_H -#error "AIXDataTypesFix.h must only be included via DataTypes.h!" -#endif - -// GCC is strict about defining large constants: they must have LL modifier. -// These will be defined properly at the end of DataTypes.h -#undef INT64_MAX -#undef INT64_MIN diff --git a/include/llvm/Support/ARMBuildAttributes.h b/include/llvm/Support/ARMBuildAttributes.h index fc14cb2d0b0c..f447cd072b5f 100644 --- a/include/llvm/Support/ARMBuildAttributes.h +++ b/include/llvm/Support/ARMBuildAttributes.h @@ -67,6 +67,7 @@ enum AttrType { ABI_FP_16bit_format = 38, MPextension_use = 42, // recoded from 70 (ABI r2.08) DIV_use = 44, + DSP_extension = 46, also_compatible_with = 65, conformance = 67, Virtualization_use = 68, @@ -106,7 +107,9 @@ enum CPUArch { v6_M = 11, // e.g. Cortex M1 v6S_M = 12, // v6_M with the System extensions v7E_M = 13, // v7_M with DSP extensions - v8 = 14, // v8,v8.1a AArch32 + v8_A = 14, // v8_A AArch32 + v8_M_Base= 16, // v8_M_Base AArch32 + v8_M_Main= 17, // v8_M_Main AArch32 }; enum CPUArchProfile { // (=7), uleb128 @@ -126,6 +129,7 @@ enum { // Tag_THUMB_ISA_use, (=9), uleb128 AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions) + AllowThumbDerived = 3, // Thumb allowed, derived from arch/profile // Tag_FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10) AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA) diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def index d94a51b8bcf9..195f7112d6a0 100644 --- a/include/llvm/Support/ARMTargetParser.def +++ b/include/llvm/Support/ARMTargetParser.def @@ -45,180 +45,198 @@ ARM_FPU("softvfp", FK_SOFTVFP, FV_NONE, NS_None, FR_None) #define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) #endif ARM_ARCH("invalid", AK_INVALID, nullptr, nullptr, - ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, AEK_NONE) + ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv2", AK_ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv2a", AK_ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv3", AK_ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv3m", AK_ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv4", AK_ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv4t", AK_ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv5t", AK_ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv5te", AK_ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv5tej", AK_ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv6", AK_ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6, - FK_VFPV2, AEK_DSP) + FK_VFPV2, ARM::AEK_DSP) ARM_ARCH("armv6k", AK_ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K, - FK_VFPV2, AEK_DSP) + FK_VFPV2, ARM::AEK_DSP) ARM_ARCH("armv6t2", AK_ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv6kz", AK_ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ, - FK_VFPV2, (AEK_SEC | AEK_DSP)) + FK_VFPV2, (ARM::AEK_SEC | ARM::AEK_DSP)) ARM_ARCH("armv6-m", AK_ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv7-a", AK_ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7, - FK_NEON, AEK_DSP) + FK_NEON, ARM::AEK_DSP) ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7, - FK_NONE, (AEK_HWDIV | AEK_DSP)) + FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP)) ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7, - FK_NONE, AEK_HWDIV) + FK_NONE, ARM::AEK_HWDIV) ARM_ARCH("armv7e-m", AK_ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M, - FK_NONE, (AEK_HWDIV | AEK_DSP)) -ARM_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) -ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", ARMBuildAttrs::CPUArch::v8, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) -ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", ARMBuildAttrs::CPUArch::v8, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) + FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP)) +ARM_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, + FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS)) +ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8-m.base", AK_ARMV8MBaseline, "8-M.Baseline", "v8m.base", + ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIV) +ARM_ARCH("armv8-m.main", AK_ARMV8MMainline, "8-M.Mainline", "v8m.main", + ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIV) // Non-standard Arch names. ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("iwmmxt2", AK_IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("xscale", AK_XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv7s", AK_ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7, - FK_NEON_VFPV4, AEK_DSP) + FK_NEON_VFPV4, ARM::AEK_DSP) ARM_ARCH("armv7k", AK_ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) #undef ARM_ARCH #ifndef ARM_ARCH_EXT_NAME #define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) #endif // FIXME: This would be nicer were it tablegen -ARM_ARCH_EXT_NAME("invalid", AEK_INVALID, nullptr, nullptr) -ARM_ARCH_EXT_NAME("none", AEK_NONE, nullptr, nullptr) -ARM_ARCH_EXT_NAME("crc", AEK_CRC, "+crc", "-crc") -ARM_ARCH_EXT_NAME("crypto", AEK_CRYPTO, "+crypto","-crypto") -ARM_ARCH_EXT_NAME("fp", AEK_FP, nullptr, nullptr) -ARM_ARCH_EXT_NAME("idiv", (AEK_HWDIVARM | AEK_HWDIV), nullptr, nullptr) -ARM_ARCH_EXT_NAME("mp", AEK_MP, nullptr, nullptr) -ARM_ARCH_EXT_NAME("simd", AEK_SIMD, nullptr, nullptr) -ARM_ARCH_EXT_NAME("sec", AEK_SEC, nullptr, nullptr) -ARM_ARCH_EXT_NAME("virt", AEK_VIRT, nullptr, nullptr) -ARM_ARCH_EXT_NAME("fp16", AEK_FP16, "+fullfp16", "-fullfp16") -ARM_ARCH_EXT_NAME("os", AEK_OS, nullptr, nullptr) -ARM_ARCH_EXT_NAME("iwmmxt", AEK_IWMMXT, nullptr, nullptr) -ARM_ARCH_EXT_NAME("iwmmxt2", AEK_IWMMXT2, nullptr, nullptr) -ARM_ARCH_EXT_NAME("maverick", AEK_MAVERICK, nullptr, nullptr) -ARM_ARCH_EXT_NAME("xscale", AEK_XSCALE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("invalid", ARM::AEK_INVALID, nullptr, nullptr) +ARM_ARCH_EXT_NAME("none", ARM::AEK_NONE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc") +ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto") +ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp") +ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV), nullptr, nullptr) +ARM_ARCH_EXT_NAME("mp", ARM::AEK_MP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("simd", ARM::AEK_SIMD, nullptr, nullptr) +ARM_ARCH_EXT_NAME("sec", ARM::AEK_SEC, nullptr, nullptr) +ARM_ARCH_EXT_NAME("virt", ARM::AEK_VIRT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp16", ARM::AEK_FP16, "+fullfp16", "-fullfp16") +ARM_ARCH_EXT_NAME("ras", ARM::AEK_RAS, "+ras", "-ras") +ARM_ARCH_EXT_NAME("os", ARM::AEK_OS, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt", ARM::AEK_IWMMXT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt2", ARM::AEK_IWMMXT2, nullptr, nullptr) +ARM_ARCH_EXT_NAME("maverick", ARM::AEK_MAVERICK, nullptr, nullptr) +ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr) #undef ARM_ARCH_EXT_NAME #ifndef ARM_HW_DIV_NAME #define ARM_HW_DIV_NAME(NAME, ID) #endif -ARM_HW_DIV_NAME("invalid", AEK_INVALID) -ARM_HW_DIV_NAME("none", AEK_NONE) -ARM_HW_DIV_NAME("thumb", AEK_HWDIV) -ARM_HW_DIV_NAME("arm", AEK_HWDIVARM) -ARM_HW_DIV_NAME("arm,thumb", (AEK_HWDIVARM | AEK_HWDIV)) +ARM_HW_DIV_NAME("invalid", ARM::AEK_INVALID) +ARM_HW_DIV_NAME("none", ARM::AEK_NONE) +ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIV) +ARM_HW_DIV_NAME("arm", ARM::AEK_HWDIVARM) +ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) #undef ARM_HW_DIV_NAME #ifndef ARM_CPU_NAME #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) #endif -ARM_CPU_NAME("arm2", AK_ARMV2, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm3", AK_ARMV2A, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm6", AK_ARMV3, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm7m", AK_ARMV3M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm8", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm810", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm", AK_ARMV4, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("strongarm110", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm1100", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm1110", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm7tdmi", AK_ARMV4T, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm7tdmi-s", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm710t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm720t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9tdmi", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm920", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm920t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm922t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9312", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm940t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("ep9312", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm10tdmi", AK_ARMV5T, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1020t", AK_ARMV5T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm946e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm966e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm968e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm10e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1020e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1022e", AK_ARMV5TE, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm926ej-s", AK_ARMV5TEJ, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1136j-s", AK_ARMV6, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1136jf-s", AK_ARMV6, FK_VFPV2, true, AEK_NONE) -ARM_CPU_NAME("arm1136jz-s", AK_ARMV6, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1176j-s", AK_ARMV6K, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1176jz-s", AK_ARMV6KZ, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("mpcore", AK_ARMV6K, FK_VFPV2, false, AEK_NONE) -ARM_CPU_NAME("mpcorenovfp", AK_ARMV6K, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1176jzf-s", AK_ARMV6KZ, FK_VFPV2, true, AEK_NONE) -ARM_CPU_NAME("arm1156t2-s", AK_ARMV6T2, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1156t2f-s", AK_ARMV6T2, FK_VFPV2, false, AEK_NONE) -ARM_CPU_NAME("cortex-m0", AK_ARMV6M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-m0plus", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-m1", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("sc000", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false, (AEK_SEC | AEK_MP)) +ARM_CPU_NAME("arm2", AK_ARMV2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm3", AK_ARMV2A, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm6", AK_ARMV3, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7m", AK_ARMV3M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm8", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm810", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm", AK_ARMV4, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1100", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi", AK_ARMV4T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi-s", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm710t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm720t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9tdmi", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm922t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm940t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("ep9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10tdmi", AK_ARMV5T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020t", AK_ARMV5T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm946e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm966e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm968e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1022e", AK_ARMV5TE, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm926ej-s", AK_ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136j-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jf-s", AK_ARMV6, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jz-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176j-s", AK_ARMV6K, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jz-s", AK_ARMV6KZ, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("mpcore", AK_ARMV6K, FK_VFPV2, false, ARM::AEK_NONE) +ARM_CPU_NAME("mpcorenovfp", AK_ARMV6K, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jzf-s", AK_ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2-s", AK_ARMV6T2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2f-s", AK_ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0", AK_ARMV6M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0plus", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m1", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("sc000", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP)) ARM_CPU_NAME("cortex-a7", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) -ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, AEK_SEC) -ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (AEK_SEC | AEK_MP)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) +ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, ARM::AEK_SEC) +ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP)) ARM_CPU_NAME("cortex-a12", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("cortex-a15", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("cortex-a17", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("krait", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_HWDIVARM | AEK_HWDIV)) -ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, AEK_NONE) + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) +ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE) ARM_CPU_NAME("cortex-r5", AK_ARMV7R, FK_VFPV3_D16, false, - (AEK_MP | AEK_HWDIVARM)) + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) ARM_CPU_NAME("cortex-r7", AK_ARMV7R, FK_VFPV3_D16_FP16, false, - (AEK_MP | AEK_HWDIVARM)) -ARM_CPU_NAME("sc300", AK_ARMV7M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-m3", AK_ARMV7M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-m4", AK_ARMV7EM, FK_FPV4_SP_D16, true, AEK_NONE) -ARM_CPU_NAME("cortex-m7", AK_ARMV7EM, FK_FPV5_D16, false, AEK_NONE) -ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, AEK_CRC) -ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("cortex-r8", AK_ARMV7R, FK_VFPV3_D16_FP16, false, + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("sc300", AK_ARMV7M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m3", AK_ARMV7M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m4", AK_ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m7", AK_ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-a32", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) // Non-standard Arch names. -ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, AEK_NONE) +ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, ARM::AEK_NONE) ARM_CPU_NAME("swift", AK_ARMV7S, FK_NEON_VFPV4, true, - (AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) // Invalid CPU -ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AEK_INVALID) +ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, ARM::AEK_INVALID) #undef ARM_CPU_NAME diff --git a/include/llvm/Support/AlignOf.h b/include/llvm/Support/AlignOf.h index 5268c8d16986..af7f20028b6d 100644 --- a/include/llvm/Support/AlignOf.h +++ b/include/llvm/Support/AlignOf.h @@ -38,7 +38,7 @@ struct AlignmentCalcImpl { #endif T t; private: - AlignmentCalcImpl() {} // Never instantiate. + AlignmentCalcImpl() = delete; }; // Abstract base class helper, this will have the minimal alignment and size @@ -55,7 +55,7 @@ struct AlignmentCalcImplBase { // of type T. template <typename T> struct AlignmentCalcImpl<T, true> : AlignmentCalcImplBase, T { - virtual ~AlignmentCalcImpl() = 0; + ~AlignmentCalcImpl() override = 0; }; } // End detail namespace. @@ -79,8 +79,8 @@ struct AlignOf { sizeof(detail::AlignmentCalcImpl<T>) - sizeof(T)); #else enum { - Alignment = static_cast<unsigned int>(sizeof(detail::AlignmentCalcImpl<T>) - - sizeof(T)) + Alignment = static_cast<unsigned int>( + sizeof(::llvm::detail::AlignmentCalcImpl<T>) - sizeof(T)) }; #endif enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 }; @@ -223,7 +223,7 @@ template <typename T1, class AlignerImpl { T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10; - AlignerImpl(); // Never defined or instantiated. + AlignerImpl() = delete; }; template <typename T1, @@ -249,10 +249,11 @@ template <typename T1, typename T5 = char, typename T6 = char, typename T7 = char, typename T8 = char, typename T9 = char, typename T10 = char> struct AlignedCharArrayUnion : llvm::AlignedCharArray< - AlignOf<detail::AlignerImpl<T1, T2, T3, T4, T5, - T6, T7, T8, T9, T10> >::Alignment, - sizeof(detail::SizerImpl<T1, T2, T3, T4, T5, - T6, T7, T8, T9, T10>)> { + AlignOf<llvm::detail::AlignerImpl<T1, T2, T3, T4, T5, + T6, T7, T8, T9, T10> >::Alignment, + sizeof(::llvm::detail::SizerImpl<T1, T2, T3, T4, T5, + T6, T7, T8, T9, T10>)> { }; } // end namespace llvm -#endif + +#endif // LLVM_SUPPORT_ALIGNOF_H diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index 043d82314609..1c9508661d6f 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -278,6 +278,8 @@ public: return TotalMemory; } + size_t getBytesAllocated() const { return BytesAllocated; } + void PrintStats() const { detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated, getTotalMemory()); diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h index 9ec23e827023..d03714b009c5 100644 --- a/include/llvm/Support/Atomic.h +++ b/include/llvm/Support/Atomic.h @@ -9,6 +9,10 @@ // // This file declares the llvm::sys atomic operations. // +// DO NOT USE IN NEW CODE! +// +// New code should always rely on the std::atomic facilities in C++11. +// //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_ATOMIC_H @@ -28,11 +32,6 @@ namespace llvm { cas_flag CompareAndSwap(volatile cas_flag* ptr, cas_flag new_value, cas_flag old_value); - cas_flag AtomicIncrement(volatile cas_flag* ptr); - cas_flag AtomicDecrement(volatile cas_flag* ptr); - cas_flag AtomicAdd(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicMul(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicDiv(volatile cas_flag* ptr, cas_flag val); } } diff --git a/include/llvm/Support/AtomicOrdering.h b/include/llvm/Support/AtomicOrdering.h new file mode 100644 index 000000000000..8837fab19575 --- /dev/null +++ b/include/llvm/Support/AtomicOrdering.h @@ -0,0 +1,153 @@ +//===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Atomic ordering constants. +/// +/// These values are used by LLVM to represent atomic ordering for C++11's +/// memory model and more, as detailed in docs/Atomics.rst. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ATOMICORDERING_H +#define LLVM_SUPPORT_ATOMICORDERING_H + +#include <cstddef> + +namespace llvm { + +/// Atomic ordering for C11 / C++11's memody models. +/// +/// These values cannot change because they are shared with standard library +/// implementations as well as with other compilers. +enum class AtomicOrderingCABI { + relaxed = 0, + consume = 1, + acquire = 2, + release = 3, + acq_rel = 4, + seq_cst = 5, +}; + +bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete; + +// Validate an integral value which isn't known to fit within the enum's range +// is a valid AtomicOrderingCABI. +template <typename Int> static inline bool isValidAtomicOrderingCABI(Int I) { + return (Int)AtomicOrderingCABI::relaxed <= I && + I <= (Int)AtomicOrderingCABI::seq_cst; +} + +/// Atomic ordering for LLVM's memory model. +/// +/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and +/// Unordered, which are both below the C++ orders. +/// +/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst +/// \-->consume-->acquire--/ +enum class AtomicOrdering { + NotAtomic = 0, + Unordered = 1, + Monotonic = 2, // Equivalent to C++'s relaxed. + // Consume = 3, // Not specified yet. + Acquire = 4, + Release = 5, + AcquireRelease = 6, + SequentiallyConsistent = 7 +}; + +bool operator<(AtomicOrdering, AtomicOrdering) = delete; +bool operator>(AtomicOrdering, AtomicOrdering) = delete; +bool operator<=(AtomicOrdering, AtomicOrdering) = delete; +bool operator>=(AtomicOrdering, AtomicOrdering) = delete; + +// Validate an integral value which isn't known to fit within the enum's range +// is a valid AtomicOrdering. +template <typename Int> static inline bool isValidAtomicOrdering(Int I) { + return (Int)AtomicOrdering::NotAtomic <= I && + I <= (Int)AtomicOrdering::SequentiallyConsistent; +} + +/// String used by LLVM IR to represent atomic ordering. +static inline const char *toIRString(AtomicOrdering ao) { + static const char *names[8] = {"not_atomic", "unordered", "monotonic", + "consume", "acquire", "release", + "acq_rel", "seq_cst"}; + return names[(size_t)ao]; +} + +/// Returns true if ao is stronger than other as defined by the AtomicOrdering +/// lattice, which is based on C++'s definition. +static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) { + static const bool lookup[8][8] = { + // NA UN RX CO AC RE AR SC + /* NotAtomic */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* Unordered */ {1, 0, 0, 0, 0, 0, 0, 0}, + /* relaxed */ {1, 1, 0, 0, 0, 0, 0, 0}, + /* consume */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* acquire */ {1, 1, 1, 1, 0, 0, 0, 0}, + /* release */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* acq_rel */ {1, 1, 1, 1, 1, 1, 0, 0}, + /* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 0}, + }; + return lookup[(size_t)ao][(size_t)other]; +} + +static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao, + AtomicOrdering other) { + static const bool lookup[8][8] = { + // NA UN RX CO AC RE AR SC + /* NotAtomic */ {1, 0, 0, 0, 0, 0, 0, 0}, + /* Unordered */ {1, 1, 0, 0, 0, 0, 0, 0}, + /* relaxed */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* consume */ {1, 1, 1, 1, 0, 0, 0, 0}, + /* acquire */ {1, 1, 1, 1, 1, 0, 0, 0}, + /* release */ {1, 1, 1, 0, 0, 1, 0, 0}, + /* acq_rel */ {1, 1, 1, 1, 1, 1, 1, 0}, + /* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 1}, + }; + return lookup[(size_t)ao][(size_t)other]; +} + +static inline bool isStrongerThanUnordered(AtomicOrdering ao) { + return isStrongerThan(ao, AtomicOrdering::Unordered); +} + +static inline bool isStrongerThanMonotonic(AtomicOrdering ao) { + return isStrongerThan(ao, AtomicOrdering::Monotonic); +} + +static inline bool isAcquireOrStronger(AtomicOrdering ao) { + return isAtLeastOrStrongerThan(ao, AtomicOrdering::Acquire); +} + +static inline bool isReleaseOrStronger(AtomicOrdering ao) { + return isAtLeastOrStrongerThan(ao, AtomicOrdering::Release); +} + +static inline AtomicOrderingCABI toCABI(AtomicOrdering ao) { + static const AtomicOrderingCABI lookup[8] = { + /* NotAtomic */ AtomicOrderingCABI::relaxed, + /* Unordered */ AtomicOrderingCABI::relaxed, + /* relaxed */ AtomicOrderingCABI::relaxed, + /* consume */ AtomicOrderingCABI::consume, + /* acquire */ AtomicOrderingCABI::acquire, + /* release */ AtomicOrderingCABI::release, + /* acq_rel */ AtomicOrderingCABI::acq_rel, + /* seq_cst */ AtomicOrderingCABI::seq_cst, + }; + return lookup[(size_t)ao]; +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_ATOMICORDERING_H diff --git a/include/llvm/Support/BranchProbability.h b/include/llvm/Support/BranchProbability.h index 26bc888d1cab..e8eb50d53eb6 100644 --- a/include/llvm/Support/BranchProbability.h +++ b/include/llvm/Support/BranchProbability.h @@ -203,7 +203,7 @@ void BranchProbability::normalizeProbabilities(ProbabilityIter Begin, if (Sum <= BranchProbability::getDenominator()) return; } - + if (Sum == 0) { BranchProbability BP(1, std::distance(Begin, End)); std::fill(Begin, End, BP); diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h index 0245632c96a0..7dad3e82bda6 100644 --- a/include/llvm/Support/COFF.h +++ b/include/llvm/Support/COFF.h @@ -377,7 +377,6 @@ namespace COFF { uint8_t unused[10]; }; - /// These are not documented in the spec, but are located in WinNT.h. enum WeakExternalCharacteristics { IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY = 1, IMAGE_WEAK_EXTERN_SEARCH_LIBRARY = 2, @@ -530,7 +529,7 @@ namespace COFF { EXCEPTION_TABLE, CERTIFICATE_TABLE, BASE_RELOCATION_TABLE, - DEBUG, + DEBUG_DIRECTORY, ARCHITECTURE, GLOBAL_PTR, TLS_TABLE, @@ -599,7 +598,13 @@ namespace COFF { IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7, IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8, IMAGE_DEBUG_TYPE_BORLAND = 9, - IMAGE_DEBUG_TYPE_CLSID = 11 + IMAGE_DEBUG_TYPE_RESERVED10 = 10, + IMAGE_DEBUG_TYPE_CLSID = 11, + IMAGE_DEBUG_TYPE_VC_FEATURE = 12, + IMAGE_DEBUG_TYPE_POGO = 13, + IMAGE_DEBUG_TYPE_ILTCG = 14, + IMAGE_DEBUG_TYPE_MPX = 15, + IMAGE_DEBUG_TYPE_REPRO = 16, }; enum BaseRelocationType { @@ -656,26 +661,8 @@ namespace COFF { } }; - enum CodeViewLine : unsigned { - CVL_LineNumberStartBits = 24, - CVL_LineNumberEndDeltaBits = 7, - CVL_LineNumberEndDeltaMask = (1U << CVL_LineNumberEndDeltaBits) - 1, - CVL_MaxLineNumber = (1U << CVL_LineNumberStartBits) - 1, - CVL_IsStatement = 1U << 31, - CVL_MaxColumnNumber = UINT16_MAX, - }; - enum CodeViewIdentifiers { - DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS = 0x1, DEBUG_SECTION_MAGIC = 0x4, - DEBUG_SYMBOL_SUBSECTION = 0xF1, - DEBUG_LINE_TABLE_SUBSECTION = 0xF2, - DEBUG_STRING_TABLE_SUBSECTION = 0xF3, - DEBUG_INDEX_SUBSECTION = 0xF4, - - // Symbol subsections are split into records of different types. - DEBUG_SYMBOL_TYPE_PROC_START = 0x1147, - DEBUG_SYMBOL_TYPE_PROC_END = 0x114F }; inline bool isReservedSectionNumber(int32_t SectionNumber) { diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h new file mode 100644 index 000000000000..383414119139 --- /dev/null +++ b/include/llvm/Support/CachePruning.h @@ -0,0 +1,69 @@ +//=- CachePruning.h - Helper to manage the pruning of a cache dir -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements pruning of a directory intended for cache storage, using +// various policies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CACHE_PRUNING_H +#define LLVM_SUPPORT_CACHE_PRUNING_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +/// Handle pruning a directory provided a path and some options to control what +/// to prune. +class CachePruning { +public: + /// Prepare to prune \p Path. + CachePruning(StringRef Path) : Path(Path) {} + + /// Define the pruning interval. This is intended to be used to avoid scanning + /// the directory too often. It does not impact the decision of which file to + /// prune. A value of 0 forces the scan to occurs. + CachePruning &setPruningInterval(int PruningInterval) { + Interval = PruningInterval; + return *this; + } + + /// Define the expiration for a file. When a file hasn't been accessed for + /// \p ExpireAfter seconds, it is removed from the cache. A value of 0 disable + /// the expiration-based pruning. + CachePruning &setEntryExpiration(unsigned ExpireAfter) { + Expiration = ExpireAfter; + return *this; + } + + /// Define the maximum size for the cache directory, in terms of percentage of + /// the available space on the the disk. Set to 100 to indicate no limit, 50 + /// to indicate that the cache size will not be left over half the + /// available disk space. A value over 100 will be reduced to 100. A value of + /// 0 disable the size-based pruning. + CachePruning &setMaxSize(unsigned Percentage) { + PercentageOfAvailableSpace = std::min(100u, Percentage); + return *this; + } + + /// Peform pruning using the supplied options, returns true if pruning + /// occured, i.e. if PruningInterval was expired. + bool prune(); + +private: + // Options that matches the setters above. + std::string Path; + unsigned Expiration = 0; + unsigned Interval = 0; + unsigned PercentageOfAvailableSpace = 0; +}; + +} // namespace llvm + +#endif
\ No newline at end of file diff --git a/include/llvm/Support/CodeGen.h b/include/llvm/Support/CodeGen.h index 243f2dd7498c..e19abf8271eb 100644 --- a/include/llvm/Support/CodeGen.h +++ b/include/llvm/Support/CodeGen.h @@ -15,22 +15,25 @@ #ifndef LLVM_SUPPORT_CODEGEN_H #define LLVM_SUPPORT_CODEGEN_H -#include "llvm-c/TargetMachine.h" -#include "llvm/Support/ErrorHandling.h" - namespace llvm { // Relocation model types. namespace Reloc { - enum Model { Default, Static, PIC_, DynamicNoPIC }; + enum Model { Static, PIC_, DynamicNoPIC }; } // Code model types. namespace CodeModel { + // Sync changes with CodeGenCWrappers.h. enum Model { Default, JITDefault, Small, Kernel, Medium, Large }; } namespace PICLevel { + // This is used to map -fpic/-fPIC. + enum Level { NotPIC=0, SmallPIC=1, BigPIC=2 }; + } + + namespace PIELevel { enum Level { Default=0, Small=1, Large=2 }; } @@ -54,42 +57,6 @@ namespace llvm { }; } - // Create wrappers for C Binding types (see CBindingWrapping.h). - inline CodeModel::Model unwrap(LLVMCodeModel Model) { - switch (Model) { - case LLVMCodeModelDefault: - return CodeModel::Default; - case LLVMCodeModelJITDefault: - return CodeModel::JITDefault; - case LLVMCodeModelSmall: - return CodeModel::Small; - case LLVMCodeModelKernel: - return CodeModel::Kernel; - case LLVMCodeModelMedium: - return CodeModel::Medium; - case LLVMCodeModelLarge: - return CodeModel::Large; - } - return CodeModel::Default; - } - - inline LLVMCodeModel wrap(CodeModel::Model Model) { - switch (Model) { - case CodeModel::Default: - return LLVMCodeModelDefault; - case CodeModel::JITDefault: - return LLVMCodeModelJITDefault; - case CodeModel::Small: - return LLVMCodeModelSmall; - case CodeModel::Kernel: - return LLVMCodeModelKernel; - case CodeModel::Medium: - return LLVMCodeModelMedium; - case CodeModel::Large: - return LLVMCodeModelLarge; - } - llvm_unreachable("Bad CodeModel!"); - } } // end llvm namespace #endif diff --git a/include/llvm/Support/CodeGenCWrappers.h b/include/llvm/Support/CodeGenCWrappers.h new file mode 100644 index 000000000000..6db4433a4350 --- /dev/null +++ b/include/llvm/Support/CodeGenCWrappers.h @@ -0,0 +1,64 @@ +//===- llvm/Support/CodeGenCWrappers.h - CodeGen C Wrappers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines C bindings wrappers for enums in llvm/Support/CodeGen.h +// that need them. The wrappers are separated to avoid adding an indirect +// dependency on llvm/Config/Targets.def to CodeGen.h. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CODEGENCWRAPPERS_H +#define LLVM_SUPPORT_CODEGENCWRAPPERS_H + +#include "llvm-c/TargetMachine.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +inline CodeModel::Model unwrap(LLVMCodeModel Model) { + switch (Model) { + case LLVMCodeModelDefault: + return CodeModel::Default; + case LLVMCodeModelJITDefault: + return CodeModel::JITDefault; + case LLVMCodeModelSmall: + return CodeModel::Small; + case LLVMCodeModelKernel: + return CodeModel::Kernel; + case LLVMCodeModelMedium: + return CodeModel::Medium; + case LLVMCodeModelLarge: + return CodeModel::Large; + } + return CodeModel::Default; +} + +inline LLVMCodeModel wrap(CodeModel::Model Model) { + switch (Model) { + case CodeModel::Default: + return LLVMCodeModelDefault; + case CodeModel::JITDefault: + return LLVMCodeModelJITDefault; + case CodeModel::Small: + return LLVMCodeModelSmall; + case CodeModel::Kernel: + return LLVMCodeModelKernel; + case CodeModel::Medium: + return LLVMCodeModelMedium; + case CodeModel::Large: + return LLVMCodeModelLarge; + } + llvm_unreachable("Bad CodeModel!"); +} + +} // end llvm namespace + +#endif + diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 943d2df37708..70465a0e3fd3 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -21,10 +21,12 @@ #define LLVM_SUPPORT_COMMANDLINE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ManagedStatic.h" #include <cassert> #include <climits> #include <cstdarg> @@ -43,8 +45,9 @@ namespace cl { //===----------------------------------------------------------------------===// // ParseCommandLineOptions - Command line option processing entry point. // -void ParseCommandLineOptions(int argc, const char *const *argv, - const char *Overview = nullptr); +bool ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview = nullptr, + bool IgnoreErrors = false); //===----------------------------------------------------------------------===// // ParseEnvironmentOptions - Environment variable option processing alternate @@ -171,6 +174,45 @@ public: extern OptionCategory GeneralCategory; //===----------------------------------------------------------------------===// +// SubCommand class +// +class SubCommand { +private: + const char *const Name = nullptr; + const char *const Description = nullptr; + +protected: + void registerSubCommand(); + void unregisterSubCommand(); + +public: + SubCommand(const char *const Name, const char *const Description = nullptr) + : Name(Name), Description(Description) { + registerSubCommand(); + } + SubCommand() {} + + void reset(); + + operator bool() const; + + const char *getName() const { return Name; } + const char *getDescription() const { return Description; } + + SmallVector<Option *, 4> PositionalOpts; + SmallVector<Option *, 4> SinkOpts; + StringMap<Option *> OptionsMap; + + Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it exists. +}; + +// A special subcommand representing no subcommand +extern ManagedStatic<SubCommand> TopLevelSubCommand; + +// A special subcommand that can be used to put an option into all subcommands. +extern ManagedStatic<SubCommand> AllSubCommands; + +//===----------------------------------------------------------------------===// // Option Base class // class alias; @@ -209,6 +251,7 @@ public: StringRef HelpStr; // The descriptive text message for -help StringRef ValueStr; // String describing what the value of this option is OptionCategory *Category; // The Category this option belongs to + SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option belongs to. bool FullyInitialized; // Has addArguemnt been called? inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { @@ -229,6 +272,16 @@ public: // hasArgStr - Return true if the argstr != "" bool hasArgStr() const { return !ArgStr.empty(); } + bool isPositional() const { return getFormattingFlag() == cl::Positional; } + bool isSink() const { return getMiscFlags() & cl::Sink; } + bool isConsumeAfter() const { + return getNumOccurrencesFlag() == cl::ConsumeAfter; + } + bool isInAllSubCommands() const { + return std::any_of(Subs.begin(), Subs.end(), [](const SubCommand *SC) { + return SC == &*AllSubCommands; + }); + } //-------------------------------------------------------------------------=== // Accessor functions set by OptionModifiers @@ -243,6 +296,7 @@ public: void setMiscFlag(enum MiscFlags M) { Misc |= M; } void setPosition(unsigned pos) { Position = pos; } void setCategory(OptionCategory &C) { Category = &C; } + void addSubCommand(SubCommand &S) { Subs.insert(&S); } protected: explicit Option(enum NumOccurrencesFlag OccurrencesFlag, @@ -287,6 +341,7 @@ public: public: inline int getNumOccurrences() const { return NumOccurrences; } + inline void reset() { NumOccurrences = 0; } virtual ~Option() {} }; @@ -349,6 +404,14 @@ struct cat { template <class Opt> void apply(Opt &O) const { O.setCategory(Category); } }; +// sub - Specify the subcommand that this option belongs to. +struct sub { + SubCommand ⋐ + sub(SubCommand &S) : Sub(S) {} + + template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub); } +}; + //===----------------------------------------------------------------------===// // OptionValue class @@ -946,7 +1009,7 @@ public: // getValueName - Overload in subclass to provide a better default value. const char *getValueName() const override { return "string"; } - void printOptionDiff(const Option &O, StringRef V, OptVal Default, + void printOptionDiff(const Option &O, StringRef V, const OptVal &Default, size_t GlobalWidth) const; // An out-of-line virtual method to provide a 'home' for this class. @@ -1589,6 +1652,7 @@ class alias : public Option { error("cl::alias must have argument name specified!"); if (!AliasFor) error("cl::alias must have an cl::aliasopt(option) specified!"); + Subs = AliasFor->Subs; addArgument(); } @@ -1669,7 +1733,7 @@ void PrintHelpMessage(bool Hidden = false, bool Categorized = false); /// Hopefully this API can be depricated soon. Any situation where options need /// to be modified by tools or libraries should be handled by sane APIs rather /// than just handing around a global list. -StringMap<Option *> &getRegisteredOptions(); +StringMap<Option *> &getRegisteredOptions(SubCommand &Sub = *TopLevelSubCommand); //===----------------------------------------------------------------------===// // Standalone command line processing utilities. @@ -1737,7 +1801,8 @@ bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, /// Some tools (like clang-format) like to be able to hide all options that are /// not specific to the tool. This function allows a tool to specify a single /// option category to display in the -help output. -void HideUnrelatedOptions(cl::OptionCategory &Category); +void HideUnrelatedOptions(cl::OptionCategory &Category, + SubCommand &Sub = *TopLevelSubCommand); /// \brief Mark all options not part of the categories as cl::ReallyHidden. /// @@ -1746,7 +1811,19 @@ void HideUnrelatedOptions(cl::OptionCategory &Category); /// Some tools (like clang-format) like to be able to hide all options that are /// not specific to the tool. This function allows a tool to specify a single /// option category to display in the -help output. -void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories); +void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, + SubCommand &Sub = *TopLevelSubCommand); + +/// \brief Reset all command line options to a state that looks as if they have +/// never appeared on the command line. This is useful for being able to parse +/// a command line multiple times (especially useful for writing tests). +void ResetAllOptionOccurrences(); + +/// \brief Reset the command line parser back to its initial state. This +/// removes +/// all options, categories, and subcommands and returns the parser to a state +/// where no options are supported. +void ResetCommandLineParser(); } // End namespace cl diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index b3416bbfffb6..fae0d8f4419e 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -17,6 +17,10 @@ #include "llvm/Config/llvm-config.h" +#if defined(_MSC_VER) +#include <sal.h> +#endif + #ifndef __has_feature # define __has_feature(x) 0 #endif @@ -92,7 +96,7 @@ #define LLVM_LVALUE_FUNCTION #endif -#if __has_feature(cxx_constexpr) || defined(__GXX_EXPERIMENTAL_CXX0X__) +#if __has_feature(cxx_constexpr) || defined(__GXX_EXPERIMENTAL_CXX0X__) || LLVM_MSC_PREREQ(1900) # define LLVM_CONSTEXPR constexpr #else # define LLVM_CONSTEXPR @@ -124,6 +128,8 @@ #if __has_attribute(warn_unused_result) || LLVM_GNUC_PREREQ(3, 4, 0) #define LLVM_ATTRIBUTE_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_UNUSED_RESULT _Check_return_ #else #define LLVM_ATTRIBUTE_UNUSED_RESULT #endif @@ -206,6 +212,8 @@ #if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0) #define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_ #else #define LLVM_ATTRIBUTE_RETURNS_NONNULL #endif @@ -266,6 +274,23 @@ # define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0 #endif +/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to +/// an expression which causes the program to break while running +/// under a debugger. +#if __has_builtin(__builtin_debugtrap) +# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap() +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC and breaks while +// running under the debugger, and also supports invoking a debugger +// when the OS is configured appropriately. +# define LLVM_BUILTIN_DEBUGTRAP __debugbreak() +#else +// Just continue execution when built with compilers that have no +// support. This is a debugging aid and not intended to force the +// program to abort if encountered. +# define LLVM_BUILTIN_DEBUGTRAP +#endif + /// \macro LLVM_ASSUME_ALIGNED /// \brief Returns a pointer with an assumed alignment. #if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0) @@ -407,6 +432,14 @@ void AnnotateIgnoreWritesEnd(const char *file, int line); # define TsanIgnoreWritesEnd() #endif +/// \macro LLVM_NO_SANITIZE +/// \brief Disable a particular sanitizer for a function. +#if __has_attribute(no_sanitize) +#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND))) +#else +#define LLVM_NO_SANITIZE(KIND) +#endif + /// \brief Mark debug helper function definitions like dump() that should not be /// stripped from debug builds. // FIXME: Move this to a private config.h as it's not usable in public headers. diff --git a/include/llvm/Support/ConvertUTF.h b/include/llvm/Support/ConvertUTF.h index 38952ec99e61..5de5774f9db5 100644 --- a/include/llvm/Support/ConvertUTF.h +++ b/include/llvm/Support/ConvertUTF.h @@ -180,10 +180,13 @@ unsigned getNumBytesForUTF8(UTF8 firstByte); /*************************************************************************/ /* Below are LLVM-specific wrappers of the functions above. */ -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" +#include <string> +#include <cstddef> namespace llvm { +template <typename T> class ArrayRef; +template <typename T> class SmallVectorImpl; +class StringRef; /** * Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on @@ -198,6 +201,25 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, char *&ResultPtr, const UTF8 *&ErrorPtr); /** +* Converts a UTF-8 StringRef to a std::wstring. +* \return true on success. +*/ +bool ConvertUTF8toWide(llvm::StringRef Source, std::wstring &Result); + +/** +* Converts a UTF-8 C-string to a std::wstring. +* \return true on success. +*/ +bool ConvertUTF8toWide(const char *Source, std::wstring &Result); + +/** +* Converts a std::wstring to a UTF-8 encoded std::string. +* \return true on success. +*/ +bool convertWideToUTF8(const std::wstring &Source, std::string &Result); + + +/** * Convert an Unicode code point to UTF8 sequence. * * \param Source a Unicode code point. @@ -252,6 +274,15 @@ bool hasUTF16ByteOrderMark(ArrayRef<char> SrcBytes); bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out); /** +* Converts a UTF16 string into a UTF8 std::string. +* +* \param [in] Src A buffer of UTF-16 encoded text. +* \param [out] Out Converted UTF-8 is stored here on success. +* \returns true on success +*/ +bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out); + +/** * Converts a UTF-8 string into a UTF-16 string with native endianness. * * \returns true on success diff --git a/include/llvm/Support/CrashRecoveryContext.h b/include/llvm/Support/CrashRecoveryContext.h index 1a1c74368761..6cbc331d2731 100644 --- a/include/llvm/Support/CrashRecoveryContext.h +++ b/include/llvm/Support/CrashRecoveryContext.h @@ -11,7 +11,6 @@ #define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H #include "llvm/ADT/STLExtras.h" -#include <string> namespace llvm { class CrashRecoveryContextCleanup; @@ -70,8 +69,7 @@ public: /// \return True if the function completed successfully, and false if the /// function crashed (or HandleCrash was called explicitly). Clients should /// make as little assumptions as possible about the program state when - /// RunSafely has returned false. Clients can use getBacktrace() to retrieve - /// the backtrace of the crash on failures. + /// RunSafely has returned false. bool RunSafely(function_ref<void()> Fn); bool RunSafely(void (*Fn)(void*), void *UserData) { return RunSafely([&]() { Fn(UserData); }); @@ -94,13 +92,6 @@ public: /// \brief Explicitly trigger a crash recovery in the current process, and /// return failure from RunSafely(). This function does not return. void HandleCrash(); - - /// \brief Return a string containing the backtrace where the crash was - /// detected; or empty if the backtrace wasn't recovered. - /// - /// This function is only valid when a crash has been detected (i.e., - /// RunSafely() has returned false. - const std::string &getBacktrace() const; }; class CrashRecoveryContextCleanup { diff --git a/include/llvm/Support/DataTypes.h.cmake b/include/llvm/Support/DataTypes.h.cmake index c90bf51afaee..541dbc3d635d 100644 --- a/include/llvm/Support/DataTypes.h.cmake +++ b/include/llvm/Support/DataTypes.h.cmake @@ -21,8 +21,6 @@ /* Please leave this file C-compatible. */ -/* Please keep this file in sync with DataTypes.h.in */ - #ifndef SUPPORT_DATATYPES_H #define SUPPORT_DATATYPES_H @@ -37,36 +35,43 @@ #include <math.h> #endif +#ifdef __cplusplus +#include <cinttypes> +#else #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif +#endif +#ifdef __cplusplus +#include <cstdint> +#else #ifdef HAVE_STDINT_H #include <stdint.h> #else #error "Compiler must provide an implementation of stdint.h" #endif +#endif #ifndef _MSC_VER -/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS - being defined. We would define it here, but in order to prevent Bad Things - happening when system headers or C++ STL headers include stdint.h before we - define it here, we define it on the g++ command line (in Makefile.rules). */ -#if !defined(__STDC_LIMIT_MACROS) -# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h" +#if !defined(UINT32_MAX) +# error "The standard header <cstdint> is not C++11 compliant. Must #define "\ + "__STDC_LIMIT_MACROS before #including Support/DataTypes.h" #endif -#if !defined(__STDC_CONSTANT_MACROS) -# error "Must #define __STDC_CONSTANT_MACROS before " \ - "#including Support/DataTypes.h" +#if !defined(UINT32_C) +# error "The standard header <cstdint> is not C++11 compliant. Must #define "\ + "__STDC_CONSTANT_MACROS before #including Support/DataTypes.h" #endif /* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ #include <sys/types.h> #ifdef _AIX -#include "llvm/Support/AIXDataTypesFix.h" +// GCC is strict about defining large constants: they must have LL modifier. +#undef INT64_MAX +#undef INT64_MIN #endif /* Handle incorrect definition of uint64_t as u_int64_t */ @@ -79,14 +84,14 @@ typedef u_int64_t uint64_t; #endif #else /* _MSC_VER */ -#include <stdlib.h> -#include <stddef.h> -#include <sys/types.h> #ifdef __cplusplus -#include <cmath> +#include <cstdlib> +#include <cstddef> #else -#include <math.h> +#include <stdlib.h> +#include <stddef.h> #endif +#include <sys/types.h> #if defined(_WIN64) typedef signed __int64 ssize_t; @@ -127,4 +132,4 @@ typedef signed int ssize_t; #define HUGE_VALF (float)HUGE_VAL #endif -#endif /* SUPPORT_DATATYPES_H */ +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/DataTypes.h.in b/include/llvm/Support/DataTypes.h.in deleted file mode 100644 index b8b2ba56ff30..000000000000 --- a/include/llvm/Support/DataTypes.h.in +++ /dev/null @@ -1,123 +0,0 @@ -/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\ -|* *| -|* The LLVM Compiler Infrastructure *| -|* *| -|* This file is distributed under the University of Illinois Open Source *| -|* License. See LICENSE.TXT for details. *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This file contains definitions to figure out the size of _HOST_ data types.*| -|* This file is important because different host OS's define different macros,*| -|* which makes portability tough. This file exports the following *| -|* definitions: *| -|* *| -|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| -|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| -|* *| -|* No library is required when using these functions. *| -|* *| -|*===----------------------------------------------------------------------===*/ - -/* Please leave this file C-compatible. */ - -/* Please keep this file in sync with DataTypes.h.cmake */ - -#ifndef SUPPORT_DATATYPES_H -#define SUPPORT_DATATYPES_H - -#undef HAVE_INTTYPES_H -#undef HAVE_STDINT_H -#undef HAVE_UINT64_T -#undef HAVE_U_INT64_T - -#ifdef __cplusplus -#include <cmath> -#else -#include <math.h> -#endif - -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#endif - -#ifdef HAVE_STDINT_H -#include <stdint.h> -#else -#error "Compiler must provide an implementation of stdint.h" -#endif - -#ifndef _MSC_VER - -/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS - being defined. We would define it here, but in order to prevent Bad Things - happening when system headers or C++ STL headers include stdint.h before we - define it here, we define it on the g++ command line (in Makefile.rules). */ -#if !defined(__STDC_LIMIT_MACROS) -# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h" -#endif - -#if !defined(__STDC_CONSTANT_MACROS) -# error "Must #define __STDC_CONSTANT_MACROS before " \ - "#including Support/DataTypes.h" -#endif - -/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ -#include <sys/types.h> - -#ifdef _AIX -#include "llvm/Support/AIXDataTypesFix.h" -#endif - -/* Handle incorrect definition of uint64_t as u_int64_t */ -#ifndef HAVE_UINT64_T -#ifdef HAVE_U_INT64_T -typedef u_int64_t uint64_t; -#else -# error "Don't have a definition for uint64_t on this platform" -#endif -#endif - -#else /* _MSC_VER */ -#include <stdlib.h> -#include <stddef.h> -#include <sys/types.h> -#ifdef __cplusplus -#include <cmath> -#else -#include <math.h> -#endif - -#if defined(_WIN64) -typedef signed __int64 ssize_t; -#else -typedef signed int ssize_t; -#endif /* _WIN64 */ - -#ifndef HAVE_INTTYPES_H -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#endif /* HAVE_INTTYPES_H */ - -#endif /* _MSC_VER */ - -/* Set defaults for constants which we cannot find. */ -#if !defined(INT64_MAX) -# define INT64_MAX 9223372036854775807LL -#endif -#if !defined(INT64_MIN) -# define INT64_MIN ((-INT64_MAX)-1) -#endif -#if !defined(UINT64_MAX) -# define UINT64_MAX 0xffffffffffffffffULL -#endif - -#ifndef HUGE_VALF -#define HUGE_VALF (float)HUGE_VAL -#endif - -#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/Dwarf.def b/include/llvm/Support/Dwarf.def index b15070b3e9b0..b73f2aed5311 100644 --- a/include/llvm/Support/Dwarf.def +++ b/include/llvm/Support/Dwarf.def @@ -14,7 +14,7 @@ // TODO: Add other DW-based macros. #if !(defined HANDLE_DW_TAG || defined HANDLE_DW_OP || \ defined HANDLE_DW_LANG || defined HANDLE_DW_ATE || \ - defined HANDLE_DW_VIRTUALITY) + defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_CC) #error "Missing macro definition of HANDLE_DW*" #endif @@ -38,6 +38,11 @@ #define HANDLE_DW_VIRTUALITY(ID, NAME) #endif +#ifndef HANDLE_DW_CC +#define HANDLE_DW_CC(ID, NAME) +#endif + + HANDLE_DW_TAG(0x0001, array_type) HANDLE_DW_TAG(0x0002, class_type) HANDLE_DW_TAG(0x0003, entry_point) @@ -320,6 +325,7 @@ HANDLE_DW_LANG(0x0021, C_plus_plus_14) HANDLE_DW_LANG(0x0022, Fortran03) HANDLE_DW_LANG(0x0023, Fortran08) HANDLE_DW_LANG(0x8001, Mips_Assembler) +HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript) HANDLE_DW_LANG(0xb000, BORLAND_Delphi) // DWARF attribute type encodings. @@ -345,8 +351,23 @@ HANDLE_DW_VIRTUALITY(0x00, none) HANDLE_DW_VIRTUALITY(0x01, virtual) HANDLE_DW_VIRTUALITY(0x02, pure_virtual) +// DWARF calling convention codes. +HANDLE_DW_CC(0x01, normal) +HANDLE_DW_CC(0x02, program) +HANDLE_DW_CC(0x03, nocall) +HANDLE_DW_CC(0x41, GNU_borland_fastcall_i386) +HANDLE_DW_CC(0xb0, BORLAND_safecall) +HANDLE_DW_CC(0xb1, BORLAND_stdcall) +HANDLE_DW_CC(0xb2, BORLAND_pascal) +HANDLE_DW_CC(0xb3, BORLAND_msfastcall) +HANDLE_DW_CC(0xb4, BORLAND_msreturn) +HANDLE_DW_CC(0xb5, BORLAND_thiscall) +HANDLE_DW_CC(0xb6, BORLAND_fastcall) +HANDLE_DW_CC(0xc0, LLVM_vectorcall) + #undef HANDLE_DW_TAG #undef HANDLE_DW_OP #undef HANDLE_DW_LANG #undef HANDLE_DW_ATE #undef HANDLE_DW_VIRTUALITY +#undef HANDLE_DW_CC diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h index cea61bd75833..86b19676c345 100644 --- a/include/llvm/Support/Dwarf.h +++ b/include/llvm/Support/Dwarf.h @@ -20,11 +20,11 @@ #ifndef LLVM_SUPPORT_DWARF_H #define LLVM_SUPPORT_DWARF_H -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" namespace llvm { +class StringRef; namespace dwarf { @@ -389,18 +389,9 @@ enum CaseSensitivity { enum CallingConvention { // Calling convention codes - DW_CC_normal = 0x01, - DW_CC_program = 0x02, - DW_CC_nocall = 0x03, +#define HANDLE_DW_CC(ID, NAME) DW_CC_##NAME = ID, +#include "llvm/Support/Dwarf.def" DW_CC_lo_user = 0x40, - DW_CC_GNU_borland_fastcall_i386 = 0x41, - DW_CC_BORLAND_safecall = 0xb0, - DW_CC_BORLAND_stdcall = 0xb1, - DW_CC_BORLAND_pascal = 0xb2, - DW_CC_BORLAND_msfastcall = 0xb3, - DW_CC_BORLAND_msreturn = 0xb4, - DW_CC_BORLAND_thiscall = 0xb5, - DW_CC_BORLAND_fastcall = 0xb6, DW_CC_hi_user = 0xff }; @@ -547,7 +538,7 @@ enum LocationListEntry : unsigned char { DW_LLE_offset_pair_entry }; -/// Contstants for the DW_APPLE_PROPERTY_attributes attribute. +/// Constants for the DW_APPLE_PROPERTY_attributes attribute. /// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind. enum ApplePropertyAttributes { // Apple Objective-C Property Attributes @@ -562,7 +553,10 @@ enum ApplePropertyAttributes { DW_APPLE_PROPERTY_atomic = 0x100, DW_APPLE_PROPERTY_weak = 0x200, DW_APPLE_PROPERTY_strong = 0x400, - DW_APPLE_PROPERTY_unsafe_unretained = 0x800 + DW_APPLE_PROPERTY_unsafe_unretained = 0x800, + DW_APPLE_PROPERTY_nullability = 0x1000, + DW_APPLE_PROPERTY_null_resettable = 0x2000, + DW_APPLE_PROPERTY_class = 0x4000 }; // Constants for the DWARF5 Accelerator Table Proposal @@ -652,6 +646,7 @@ unsigned getTag(StringRef TagString); unsigned getOperationEncoding(StringRef OperationEncodingString); unsigned getVirtuality(StringRef VirtualityString); unsigned getLanguage(StringRef LanguageString); +unsigned getCallingConvention(StringRef LanguageString); unsigned getAttributeEncoding(StringRef EncodingString); unsigned getMacinfo(StringRef MacinfoString); /// @} diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index e24420fc1fe4..70b9daab8360 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -310,6 +310,8 @@ enum { EM_NORC = 218, // Nanoradio Optimized RISC EM_CSR_KALIMBA = 219, // CSR Kalimba architecture family EM_AMDGPU = 224, // AMD GPU architecture + EM_LANAI = 244, // Lanai 32-bit processor + EM_BPF = 247, // Linux kernel bpf virtual machine // A request has been made to the maintainer of the official registry for // such numbers for an official value for WebAssembly. As soon as one is @@ -481,6 +483,7 @@ enum : unsigned { EF_MIPS_ABI = 0x0000f000, // Mask for selecting EF_MIPS_ABI_ variant. // MIPS machine variant + EF_MIPS_MACH_NONE = 0x00000000, // A standard MIPS implementation. EF_MIPS_MACH_3900 = 0x00810000, // Toshiba R3900 EF_MIPS_MACH_4010 = 0x00820000, // LSI R4010 EF_MIPS_MACH_4100 = 0x00830000, // NEC VR4100 @@ -589,6 +592,11 @@ enum { #include "ELFRelocs/Hexagon.def" }; +// ELF Relocation type for Lanai. +enum { +#include "ELFRelocs/Lanai.def" +}; + // ELF Relocation types for S390/zSeries enum { #include "ELFRelocs/SystemZ.def" @@ -604,6 +612,16 @@ enum { #include "ELFRelocs/WebAssembly.def" }; +// ELF Relocation types for AMDGPU +enum { +#include "ELFRelocs/AMDGPU.def" +}; + +// ELF Relocation types for BPF +enum { +#include "ELFRelocs/BPF.def" +}; + #undef ELF_RELOC // Section header. @@ -730,6 +748,9 @@ enum : unsigned { // This section holds Thread-Local Storage. SHF_TLS = 0x400U, + // Identifies a section containing compressed data. + SHF_COMPRESSED = 0x800U, + // This section is excluded from the final executable or shared library. SHF_EXCLUDE = 0x80000000U, @@ -1116,6 +1137,8 @@ enum { DT_HIPROC = 0x7FFFFFFF, // End of processor specific tags. DT_GNU_HASH = 0x6FFFFEF5, // Reference to the GNU hash table. + DT_TLSDESC_PLT = 0x6FFFFEF6, // Location of PLT entry for TLS descriptor resolver calls. + DT_TLSDESC_GOT = 0x6FFFFEF7, // Location of GOT entry used by TLS descriptor resolver PLT entry. DT_RELACOUNT = 0x6FFFFFF9, // ELF32_Rela count. DT_RELCOUNT = 0x6FFFFFFA, // ELF32_Rel count. @@ -1199,8 +1222,12 @@ enum { DT_MIPS_PLTGOT = 0x70000032, // Address of the base of the PLTGOT. DT_MIPS_RWPLT = 0x70000034, // Points to the base // of a writable PLT. - DT_MIPS_RLD_MAP_REL = 0x70000035 // Relative offset of run time loader + DT_MIPS_RLD_MAP_REL = 0x70000035, // Relative offset of run time loader // map, used for debugging. + + // Sun machine-independent extensions. + DT_AUXILIARY = 0x7FFFFFFD, // Shared object to load before self + DT_FILTER = 0x7FFFFFFF // Shared object to get values from }; // DT_FLAGS values. @@ -1294,6 +1321,35 @@ enum { VER_NEED_CURRENT = 1 }; +// SHT_NOTE section types +enum { + NT_GNU_BUILD_ID = 3 +}; + +// Compressed section header for ELF32. +struct Elf32_Chdr { + Elf32_Word ch_type; + Elf32_Word ch_size; + Elf32_Word ch_addralign; +}; + +// Compressed section header for ELF64. +struct Elf64_Chdr { + Elf64_Word ch_type; + Elf64_Word ch_reserved; + Elf64_Xword ch_size; + Elf64_Xword ch_addralign; +}; + +// Legal values for ch_type field of compressed section header. +enum { + ELFCOMPRESS_ZLIB = 1, // ZLIB/DEFLATE algorithm. + ELFCOMPRESS_LOOS = 0x60000000, // Start of OS-specific. + ELFCOMPRESS_HIOS = 0x6fffffff, // End of OS-specific. + ELFCOMPRESS_LOPROC = 0x70000000, // Start of processor-specific. + ELFCOMPRESS_HIPROC = 0x7fffffff // End of processor-specific. +}; + } // end namespace ELF } // end namespace llvm diff --git a/include/llvm/Support/ELFRelocs/AMDGPU.def b/include/llvm/Support/ELFRelocs/AMDGPU.def new file mode 100644 index 000000000000..c1e6797fdb0d --- /dev/null +++ b/include/llvm/Support/ELFRelocs/AMDGPU.def @@ -0,0 +1,12 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC(R_AMDGPU_NONE, 0) +ELF_RELOC(R_AMDGPU_ABS32_LO, 1) +ELF_RELOC(R_AMDGPU_ABS32_HI, 2) +ELF_RELOC(R_AMDGPU_ABS64, 3) +ELF_RELOC(R_AMDGPU_REL32, 4) +ELF_RELOC(R_AMDGPU_REL64, 5) +ELF_RELOC(R_AMDGPU_ABS32, 6) +ELF_RELOC(R_AMDGPU_GOTPCREL, 7) diff --git a/include/llvm/Support/ELFRelocs/BPF.def b/include/llvm/Support/ELFRelocs/BPF.def new file mode 100644 index 000000000000..868974d683c7 --- /dev/null +++ b/include/llvm/Support/ELFRelocs/BPF.def @@ -0,0 +1,9 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +// No relocation +ELF_RELOC(R_BPF_NONE, 0) +// Map index in "maps" section to file descriptor +// within ld_64 instruction. +ELF_RELOC(R_BPF_MAP_FD, 1) diff --git a/include/llvm/Support/ELFRelocs/Hexagon.def b/include/llvm/Support/ELFRelocs/Hexagon.def index a698ecb89e16..74e1d405cebd 100644 --- a/include/llvm/Support/ELFRelocs/Hexagon.def +++ b/include/llvm/Support/ELFRelocs/Hexagon.def @@ -98,3 +98,4 @@ ELF_RELOC(R_HEX_LD_GOT_16, 90) ELF_RELOC(R_HEX_LD_GOT_32_6_X, 91) ELF_RELOC(R_HEX_LD_GOT_16_X, 92) ELF_RELOC(R_HEX_LD_GOT_11_X, 93) +ELF_RELOC(R_HEX_23_REG, 94) diff --git a/include/llvm/Support/ELFRelocs/Lanai.def b/include/llvm/Support/ELFRelocs/Lanai.def new file mode 100644 index 000000000000..77ecb048403d --- /dev/null +++ b/include/llvm/Support/ELFRelocs/Lanai.def @@ -0,0 +1,19 @@ + +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +// No relocation +ELF_RELOC(R_LANAI_NONE, 0) +// 21-bit symbol relocation +ELF_RELOC(R_LANAI_21, 1) +// 21-bit symbol relocation with last two bits masked to 0 +ELF_RELOC(R_LANAI_21_F, 2) +// 25-bit branch targets +ELF_RELOC(R_LANAI_25, 3) +// General 32-bit relocation +ELF_RELOC(R_LANAI_32, 4) +// Upper 16-bits of a symbolic relocation +ELF_RELOC(R_LANAI_HI16, 5) +// Lower 16-bits of a symbolic relocation +ELF_RELOC(R_LANAI_LO16, 6) diff --git a/include/llvm/Support/ELFRelocs/Mips.def b/include/llvm/Support/ELFRelocs/Mips.def index 77e7f8e8712b..bc0088dff3f4 100644 --- a/include/llvm/Support/ELFRelocs/Mips.def +++ b/include/llvm/Support/ELFRelocs/Mips.def @@ -108,8 +108,8 @@ ELF_RELOC(R_MICROMIPS_TLS_TPREL_HI16, 169) ELF_RELOC(R_MICROMIPS_TLS_TPREL_LO16, 170) ELF_RELOC(R_MICROMIPS_GPREL7_S2, 172) ELF_RELOC(R_MICROMIPS_PC23_S2, 173) -ELF_RELOC(R_MICROMIPS_PC21_S2, 174) -ELF_RELOC(R_MICROMIPS_PC26_S2, 175) +ELF_RELOC(R_MICROMIPS_PC21_S1, 174) +ELF_RELOC(R_MICROMIPS_PC26_S1, 175) ELF_RELOC(R_MICROMIPS_PC18_S3, 176) ELF_RELOC(R_MICROMIPS_PC19_S2, 177) ELF_RELOC(R_MIPS_NUM, 218) diff --git a/include/llvm/Support/ELFRelocs/i386.def b/include/llvm/Support/ELFRelocs/i386.def index 45eae7fe426b..1d28cf595cd5 100644 --- a/include/llvm/Support/ELFRelocs/i386.def +++ b/include/llvm/Support/ELFRelocs/i386.def @@ -44,4 +44,4 @@ ELF_RELOC(R_386_TLS_GOTDESC, 39) ELF_RELOC(R_386_TLS_DESC_CALL, 40) ELF_RELOC(R_386_TLS_DESC, 41) ELF_RELOC(R_386_IRELATIVE, 42) -ELF_RELOC(R_386_NUM, 43) +ELF_RELOC(R_386_GOT32X, 43) diff --git a/include/llvm/Support/ELFRelocs/x86_64.def b/include/llvm/Support/ELFRelocs/x86_64.def index 36ad0618eb2d..18fdcf9472dc 100644 --- a/include/llvm/Support/ELFRelocs/x86_64.def +++ b/include/llvm/Support/ELFRelocs/x86_64.def @@ -41,4 +41,5 @@ ELF_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) ELF_RELOC(R_X86_64_TLSDESC_CALL, 35) ELF_RELOC(R_X86_64_TLSDESC, 36) ELF_RELOC(R_X86_64_IRELATIVE, 37) - +ELF_RELOC(R_X86_64_GOTPCRELX, 41) +ELF_RELOC(R_X86_64_REX_GOTPCRELX, 42) diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index bc93c9a66eef..cb5cd8e511b1 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -173,6 +173,10 @@ template<typename value_type, endianness endian, std::size_t alignment> struct packed_endian_specific_integral { + packed_endian_specific_integral() = default; + + explicit packed_endian_specific_integral(value_type val) { *this = val; } + operator value_type() const { return endian::read<value_type, endian, alignment>( (const void*)Value.buffer); diff --git a/include/llvm/Support/EndianStream.h b/include/llvm/Support/EndianStream.h index d44a9b3b7ce8..43ecd4a5c97e 100644 --- a/include/llvm/Support/EndianStream.h +++ b/include/llvm/Support/EndianStream.h @@ -15,6 +15,7 @@ #ifndef LLVM_SUPPORT_ENDIANSTREAM_H #define LLVM_SUPPORT_ENDIANSTREAM_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" @@ -26,6 +27,10 @@ namespace endian { template <endianness endian> struct Writer { raw_ostream &OS; Writer(raw_ostream &OS) : OS(OS) {} + template <typename value_type> void write(ArrayRef<value_type> Vals) { + for (value_type V : Vals) + write(V); + } template <typename value_type> void write(value_type Val) { Val = byte_swap<value_type, endian>(Val); OS.write((const char *)&Val, sizeof(value_type)); diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h new file mode 100644 index 000000000000..5f515a88a021 --- /dev/null +++ b/include/llvm/Support/Error.h @@ -0,0 +1,950 @@ +//===----- llvm/Support/Error.h - Recoverable error handling ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an API used to report recoverable errors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ERROR_H +#define LLVM_SUPPORT_ERROR_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +namespace llvm { + +class Error; +class ErrorList; + +/// Base class for error info classes. Do not extend this directly: Extend +/// the ErrorInfo template subclass instead. +class ErrorInfoBase { +public: + virtual ~ErrorInfoBase() {} + + /// Print an error message to an output stream. + virtual void log(raw_ostream &OS) const = 0; + + /// Return the error message as a string. + virtual std::string message() const { + std::string Msg; + raw_string_ostream OS(Msg); + log(OS); + return OS.str(); + } + + /// Convert this error to a std::error_code. + /// + /// This is a temporary crutch to enable interaction with code still + /// using std::error_code. It will be removed in the future. + virtual std::error_code convertToErrorCode() const = 0; + + // Check whether this instance is a subclass of the class identified by + // ClassID. + virtual bool isA(const void *const ClassID) const { + return ClassID == classID(); + } + + // Check whether this instance is a subclass of ErrorInfoT. + template <typename ErrorInfoT> bool isA() const { + return isA(ErrorInfoT::classID()); + } + + // Returns the class ID for this type. + static const void *classID() { return &ID; } + +private: + virtual void anchor(); + static char ID; +}; + +/// Lightweight error class with error context and mandatory checking. +/// +/// Instances of this class wrap a ErrorInfoBase pointer. Failure states +/// are represented by setting the pointer to a ErrorInfoBase subclass +/// instance containing information describing the failure. Success is +/// represented by a null pointer value. +/// +/// Instances of Error also contains a 'Checked' flag, which must be set +/// before the destructor is called, otherwise the destructor will trigger a +/// runtime error. This enforces at runtime the requirement that all Error +/// instances be checked or returned to the caller. +/// +/// There are two ways to set the checked flag, depending on what state the +/// Error instance is in. For Error instances indicating success, it +/// is sufficient to invoke the boolean conversion operator. E.g.: +/// +/// Error foo(<...>); +/// +/// if (auto E = foo(<...>)) +/// return E; // <- Return E if it is in the error state. +/// // We have verified that E was in the success state. It can now be safely +/// // destroyed. +/// +/// A success value *can not* be dropped. For example, just calling 'foo(<...>)' +/// without testing the return value will raise a runtime error, even if foo +/// returns success. +/// +/// For Error instances representing failure, you must use either the +/// handleErrors or handleAllErrors function with a typed handler. E.g.: +/// +/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> { +/// // Custom error info. +/// }; +/// +/// Error foo(<...>) { return make_error<MyErrorInfo>(...); } +/// +/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo. +/// auto NewE = +/// handleErrors(E, +/// [](const MyErrorInfo &M) { +/// // Deal with the error. +/// }, +/// [](std::unique_ptr<OtherError> M) -> Error { +/// if (canHandle(*M)) { +/// // handle error. +/// return Error::success(); +/// } +/// // Couldn't handle this error instance. Pass it up the stack. +/// return Error(std::move(M)); +/// ); +/// // Note - we must check or return NewE in case any of the handlers +/// // returned a new error. +/// +/// The handleAllErrors function is identical to handleErrors, except +/// that it has a void return type, and requires all errors to be handled and +/// no new errors be returned. It prevents errors (assuming they can all be +/// handled) from having to be bubbled all the way to the top-level. +/// +/// *All* Error instances must be checked before destruction, even if +/// they're moved-assigned or constructed from Success values that have already +/// been checked. This enforces checking through all levels of the call stack. +class Error { + + // ErrorList needs to be able to yank ErrorInfoBase pointers out of this + // class to add to the error list. + friend class ErrorList; + + // handleErrors needs to be able to set the Checked flag. + template <typename... HandlerTs> + friend Error handleErrors(Error E, HandlerTs &&... Handlers); + + // Expected<T> needs to be able to steal the payload when constructed from an + // error. + template <typename T> class Expected; + +public: + /// Create a success value. Prefer using 'Error::success()' for readability + /// where possible. + Error() { + setPtr(nullptr); + setChecked(false); + } + + /// Create a success value. This is equivalent to calling the default + /// constructor, but should be preferred for readability where possible. + static Error success() { return Error(); } + + // Errors are not copy-constructable. + Error(const Error &Other) = delete; + + /// Move-construct an error value. The newly constructed error is considered + /// unchecked, even if the source error had been checked. The original error + /// becomes a checked Success value, regardless of its original state. + Error(Error &&Other) { + setChecked(true); + *this = std::move(Other); + } + + /// Create an error value. Prefer using the 'make_error' function, but + /// this constructor can be useful when "re-throwing" errors from handlers. + Error(std::unique_ptr<ErrorInfoBase> Payload) { + setPtr(Payload.release()); + setChecked(false); + } + + // Errors are not copy-assignable. + Error &operator=(const Error &Other) = delete; + + /// Move-assign an error value. The current error must represent success, you + /// you cannot overwrite an unhandled error. The current error is then + /// considered unchecked. The source error becomes a checked success value, + /// regardless of its original state. + Error &operator=(Error &&Other) { + // Don't allow overwriting of unchecked values. + assertIsChecked(); + setPtr(Other.getPtr()); + + // This Error is unchecked, even if the source error was checked. + setChecked(false); + + // Null out Other's payload and set its checked bit. + Other.setPtr(nullptr); + Other.setChecked(true); + + return *this; + } + + /// Destroy a Error. Fails with a call to abort() if the error is + /// unchecked. + ~Error() { + assertIsChecked(); + delete getPtr(); + } + + /// Bool conversion. Returns true if this Error is in a failure state, + /// and false if it is in an accept state. If the error is in a Success state + /// it will be considered checked. + explicit operator bool() { + setChecked(getPtr() == nullptr); + return getPtr() != nullptr; + } + + /// Check whether one error is a subclass of another. + template <typename ErrT> bool isA() const { + return getPtr() && getPtr()->isA(ErrT::classID()); + } + +private: + void assertIsChecked() { +#ifndef NDEBUG + if (!getChecked() || getPtr()) { + dbgs() << "Program aborted due to an unhandled Error:\n"; + if (getPtr()) + getPtr()->log(dbgs()); + else + dbgs() + << "Error value was Success. (Note: Success values must still be " + "checked prior to being destroyed).\n"; + abort(); + } +#endif + } + + ErrorInfoBase *getPtr() const { +#ifndef NDEBUG + return PayloadAndCheckedBit.getPointer(); +#else + return Payload; +#endif + } + + void setPtr(ErrorInfoBase *EI) { +#ifndef NDEBUG + PayloadAndCheckedBit.setPointer(EI); +#else + Payload = EI; +#endif + } + + bool getChecked() const { +#ifndef NDEBUG + return PayloadAndCheckedBit.getInt(); +#else + return true; +#endif + } + + void setChecked(bool V) { +#ifndef NDEBUG + PayloadAndCheckedBit.setInt(V); +#endif + } + + std::unique_ptr<ErrorInfoBase> takePayload() { + std::unique_ptr<ErrorInfoBase> Tmp(getPtr()); + setPtr(nullptr); + setChecked(true); + return Tmp; + } + +#ifndef NDEBUG + PointerIntPair<ErrorInfoBase *, 1> PayloadAndCheckedBit; +#else + ErrorInfoBase *Payload; +#endif +}; + +/// Make a Error instance representing failure using the given error info +/// type. +template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { + return Error(llvm::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); +} + +/// Base class for user error types. Users should declare their error types +/// like: +/// +/// class MyError : public ErrorInfo<MyError> { +/// .... +/// }; +/// +/// This class provides an implementation of the ErrorInfoBase::kind +/// method, which is used by the Error RTTI system. +template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> +class ErrorInfo : public ParentErrT { +public: + bool isA(const void *const ClassID) const override { + return ClassID == classID() || ParentErrT::isA(ClassID); + } + + static const void *classID() { return &ThisErrT::ID; } +}; + +/// Special ErrorInfo subclass representing a list of ErrorInfos. +/// Instances of this class are constructed by joinError. +class ErrorList final : public ErrorInfo<ErrorList> { + + // handleErrors needs to be able to iterate the payload list of an + // ErrorList. + template <typename... HandlerTs> + friend Error handleErrors(Error E, HandlerTs &&... Handlers); + + // joinErrors is implemented in terms of join. + friend Error joinErrors(Error, Error); + +public: + void log(raw_ostream &OS) const override { + OS << "Multiple errors:\n"; + for (auto &ErrPayload : Payloads) { + ErrPayload->log(OS); + OS << "\n"; + } + } + + std::error_code convertToErrorCode() const override; + + // Used by ErrorInfo::classID. + static char ID; + +private: + ErrorList(std::unique_ptr<ErrorInfoBase> Payload1, + std::unique_ptr<ErrorInfoBase> Payload2) { + assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && + "ErrorList constructor payloads should be singleton errors"); + Payloads.push_back(std::move(Payload1)); + Payloads.push_back(std::move(Payload2)); + } + + static Error join(Error E1, Error E2) { + if (!E1) + return E2; + if (!E2) + return E1; + if (E1.isA<ErrorList>()) { + auto &E1List = static_cast<ErrorList &>(*E1.getPtr()); + if (E2.isA<ErrorList>()) { + auto E2Payload = E2.takePayload(); + auto &E2List = static_cast<ErrorList &>(*E2Payload); + for (auto &Payload : E2List.Payloads) + E1List.Payloads.push_back(std::move(Payload)); + } else + E1List.Payloads.push_back(E2.takePayload()); + + return E1; + } + if (E2.isA<ErrorList>()) { + auto &E2List = static_cast<ErrorList &>(*E2.getPtr()); + E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload()); + return E2; + } + return Error(std::unique_ptr<ErrorList>( + new ErrorList(E1.takePayload(), E2.takePayload()))); + } + + std::vector<std::unique_ptr<ErrorInfoBase>> Payloads; +}; + +/// Concatenate errors. The resulting Error is unchecked, and contains the +/// ErrorInfo(s), if any, contained in E1, followed by the +/// ErrorInfo(s), if any, contained in E2. +inline Error joinErrors(Error E1, Error E2) { + return ErrorList::join(std::move(E1), std::move(E2)); +} + +/// Helper for testing applicability of, and applying, handlers for +/// ErrorInfo types. +template <typename HandlerT> +class ErrorHandlerTraits + : public ErrorHandlerTraits<decltype( + &std::remove_reference<HandlerT>::type::operator())> {}; + +// Specialization functions of the form 'Error (const ErrT&)'. +template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + return H(static_cast<ErrT &>(*E)); + } +}; + +// Specialization functions of the form 'void (const ErrT&)'. +template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + H(static_cast<ErrT &>(*E)); + return Error::success(); + } +}; + +/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'. +template <typename ErrT> +class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); + return H(std::move(SubE)); + } +}; + +/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'. +template <typename ErrT> +class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> { +public: + static bool appliesTo(const ErrorInfoBase &E) { + return E.template isA<ErrT>(); + } + + template <typename HandlerT> + static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { + assert(appliesTo(*E) && "Applying incorrect handler"); + std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); + H(std::move(SubE)); + return Error::success(); + } +}; + +// Specialization for member functions of the form 'RetT (const ErrT&)'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(ErrT &)> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(ErrT &) const> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&)'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(const ErrT &)> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +// Specialization for member functions of the form 'RetT (const ErrT&) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const> + : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; + +/// Specialization for member functions of the form +/// 'RetT (std::unique_ptr<ErrT>) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)> + : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; + +/// Specialization for member functions of the form +/// 'RetT (std::unique_ptr<ErrT>) const'. +template <typename C, typename RetT, typename ErrT> +class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const> + : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; + +inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) { + return Error(std::move(Payload)); +} + +template <typename HandlerT, typename... HandlerTs> +Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload, + HandlerT &&Handler, HandlerTs &&... Handlers) { + if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload)) + return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler), + std::move(Payload)); + return handleErrorImpl(std::move(Payload), + std::forward<HandlerTs>(Handlers)...); +} + +/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any +/// unhandled errors (or Errors returned by handlers) are re-concatenated and +/// returned. +/// Because this function returns an error, its result must also be checked +/// or returned. If you intend to handle all errors use handleAllErrors +/// (which returns void, and will abort() on unhandled errors) instead. +template <typename... HandlerTs> +Error handleErrors(Error E, HandlerTs &&... Hs) { + if (!E) + return Error::success(); + + std::unique_ptr<ErrorInfoBase> Payload = E.takePayload(); + + if (Payload->isA<ErrorList>()) { + ErrorList &List = static_cast<ErrorList &>(*Payload); + Error R; + for (auto &P : List.Payloads) + R = ErrorList::join( + std::move(R), + handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...)); + return R; + } + + return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); +} + +/// Behaves the same as handleErrors, except that it requires that all +/// errors be handled by the given handlers. If any unhandled error remains +/// after the handlers have run, abort() will be called. +template <typename... HandlerTs> +void handleAllErrors(Error E, HandlerTs &&... Handlers) { + auto F = handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...); + // Cast 'F' to bool to set the 'Checked' flag if it's a success value: + (void)!F; +} + +/// Check that E is a non-error, then drop it. +inline void handleAllErrors(Error E) { + // Cast 'E' to a bool to set the 'Checked' flag if it's a success value: + (void)!E; +} + +/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner +/// will be printed before the first one is logged. A newline will be printed +/// after each error. +/// +/// This is useful in the base level of your program to allow clean termination +/// (allowing clean deallocation of resources, etc.), while reporting error +/// information to the user. +void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner); + +/// Write all error messages (if any) in E to a string. The newline character +/// is used to separate error messages. +inline std::string toString(Error E) { + SmallVector<std::string, 2> Errors; + handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) { + Errors.push_back(EI.message()); + }); + return join(Errors.begin(), Errors.end(), "\n"); +} + +/// Consume a Error without doing anything. This method should be used +/// only where an error can be considered a reasonable and expected return +/// value. +/// +/// Uses of this method are potentially indicative of design problems: If it's +/// legitimate to do nothing while processing an "error", the error-producer +/// might be more clearly refactored to return an Optional<T>. +inline void consumeError(Error Err) { + handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); +} + +/// Helper for Errors used as out-parameters. +/// +/// This helper is for use with the Error-as-out-parameter idiom, where an error +/// is passed to a function or method by reference, rather than being returned. +/// In such cases it is helpful to set the checked bit on entry to the function +/// so that the error can be written to (unchecked Errors abort on assignment) +/// and clear the checked bit on exit so that clients cannot accidentally forget +/// to check the result. This helper performs these actions automatically using +/// RAII: +/// +/// Result foo(Error &Err) { +/// ErrorAsOutParameter ErrAsOutParam(Err); // 'Checked' flag set +/// // <body of foo> +/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. +/// } +class ErrorAsOutParameter { +public: + ErrorAsOutParameter(Error &Err) : Err(Err) { + // Raise the checked bit if Err is success. + (void)!!Err; + } + ~ErrorAsOutParameter() { + // Clear the checked bit. + if (!Err) + Err = Error::success(); + } + +private: + Error &Err; +}; + +/// Tagged union holding either a T or a Error. +/// +/// This class parallels ErrorOr, but replaces error_code with Error. Since +/// Error cannot be copied, this class replaces getError() with +/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the +/// error class type. +template <class T> class Expected { + template <class OtherT> friend class Expected; + static const bool isRef = std::is_reference<T>::value; + typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap; + + typedef std::unique_ptr<ErrorInfoBase> error_type; + +public: + typedef typename std::conditional<isRef, wrap, T>::type storage_type; + typedef T value_type; + +private: + typedef typename std::remove_reference<T>::type &reference; + typedef const typename std::remove_reference<T>::type &const_reference; + typedef typename std::remove_reference<T>::type *pointer; + typedef const typename std::remove_reference<T>::type *const_pointer; + +public: + /// Create an Expected<T> error value from the given Error. + Expected(Error Err) + : HasError(true) +#ifndef NDEBUG + , + Checked(false) +#endif + { + assert(Err && "Cannot create Expected<T> from Error success value."); + new (getErrorStorage()) Error(std::move(Err)); + } + + /// Create an Expected<T> success value from the given OtherT value, which + /// must be convertible to T. + template <typename OtherT> + Expected(OtherT &&Val, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) + : HasError(false) +#ifndef NDEBUG + , + Checked(false) +#endif + { + new (getStorage()) storage_type(std::forward<OtherT>(Val)); + } + + /// Move construct an Expected<T> value. + Expected(Expected &&Other) { moveConstruct(std::move(Other)); } + + /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT + /// must be convertible to T. + template <class OtherT> + Expected(Expected<OtherT> &&Other, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) { + moveConstruct(std::move(Other)); + } + + /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT + /// isn't convertible to T. + template <class OtherT> + explicit Expected( + Expected<OtherT> &&Other, + typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = + nullptr) { + moveConstruct(std::move(Other)); + } + + /// Move-assign from another Expected<T>. + Expected &operator=(Expected &&Other) { + moveAssign(std::move(Other)); + return *this; + } + + /// Destroy an Expected<T>. + ~Expected() { + assertIsChecked(); + if (!HasError) + getStorage()->~storage_type(); + else + getErrorStorage()->~error_type(); + } + + /// \brief Return false if there is an error. + explicit operator bool() { +#ifndef NDEBUG + Checked = !HasError; +#endif + return !HasError; + } + + /// \brief Returns a reference to the stored T value. + reference get() { + assertIsChecked(); + return *getStorage(); + } + + /// \brief Returns a const reference to the stored T value. + const_reference get() const { + assertIsChecked(); + return const_cast<Expected<T> *>(this)->get(); + } + + /// \brief Check that this Expected<T> is an error of type ErrT. + template <typename ErrT> bool errorIsA() const { + return HasError && getErrorStorage()->template isA<ErrT>(); + } + + /// \brief Take ownership of the stored error. + /// After calling this the Expected<T> is in an indeterminate state that can + /// only be safely destructed. No further calls (beside the destructor) should + /// be made on the Expected<T> vaule. + Error takeError() { +#ifndef NDEBUG + Checked = true; +#endif + return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); + } + + /// \brief Returns a pointer to the stored T value. + pointer operator->() { + assertIsChecked(); + return toPointer(getStorage()); + } + + /// \brief Returns a const pointer to the stored T value. + const_pointer operator->() const { + assertIsChecked(); + return toPointer(getStorage()); + } + + /// \brief Returns a reference to the stored T value. + reference operator*() { + assertIsChecked(); + return *getStorage(); + } + + /// \brief Returns a const reference to the stored T value. + const_reference operator*() const { + assertIsChecked(); + return *getStorage(); + } + +private: + template <class T1> + static bool compareThisIfSameType(const T1 &a, const T1 &b) { + return &a == &b; + } + + template <class T1, class T2> + static bool compareThisIfSameType(const T1 &a, const T2 &b) { + return false; + } + + template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { + HasError = Other.HasError; + +#ifndef NDEBUG + Checked = false; + Other.Checked = true; +#endif + + if (!HasError) + new (getStorage()) storage_type(std::move(*Other.getStorage())); + else + new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); + } + + template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { + assertIsChecked(); + + if (compareThisIfSameType(*this, Other)) + return; + + this->~Expected(); + new (this) Expected(std::move(Other)); + } + + pointer toPointer(pointer Val) { return Val; } + + const_pointer toPointer(const_pointer Val) const { return Val; } + + pointer toPointer(wrap *Val) { return &Val->get(); } + + const_pointer toPointer(const wrap *Val) const { return &Val->get(); } + + storage_type *getStorage() { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<storage_type *>(TStorage.buffer); + } + + const storage_type *getStorage() const { + assert(!HasError && "Cannot get value when an error exists!"); + return reinterpret_cast<const storage_type *>(TStorage.buffer); + } + + error_type *getErrorStorage() { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<error_type *>(ErrorStorage.buffer); + } + + void assertIsChecked() { +#ifndef NDEBUG + if (!Checked) { + dbgs() << "Expected<T> must be checked before access or destruction.\n"; + if (HasError) { + dbgs() << "Unchecked Expected<T> contained error:\n"; + (*getErrorStorage())->log(dbgs()); + } else + dbgs() << "Expected<T> value was in success state. (Note: Expected<T> " + "values in success mode must still be checked prior to being " + "destroyed).\n"; + abort(); + } +#endif + } + + union { + AlignedCharArrayUnion<storage_type> TStorage; + AlignedCharArrayUnion<error_type> ErrorStorage; + }; + bool HasError : 1; +#ifndef NDEBUG + bool Checked : 1; +#endif +}; + +/// This class wraps a std::error_code in a Error. +/// +/// This is useful if you're writing an interface that returns a Error +/// (or Expected) and you want to call code that still returns +/// std::error_codes. +class ECError : public ErrorInfo<ECError> { + friend Error errorCodeToError(std::error_code); +public: + void setErrorCode(std::error_code EC) { this->EC = EC; } + std::error_code convertToErrorCode() const override { return EC; } + void log(raw_ostream &OS) const override { OS << EC.message(); } + + // Used by ErrorInfo::classID. + static char ID; + +protected: + ECError() = default; + ECError(std::error_code EC) : EC(EC) {} + std::error_code EC; +}; + +/// The value returned by this function can be returned from convertToErrorCode +/// for Error values where no sensible translation to std::error_code exists. +/// It should only be used in this situation, and should never be used where a +/// sensible conversion to std::error_code is available, as attempts to convert +/// to/from this error will result in a fatal error. (i.e. it is a programmatic +///error to try to convert such a value). +std::error_code inconvertibleErrorCode(); + +/// Helper for converting an std::error_code to a Error. +Error errorCodeToError(std::error_code EC); + +/// Helper for converting an ECError to a std::error_code. +/// +/// This method requires that Err be Error() or an ECError, otherwise it +/// will trigger a call to abort(). +std::error_code errorToErrorCode(Error Err); + +/// Convert an ErrorOr<T> to an Expected<T>. +template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) { + if (auto EC = EO.getError()) + return errorCodeToError(EC); + return std::move(*EO); +} + +/// Convert an Expected<T> to an ErrorOr<T>. +template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { + if (auto Err = E.takeError()) + return errorToErrorCode(std::move(Err)); + return std::move(*E); +} + +/// This class wraps a string in an Error. +/// +/// StringError is useful in cases where the client is not expected to be able +/// to consume the specific error message programmatically (for example, if the +/// error message is to be presented to the user). +class StringError : public ErrorInfo<StringError> { +public: + static char ID; + StringError(const Twine &S, std::error_code EC); + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; +private: + std::string Msg; + std::error_code EC; +}; + +/// Helper for check-and-exit error handling. +/// +/// For tool use only. NOT FOR USE IN LIBRARY CODE. +/// +class ExitOnError { +public: + /// Create an error on exit helper. + ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1) + : Banner(std::move(Banner)), + GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {} + + /// Set the banner string for any errors caught by operator(). + void setBanner(std::string Banner) { this->Banner = std::move(Banner); } + + /// Set the exit-code mapper function. + void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) { + this->GetExitCode = std::move(GetExitCode); + } + + /// Check Err. If it's in a failure state log the error(s) and exit. + void operator()(Error Err) const { checkError(std::move(Err)); } + + /// Check E. If it's in a success state then return the contained value. If + /// it's in a failure state log the error(s) and exit. + template <typename T> T operator()(Expected<T> &&E) const { + checkError(E.takeError()); + return std::move(*E); + } + + /// Check E. If it's in a success state then return the contained reference. If + /// it's in a failure state log the error(s) and exit. + template <typename T> T& operator()(Expected<T&> &&E) const { + checkError(E.takeError()); + return *E; + } + +private: + void checkError(Error Err) const { + if (Err) { + int ExitCode = GetExitCode(Err); + logAllUnhandledErrors(std::move(Err), errs(), Banner); + exit(ExitCode); + } + } + + std::string Banner; + std::function<int(const Error &)> GetExitCode; +}; + +/// Report a serious error, calling any installed error handler. See +/// ErrorHandling.h. +LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, + bool gen_crash_diag = true); + +} // namespace llvm + +#endif // LLVM_SUPPORT_ERROR_H diff --git a/include/llvm/Support/ErrorHandling.h b/include/llvm/Support/ErrorHandling.h index 32f05e0e9610..7c1edd801571 100644 --- a/include/llvm/Support/ErrorHandling.h +++ b/include/llvm/Support/ErrorHandling.h @@ -15,11 +15,11 @@ #ifndef LLVM_SUPPORT_ERRORHANDLING_H #define LLVM_SUPPORT_ERRORHANDLING_H -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include <string> namespace llvm { +class StringRef; class Twine; /// An error handler callback. diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h index ca6ede73e8df..877f4063cd23 100644 --- a/include/llvm/Support/ErrorOr.h +++ b/include/llvm/Support/ErrorOr.h @@ -23,20 +23,6 @@ #include <type_traits> namespace llvm { -template<class T, class V> -typename std::enable_if< std::is_constructible<T, V>::value - , typename std::remove_reference<V>::type>::type && - moveIfMoveConstructible(V &Val) { - return std::move(Val); -} - -template<class T, class V> -typename std::enable_if< !std::is_constructible<T, V>::value - , typename std::remove_reference<V>::type>::type & -moveIfMoveConstructible(V &Val) { - return Val; -} - /// \brief Stores a reference that can be changed. template <typename T> class ReferenceStorage { @@ -72,7 +58,7 @@ public: /// unary * and -> operators provide pointer like access to the value. Accessing /// the value when there is an error has undefined behavior. /// -/// When T is a reference type the behaivor is slightly different. The reference +/// When T is a reference type the behavior is slightly different. The reference /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and /// there is special handling to make operator -> work as if T was not a /// reference. @@ -98,7 +84,7 @@ public: ErrorOr(E ErrorCode, typename std::enable_if<std::is_error_code_enum<E>::value || std::is_error_condition_enum<E>::value, - void *>::type = 0) + void *>::type = nullptr) : HasError(true) { new (getErrorStorage()) std::error_code(make_error_code(ErrorCode)); } @@ -107,8 +93,12 @@ public: new (getErrorStorage()) std::error_code(EC); } - ErrorOr(T Val) : HasError(false) { - new (getStorage()) storage_type(moveIfMoveConstructible<storage_type>(Val)); + template <class OtherT> + ErrorOr(OtherT &&Val, + typename std::enable_if<std::is_convertible<OtherT, T>::value>::type + * = nullptr) + : HasError(false) { + new (getStorage()) storage_type(std::forward<OtherT>(Val)); } ErrorOr(const ErrorOr &Other) { @@ -278,7 +268,6 @@ private: return const_cast<ErrorOr<T> *>(this)->getErrorStorage(); } - union { AlignedCharArrayUnion<storage_type> TStorage; AlignedCharArrayUnion<std::error_code> ErrorStorage; @@ -295,4 +284,4 @@ operator==(const ErrorOr<T> &Err, E Code) { } } // end namespace llvm -#endif +#endif // LLVM_SUPPORT_ERROROR_H diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index 4733ddb77575..42a6180e0eb3 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -29,12 +29,15 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/TimeValue.h" +#include <cassert> +#include <cstdint> #include <ctime> -#include <iterator> #include <stack> #include <string> #include <system_error> @@ -140,11 +143,14 @@ class file_status #if defined(LLVM_ON_UNIX) dev_t fs_st_dev; ino_t fs_st_ino; + time_t fs_st_atime; time_t fs_st_mtime; uid_t fs_st_uid; gid_t fs_st_gid; off_t fs_st_size; #elif defined (LLVM_ON_WIN32) + uint32_t LastAccessedTimeHigh; + uint32_t LastAccessedTimeLow; uint32_t LastWriteTimeHigh; uint32_t LastWriteTimeLow; uint32_t VolumeSerialNumber; @@ -159,43 +165,51 @@ class file_status public: #if defined(LLVM_ON_UNIX) - file_status() : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0), + file_status() + : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0), fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(file_type::status_error), Perms(perms_not_known) {} - file_status(file_type Type) : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0), + file_status(file_type Type) + : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0), fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type), Perms(perms_not_known) {} - file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t MTime, - uid_t UID, gid_t GID, off_t Size) - : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_mtime(MTime), fs_st_uid(UID), - fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {} + file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime, + time_t MTime, uid_t UID, gid_t GID, off_t Size) + : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_atime(ATime), fs_st_mtime(MTime), + fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type), + Perms(Perms) {} #elif defined(LLVM_ON_WIN32) - file_status() : LastWriteTimeHigh(0), LastWriteTimeLow(0), - VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0), - FileIndexHigh(0), FileIndexLow(0), Type(file_type::status_error), - Perms(perms_not_known) {} + file_status() + : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0), + LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0), + FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), + Type(file_type::status_error), Perms(perms_not_known) {} - file_status(file_type Type) : LastWriteTimeHigh(0), LastWriteTimeLow(0), - VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0), - FileIndexHigh(0), FileIndexLow(0), Type(Type), + file_status(file_type Type) + : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0), + LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0), + FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type), Perms(perms_not_known) {} - file_status(file_type Type, uint32_t LastWriteTimeHigh, - uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, - uint32_t FileSizeHigh, uint32_t FileSizeLow, - uint32_t FileIndexHigh, uint32_t FileIndexLow) - : LastWriteTimeHigh(LastWriteTimeHigh), - LastWriteTimeLow(LastWriteTimeLow), - VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), - FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), - FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} + file_status(file_type Type, uint32_t LastAccessTimeHigh, + uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh, + uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, + uint32_t FileSizeHigh, uint32_t FileSizeLow, + uint32_t FileIndexHigh, uint32_t FileIndexLow) + : LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow), + LastWriteTimeHigh(LastWriteTimeHigh), + LastWriteTimeLow(LastWriteTimeLow), + VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), + FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), + FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} #endif // getters file_type type() const { return Type; } perms permissions() const { return Perms; } + TimeValue getLastAccessedTime() const; TimeValue getLastModificationTime() const; UniqueID getUniqueID() const; @@ -251,7 +265,7 @@ struct file_magic { }; bool is_object() const { - return V == unknown ? false : true; + return V != unknown; } file_magic() : V(unknown) {} @@ -590,6 +604,12 @@ std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, std::error_code createUniqueDirectory(const Twine &Prefix, SmallVectorImpl<char> &ResultPath); +/// @brief Fetch a path to an open file, as specified by a file descriptor +/// +/// @param FD File descriptor to a currently open file +/// @param ResultPath The buffer into which to write the path +std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath); + enum OpenFlags : unsigned { F_None = 0, @@ -622,7 +642,8 @@ inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) { std::error_code openFileForWrite(const Twine &Name, int &ResultFD, OpenFlags Flags, unsigned Mode = 0666); -std::error_code openFileForRead(const Twine &Name, int &ResultFD); +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl<char> *RealPath = nullptr); /// @brief Identify the type of a binary file based on how magical it is. file_magic identify_magic(StringRef magic); @@ -637,6 +658,17 @@ std::error_code identify_magic(const Twine &path, file_magic &result); std::error_code getUniqueID(const Twine Path, UniqueID &Result); +/// @brief Get disk space usage information. +/// +/// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug. +/// Note: Windows reports results according to the quota allocated to the user. +/// +/// @param Path Input path. +/// @returns a space_info structure filled with the capacity, free, and +/// available space on the device \a Path is on. A platform specific error_code +/// is returned on error. +ErrorOr<space_info> disk_space(const Twine &Path); + /// This class represents a memory mapped file. It is based on /// boost::iostreams::mapped_file. class mapped_file_region { @@ -739,7 +771,7 @@ namespace detail { intptr_t IterationHandle; directory_entry CurrentEntry; }; -} +} // end namespace detail /// directory_iterator - Iterates through the entries in path. There is no /// operator++ because we need an error_code. If it's really needed we can make @@ -801,7 +833,7 @@ namespace detail { uint16_t Level; bool HasNoPushRequest; }; -} +} // end namespace detail /// recursive_directory_iterator - Same as directory_iterator except for it /// recurses down into child directories. @@ -900,4 +932,4 @@ public: } // end namespace sys } // end namespace llvm -#endif +#endif // LLVM_SUPPORT_FILESYSTEM_H diff --git a/include/llvm/Support/Format.h b/include/llvm/Support/Format.h index f0b437a0cbed..d5c301cd7e2b 100644 --- a/include/llvm/Support/Format.h +++ b/include/llvm/Support/Format.h @@ -170,13 +170,13 @@ inline FormattedNumber format_hex(uint64_t N, unsigned Width, /// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not /// prepend '0x' to the outputted string. If number will not fit in width, /// full number is still printed. Examples: -/// OS << format_hex_no_prefix(255, 4) => ff -/// OS << format_hex_no_prefix(255, 4, true) => FF -/// OS << format_hex_no_prefix(255, 6) => 00ff /// OS << format_hex_no_prefix(255, 2) => ff +/// OS << format_hex_no_prefix(255, 2, true) => FF +/// OS << format_hex_no_prefix(255, 4) => 00ff +/// OS << format_hex_no_prefix(255, 1) => ff inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, bool Upper = false) { - assert(Width <= 18 && "hex width must be <= 18"); + assert(Width <= 16 && "hex width must be <= 16"); return FormattedNumber(N, 0, Width, true, Upper, false); } diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index 8bae582d18c7..77b5ba7e3e97 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -109,13 +109,13 @@ public: return true; SmallPtrSet<const NodeT *, 4> OtherChildren; - for (const_iterator I = Other->begin(), E = Other->end(); I != E; ++I) { - const NodeT *Nd = (*I)->getBlock(); + for (const DomTreeNodeBase *I : *Other) { + const NodeT *Nd = I->getBlock(); OtherChildren.insert(Nd); } - for (const_iterator I = begin(), E = end(); I != E; ++I) { - const NodeT *N = (*I)->getBlock(); + for (const DomTreeNodeBase *I : *this) { + const NodeT *N = I->getBlock(); if (OtherChildren.count(N) == 0) return true; } @@ -138,8 +138,9 @@ public: } } - /// getDFSNumIn/getDFSNumOut - These are an internal implementation detail, do - /// not call them. + /// getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes + /// in the dominator tree. They are only guaranteed valid if + /// updateDFSNumbers() has been called. unsigned getDFSNumIn() const { return DFSNumIn; } unsigned getDFSNumOut() const { return DFSNumOut; } @@ -348,17 +349,14 @@ public: if (DomTreeNodes.size() != OtherDomTreeNodes.size()) return true; - for (typename DomTreeNodeMapType::const_iterator - I = this->DomTreeNodes.begin(), - E = this->DomTreeNodes.end(); - I != E; ++I) { - NodeT *BB = I->first; + for (const auto &DomTreeNode : this->DomTreeNodes) { + NodeT *BB = DomTreeNode.first; typename DomTreeNodeMapType::const_iterator OI = OtherDomTreeNodes.find(BB); if (OI == OtherDomTreeNodes.end()) return true; - DomTreeNodeBase<NodeT> &MyNd = *I->second; + DomTreeNodeBase<NodeT> &MyNd = *DomTreeNode.second; DomTreeNodeBase<NodeT> &OtherNd = *OI->second; if (MyNd.compare(&OtherNd)) @@ -453,7 +451,7 @@ public: // Compare the result of the tree walk and the dfs numbers, if expensive // checks are enabled. -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS assert((!DFSInfoValid || (dominatedBySlowTreeWalk(A, B) == B->DominatedBy(A))) && "Tree walk disagrees with dfs numbers!"); diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h index 8f4bf3c1ba56..8114f9bf846b 100644 --- a/include/llvm/Support/Host.h +++ b/include/llvm/Support/Host.h @@ -16,7 +16,7 @@ #include "llvm/ADT/StringMap.h" -#if defined(__linux__) || defined(__GNU__) +#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) #include <endian.h> #else #if !defined(BYTE_ORDER) && !defined(LLVM_ON_WIN32) diff --git a/include/llvm/Support/JamCRC.h b/include/llvm/Support/JamCRC.h index 20c28a5f8e45..5268bbd9ba1e 100644 --- a/include/llvm/Support/JamCRC.h +++ b/include/llvm/Support/JamCRC.h @@ -27,10 +27,11 @@ #ifndef LLVM_SUPPORT_JAMCRC_H #define LLVM_SUPPORT_JAMCRC_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataTypes.h" namespace llvm { +template <typename T> class ArrayRef; + class JamCRC { public: JamCRC(uint32_t Init = 0xFFFFFFFFU) : CRC(Init) {} diff --git a/include/llvm/Support/Locale.h b/include/llvm/Support/Locale.h index b384d58baea7..f7a2c036ed5e 100644 --- a/include/llvm/Support/Locale.h +++ b/include/llvm/Support/Locale.h @@ -1,9 +1,9 @@ #ifndef LLVM_SUPPORT_LOCALE_H #define LLVM_SUPPORT_LOCALE_H -#include "llvm/ADT/StringRef.h" - namespace llvm { +class StringRef; + namespace sys { namespace locale { diff --git a/include/llvm/Support/LockFileManager.h b/include/llvm/Support/LockFileManager.h index 8e88d4279bd8..13d252425b93 100644 --- a/include/llvm/Support/LockFileManager.h +++ b/include/llvm/Support/LockFileManager.h @@ -11,11 +11,12 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" #include <system_error> #include <utility> // for std::pair namespace llvm { +class StringRef; + /// \brief Class that manages the creation of a lock file to aid /// implicit coordination between different processes. /// @@ -56,6 +57,7 @@ private: Optional<std::pair<std::string, int> > Owner; Optional<std::error_code> Error; + std::string ErrorDiagMsg; LockFileManager(const LockFileManager &) = delete; LockFileManager &operator=(const LockFileManager &) = delete; @@ -81,6 +83,15 @@ public: /// \brief Remove the lock file. This may delete a different lock file than /// the one previously read if there is a race. std::error_code unsafeRemoveLockFile(); + + /// \brief Get error message, or "" if there is no error. + std::string getErrorMessage() const; + + /// \brief Set error and error message + void setError(std::error_code &EC, StringRef ErrorMsg = "") { + Error = EC; + ErrorDiagMsg = ErrorMsg.str(); + } }; } // end namespace llvm diff --git a/include/llvm/Support/MD5.h b/include/llvm/Support/MD5.h index f6e1e92c9fa8..42d8ca8a1ebb 100644 --- a/include/llvm/Support/MD5.h +++ b/include/llvm/Support/MD5.h @@ -28,11 +28,12 @@ #ifndef LLVM_SUPPORT_MD5_H #define LLVM_SUPPORT_MD5_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" namespace llvm { +template <typename T> class ArrayRef; class MD5 { // Any 32-bit or wider unsigned integer data type will do. @@ -65,6 +66,18 @@ private: const uint8_t *body(ArrayRef<uint8_t> Data); }; +/// Helper to compute and return lower 64 bits of the given string's MD5 hash. +inline uint64_t MD5Hash(StringRef Str) { + MD5 Hash; + Hash.update(Str); + llvm::MD5::MD5Result Result; + Hash.final(Result); + // Return the least significant 8 bytes. Our MD5 implementation returns the + // result in little endian, so we may need to swap bytes. + using namespace llvm::support; + return endian::read<uint64_t, little, unaligned>(Result); +} + } #endif diff --git a/include/llvm/Support/MachO.def b/include/llvm/Support/MachO.def new file mode 100644 index 000000000000..9ca6440dd82b --- /dev/null +++ b/include/llvm/Support/MachO.def @@ -0,0 +1,106 @@ +//,,,-- llvm/Support/MachO.def - The MachO file definitions -----*- C++ -*-,,,// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//,,,----------------------------------------------------------------------,,,// +// +// Definitions for MachO files +// +//,,,----------------------------------------------------------------------,,,// + +#ifdef HANDLE_LOAD_COMMAND + +HANDLE_LOAD_COMMAND(LC_SEGMENT, 0x00000001u, segment_command) +HANDLE_LOAD_COMMAND(LC_SYMTAB, 0x00000002u, symtab_command) +HANDLE_LOAD_COMMAND(LC_SYMSEG, 0x00000003u, symseg_command) +HANDLE_LOAD_COMMAND(LC_THREAD, 0x00000004u, thread_command) +HANDLE_LOAD_COMMAND(LC_UNIXTHREAD, 0x00000005u, thread_command) +HANDLE_LOAD_COMMAND(LC_LOADFVMLIB, 0x00000006u, fvmlib_command) +HANDLE_LOAD_COMMAND(LC_IDFVMLIB, 0x00000007u, fvmlib_command) +HANDLE_LOAD_COMMAND(LC_IDENT, 0x00000008u, ident_command) +HANDLE_LOAD_COMMAND(LC_FVMFILE, 0x00000009u, fvmfile_command) +HANDLE_LOAD_COMMAND(LC_PREPAGE, 0x0000000Au, load_command) +HANDLE_LOAD_COMMAND(LC_DYSYMTAB, 0x0000000Bu, dysymtab_command) +HANDLE_LOAD_COMMAND(LC_LOAD_DYLIB, 0x0000000Cu, dylib_command) +HANDLE_LOAD_COMMAND(LC_ID_DYLIB, 0x0000000Du, dylib_command) +HANDLE_LOAD_COMMAND(LC_LOAD_DYLINKER, 0x0000000Eu, dylinker_command) +HANDLE_LOAD_COMMAND(LC_ID_DYLINKER, 0x0000000Fu, dylinker_command) +HANDLE_LOAD_COMMAND(LC_PREBOUND_DYLIB, 0x00000010u, prebound_dylib_command) +HANDLE_LOAD_COMMAND(LC_ROUTINES, 0x00000011u, routines_command) +HANDLE_LOAD_COMMAND(LC_SUB_FRAMEWORK, 0x00000012u, sub_framework_command) +HANDLE_LOAD_COMMAND(LC_SUB_UMBRELLA, 0x00000013u, sub_umbrella_command) +HANDLE_LOAD_COMMAND(LC_SUB_CLIENT, 0x00000014u, sub_client_command) +HANDLE_LOAD_COMMAND(LC_SUB_LIBRARY, 0x00000015u, sub_library_command) +HANDLE_LOAD_COMMAND(LC_TWOLEVEL_HINTS, 0x00000016u, twolevel_hints_command) +HANDLE_LOAD_COMMAND(LC_PREBIND_CKSUM, 0x00000017u, prebind_cksum_command) +HANDLE_LOAD_COMMAND(LC_LOAD_WEAK_DYLIB, 0x80000018u, dylib_command) +HANDLE_LOAD_COMMAND(LC_SEGMENT_64, 0x00000019u, segment_command_64) +HANDLE_LOAD_COMMAND(LC_ROUTINES_64, 0x0000001Au, routines_command_64) +HANDLE_LOAD_COMMAND(LC_UUID, 0x0000001Bu, uuid_command) +HANDLE_LOAD_COMMAND(LC_RPATH, 0x8000001Cu, rpath_command) +HANDLE_LOAD_COMMAND(LC_CODE_SIGNATURE, 0x0000001Du, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_SEGMENT_SPLIT_INFO, 0x0000001Eu, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_REEXPORT_DYLIB, 0x8000001Fu, dylib_command) +HANDLE_LOAD_COMMAND(LC_LAZY_LOAD_DYLIB, 0x00000020u, dylib_command) +HANDLE_LOAD_COMMAND(LC_ENCRYPTION_INFO, 0x00000021u, encryption_info_command) +HANDLE_LOAD_COMMAND(LC_DYLD_INFO, 0x00000022u, dyld_info_command) +HANDLE_LOAD_COMMAND(LC_DYLD_INFO_ONLY, 0x80000022u, dyld_info_command) +HANDLE_LOAD_COMMAND(LC_LOAD_UPWARD_DYLIB, 0x80000023u, dylib_command) +HANDLE_LOAD_COMMAND(LC_VERSION_MIN_MACOSX, 0x00000024u, version_min_command) +HANDLE_LOAD_COMMAND(LC_VERSION_MIN_IPHONEOS, 0x00000025u, version_min_command) +HANDLE_LOAD_COMMAND(LC_FUNCTION_STARTS, 0x00000026u, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_DYLD_ENVIRONMENT, 0x00000027u, dylinker_command) +HANDLE_LOAD_COMMAND(LC_MAIN, 0x80000028u, entry_point_command) +HANDLE_LOAD_COMMAND(LC_DATA_IN_CODE, 0x00000029u, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_SOURCE_VERSION, 0x0000002Au, source_version_command) +HANDLE_LOAD_COMMAND(LC_DYLIB_CODE_SIGN_DRS, 0x0000002Bu, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_ENCRYPTION_INFO_64, 0x0000002Cu, + encryption_info_command_64) +HANDLE_LOAD_COMMAND(LC_LINKER_OPTION, 0x0000002Du, linker_option_command) +HANDLE_LOAD_COMMAND(LC_LINKER_OPTIMIZATION_HINT, 0x0000002Eu, linkedit_data_command) +HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command) +HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command) + +#endif + +#ifdef LOAD_COMMAND_STRUCT + +LOAD_COMMAND_STRUCT(dyld_info_command) +LOAD_COMMAND_STRUCT(dylib_command) +LOAD_COMMAND_STRUCT(dylinker_command) +LOAD_COMMAND_STRUCT(dysymtab_command) +LOAD_COMMAND_STRUCT(encryption_info_command) +LOAD_COMMAND_STRUCT(encryption_info_command_64) +LOAD_COMMAND_STRUCT(entry_point_command) +LOAD_COMMAND_STRUCT(fvmfile_command) +LOAD_COMMAND_STRUCT(fvmlib_command) +LOAD_COMMAND_STRUCT(ident_command) +LOAD_COMMAND_STRUCT(linkedit_data_command) +LOAD_COMMAND_STRUCT(linker_option_command) +LOAD_COMMAND_STRUCT(load_command) +LOAD_COMMAND_STRUCT(prebind_cksum_command) +LOAD_COMMAND_STRUCT(prebound_dylib_command) +LOAD_COMMAND_STRUCT(routines_command) +LOAD_COMMAND_STRUCT(routines_command_64) +LOAD_COMMAND_STRUCT(rpath_command) +LOAD_COMMAND_STRUCT(segment_command) +LOAD_COMMAND_STRUCT(segment_command_64) +LOAD_COMMAND_STRUCT(source_version_command) +LOAD_COMMAND_STRUCT(sub_client_command) +LOAD_COMMAND_STRUCT(sub_framework_command) +LOAD_COMMAND_STRUCT(sub_library_command) +LOAD_COMMAND_STRUCT(sub_umbrella_command) +LOAD_COMMAND_STRUCT(symseg_command) +LOAD_COMMAND_STRUCT(symtab_command) +LOAD_COMMAND_STRUCT(thread_command) +LOAD_COMMAND_STRUCT(twolevel_hints_command) +LOAD_COMMAND_STRUCT(uuid_command) +LOAD_COMMAND_STRUCT(version_min_command) + +#endif + +#undef HANDLE_LOAD_COMMAND +#undef LOAD_COMMAND_STRUCT diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 54b8745de1c1..9a03722d250f 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -29,7 +29,9 @@ namespace llvm { MH_MAGIC_64 = 0xFEEDFACFu, MH_CIGAM_64 = 0xCFFAEDFEu, FAT_MAGIC = 0xCAFEBABEu, - FAT_CIGAM = 0xBEBAFECAu + FAT_CIGAM = 0xBEBAFECAu, + FAT_MAGIC_64 = 0xCAFEBABFu, + FAT_CIGAM_64 = 0xBFBAFECAu }; enum HeaderFileType { @@ -84,59 +86,15 @@ namespace llvm { LC_REQ_DYLD = 0x80000000u }; +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + LCName = LCValue, + enum LoadCommandType : uint32_t { - // Constants for the "cmd" field in llvm::MachO::load_command - LC_SEGMENT = 0x00000001u, - LC_SYMTAB = 0x00000002u, - LC_SYMSEG = 0x00000003u, - LC_THREAD = 0x00000004u, - LC_UNIXTHREAD = 0x00000005u, - LC_LOADFVMLIB = 0x00000006u, - LC_IDFVMLIB = 0x00000007u, - LC_IDENT = 0x00000008u, - LC_FVMFILE = 0x00000009u, - LC_PREPAGE = 0x0000000Au, - LC_DYSYMTAB = 0x0000000Bu, - LC_LOAD_DYLIB = 0x0000000Cu, - LC_ID_DYLIB = 0x0000000Du, - LC_LOAD_DYLINKER = 0x0000000Eu, - LC_ID_DYLINKER = 0x0000000Fu, - LC_PREBOUND_DYLIB = 0x00000010u, - LC_ROUTINES = 0x00000011u, - LC_SUB_FRAMEWORK = 0x00000012u, - LC_SUB_UMBRELLA = 0x00000013u, - LC_SUB_CLIENT = 0x00000014u, - LC_SUB_LIBRARY = 0x00000015u, - LC_TWOLEVEL_HINTS = 0x00000016u, - LC_PREBIND_CKSUM = 0x00000017u, - LC_LOAD_WEAK_DYLIB = 0x80000018u, - LC_SEGMENT_64 = 0x00000019u, - LC_ROUTINES_64 = 0x0000001Au, - LC_UUID = 0x0000001Bu, - LC_RPATH = 0x8000001Cu, - LC_CODE_SIGNATURE = 0x0000001Du, - LC_SEGMENT_SPLIT_INFO = 0x0000001Eu, - LC_REEXPORT_DYLIB = 0x8000001Fu, - LC_LAZY_LOAD_DYLIB = 0x00000020u, - LC_ENCRYPTION_INFO = 0x00000021u, - LC_DYLD_INFO = 0x00000022u, - LC_DYLD_INFO_ONLY = 0x80000022u, - LC_LOAD_UPWARD_DYLIB = 0x80000023u, - LC_VERSION_MIN_MACOSX = 0x00000024u, - LC_VERSION_MIN_IPHONEOS = 0x00000025u, - LC_FUNCTION_STARTS = 0x00000026u, - LC_DYLD_ENVIRONMENT = 0x00000027u, - LC_MAIN = 0x80000028u, - LC_DATA_IN_CODE = 0x00000029u, - LC_SOURCE_VERSION = 0x0000002Au, - LC_DYLIB_CODE_SIGN_DRS = 0x0000002Bu, - LC_ENCRYPTION_INFO_64 = 0x0000002Cu, - LC_LINKER_OPTION = 0x0000002Du, - LC_LINKER_OPTIMIZATION_HINT = 0x0000002Eu, - LC_VERSION_MIN_TVOS = 0x0000002Fu, - LC_VERSION_MIN_WATCHOS = 0x00000030u, + #include "llvm/Support/MachO.def" }; +#undef HANDLE_LOAD_COMMAND + enum : uint32_t { // Constant bits for the "flags" field in llvm::MachO::segment_command SG_HIGHVM = 0x1u, @@ -935,6 +893,15 @@ namespace llvm { uint32_t align; }; + struct fat_arch_64 { + uint32_t cputype; + uint32_t cpusubtype; + uint64_t offset; + uint64_t size; + uint32_t align; + uint32_t reserved; + }; + // Structs from <mach-o/reloc.h> struct relocation_info { int32_t r_address; @@ -993,6 +960,28 @@ namespace llvm { // Byte order swapping functions for MachO structs + inline void swapStruct(fat_header &mh) { + sys::swapByteOrder(mh.magic); + sys::swapByteOrder(mh.nfat_arch); + } + + inline void swapStruct(fat_arch &mh) { + sys::swapByteOrder(mh.cputype); + sys::swapByteOrder(mh.cpusubtype); + sys::swapByteOrder(mh.offset); + sys::swapByteOrder(mh.size); + sys::swapByteOrder(mh.align); + } + + inline void swapStruct(fat_arch_64 &mh) { + sys::swapByteOrder(mh.cputype); + sys::swapByteOrder(mh.cpusubtype); + sys::swapByteOrder(mh.offset); + sys::swapByteOrder(mh.size); + sys::swapByteOrder(mh.align); + sys::swapByteOrder(mh.reserved); + } + inline void swapStruct(mach_header &mh) { sys::swapByteOrder(mh.magic); sys::swapByteOrder(mh.cputype); @@ -1279,6 +1268,58 @@ namespace llvm { sys::swapByteOrder(C); } + inline void swapStruct(prebind_cksum_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.cksum); + } + + inline void swapStruct(twolevel_hints_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.offset); + sys::swapByteOrder(C.nhints); + } + + inline void swapStruct(prebound_dylib_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.name); + sys::swapByteOrder(C.nmodules); + sys::swapByteOrder(C.linked_modules); + } + + inline void swapStruct(fvmfile_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.name); + sys::swapByteOrder(C.header_addr); + } + + inline void swapStruct(symseg_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.offset); + sys::swapByteOrder(C.size); + } + + inline void swapStruct(ident_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + } + + inline void swapStruct(fvmlib &C) { + sys::swapByteOrder(C.name); + sys::swapByteOrder(C.minor_version); + sys::swapByteOrder(C.header_addr); + } + + inline void swapStruct(fvmlib_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + swapStruct(C.fvmlib); + } + // Get/Set functions from <mach-o/nlist.h> static inline uint16_t GET_LIBRARY_ORDINAL(uint16_t n_desc) { @@ -1669,6 +1710,13 @@ namespace llvm { const uint32_t x86_EXCEPTION_STATE_COUNT = sizeof(x86_exception_state_t) / sizeof(uint32_t); + // Define a union of all load command structs + #define LOAD_COMMAND_STRUCT(LCStruct) LCStruct LCStruct##_data; + + union macho_load_command { + #include "llvm/Support/MachO.def" + }; + } // end namespace MachO } // end namespace llvm diff --git a/include/llvm/Support/ManagedStatic.h b/include/llvm/Support/ManagedStatic.h index 2e131e47177d..ec8154b828e5 100644 --- a/include/llvm/Support/ManagedStatic.h +++ b/include/llvm/Support/ManagedStatic.h @@ -14,25 +14,26 @@ #ifndef LLVM_SUPPORT_MANAGEDSTATIC_H #define LLVM_SUPPORT_MANAGEDSTATIC_H -#include "llvm/Support/Atomic.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Threading.h" +#include <atomic> +#include <cstddef> namespace llvm { /// object_creator - Helper method for ManagedStatic. template<class C> -void* object_creator() { +LLVM_LIBRARY_VISIBILITY void* object_creator() { return new C(); } /// object_deleter - Helper method for ManagedStatic. /// -template<typename T> struct object_deleter { - static void call(void * Ptr) { delete (T*)Ptr; } +template <typename T> struct LLVM_LIBRARY_VISIBILITY object_deleter { + static void call(void *Ptr) { delete (T *)Ptr; } }; -template<typename T, size_t N> struct object_deleter<T[N]> { - static void call(void * Ptr) { delete[] (T*)Ptr; } +template <typename T, size_t N> +struct LLVM_LIBRARY_VISIBILITY object_deleter<T[N]> { + static void call(void *Ptr) { delete[](T *)Ptr; } }; /// ManagedStaticBase - Common base class for ManagedStatic instances. @@ -40,7 +41,7 @@ class ManagedStaticBase { protected: // This should only be used as a static variable, which guarantees that this // will be zero initialized. - mutable void *Ptr; + mutable std::atomic<void *> Ptr; mutable void (*DeleterFn)(void*); mutable const ManagedStaticBase *Next; @@ -60,40 +61,26 @@ public: template<class C> class ManagedStatic : public ManagedStaticBase { public: - // Accessors. C &operator*() { - void* tmp = Ptr; - if (llvm_is_multithreaded()) sys::MemoryFence(); - if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - TsanHappensAfter(this); + void *Tmp = Ptr.load(std::memory_order_acquire); + if (!Tmp) + RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - return *static_cast<C*>(Ptr); + return *static_cast<C *>(Ptr.load(std::memory_order_relaxed)); } - C *operator->() { - void* tmp = Ptr; - if (llvm_is_multithreaded()) sys::MemoryFence(); - if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - TsanHappensAfter(this); - return static_cast<C*>(Ptr); - } + C *operator->() { return &**this; } + const C &operator*() const { - void* tmp = Ptr; - if (llvm_is_multithreaded()) sys::MemoryFence(); - if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - TsanHappensAfter(this); + void *Tmp = Ptr.load(std::memory_order_acquire); + if (!Tmp) + RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - return *static_cast<C*>(Ptr); + return *static_cast<C *>(Ptr.load(std::memory_order_relaxed)); } - const C *operator->() const { - void* tmp = Ptr; - if (llvm_is_multithreaded()) sys::MemoryFence(); - if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call); - TsanHappensAfter(this); - return static_cast<C*>(Ptr); - } + const C *operator->() const { return &**this; } }; /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 408ae3c339a2..5c816ac9df92 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -16,9 +16,11 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/SwapByteOrder.h" +#include <algorithm> #include <cassert> #include <cstring> #include <type_traits> +#include <limits> #ifdef _MSC_VER #include <intrin.h> @@ -281,14 +283,19 @@ inline bool isInt<32>(int64_t x) { /// left by S. template<unsigned N, unsigned S> inline bool isShiftedInt(int64_t x) { - return isInt<N+S>(x) && (x % (1<<S) == 0); + static_assert( + N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number."); + static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide."); + return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); } /// isUInt - Checks if an unsigned integer fits into the given bit width. template<unsigned N> inline bool isUInt(uint64_t x) { + static_assert(N > 0, "isUInt<0> doesn't make sense."); return N >= 64 || x < (UINT64_C(1)<<(N)); } + // Template specializations to get better code for common cases. template<> inline bool isUInt<8>(uint64_t x) { @@ -303,23 +310,55 @@ inline bool isUInt<32>(uint64_t x) { return static_cast<uint32_t>(x) == x; } -/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted -/// left by S. +/// Checks if a unsigned integer is an N bit number shifted left by S. template<unsigned N, unsigned S> inline bool isShiftedUInt(uint64_t x) { - return isUInt<N+S>(x) && (x % (1<<S) == 0); + static_assert( + N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)"); + static_assert(N + S <= 64, + "isShiftedUInt<N, S> with N + S > 64 is too wide."); + // Per the two static_asserts above, S must be strictly less than 64. So + // 1 << S is not undefined behavior. + return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); +} + +/// Gets the maximum value for a N-bit unsigned integer. +inline uint64_t maxUIntN(uint64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + // uint64_t(1) << 64 is undefined behavior, so we can't do + // (uint64_t(1) << N) - 1 + // without checking first that N != 64. But this works and doesn't have a + // branch. + return UINT64_MAX >> (64 - N); +} + +/// Gets the minimum value for a N-bit signed integer. +inline int64_t minIntN(int64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + return -(UINT64_C(1)<<(N-1)); +} + +/// Gets the maximum value for a N-bit signed integer. +inline int64_t maxIntN(int64_t N) { + assert(N > 0 && N <= 64 && "integer width out of range"); + + // This relies on two's complement wraparound when N == 64, so we convert to + // int64_t only at the very end to avoid UB. + return (UINT64_C(1) << (N - 1)) - 1; } /// isUIntN - Checks if an unsigned integer fits into the given (dynamic) /// bit width. inline bool isUIntN(unsigned N, uint64_t x) { - return N >= 64 || x < (UINT64_C(1)<<(N)); + return N >= 64 || x <= maxUIntN(N); } /// isIntN - Checks if an signed integer fits into the given (dynamic) /// bit width. inline bool isIntN(unsigned N, int64_t x) { - return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); + return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N)); } /// isMask_32 - This function returns true if the argument is a non-empty @@ -606,57 +645,78 @@ inline uint64_t PowerOf2Floor(uint64_t A) { /// /// Examples: /// \code -/// RoundUpToAlignment(5, 8) = 8 -/// RoundUpToAlignment(17, 8) = 24 -/// RoundUpToAlignment(~0LL, 8) = 0 -/// RoundUpToAlignment(321, 255) = 510 +/// alignTo(5, 8) = 8 +/// alignTo(17, 8) = 24 +/// alignTo(~0LL, 8) = 0 +/// alignTo(321, 255) = 510 /// -/// RoundUpToAlignment(5, 8, 7) = 7 -/// RoundUpToAlignment(17, 8, 1) = 17 -/// RoundUpToAlignment(~0LL, 8, 3) = 3 -/// RoundUpToAlignment(321, 255, 42) = 552 +/// alignTo(5, 8, 7) = 7 +/// alignTo(17, 8, 1) = 17 +/// alignTo(~0LL, 8, 3) = 3 +/// alignTo(321, 255, 42) = 552 /// \endcode -inline uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align, - uint64_t Skew = 0) { +inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { Skew %= Align; return (Value + Align - 1 - Skew) / Align * Align + Skew; } +/// Returns the largest uint64_t less than or equal to \p Value and is +/// \p Skew mod \p Align. \p Align must be non-zero +inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) { + Skew %= Align; + return (Value - Skew) / Align * Align + Skew; +} + /// Returns the offset to the next integer (mod 2**64) that is greater than /// or equal to \p Value and is a multiple of \p Align. \p Align must be /// non-zero. inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) { - return RoundUpToAlignment(Value, Align) - Value; + return alignTo(Value, Align) - Value; } -/// SignExtend32 - Sign extend B-bit number x to 32-bit int. -/// Usage int32_t r = SignExtend32<5>(x); -template <unsigned B> inline int32_t SignExtend32(uint32_t x) { - return int32_t(x << (32 - B)) >> (32 - B); +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires 0 < B <= 32. +template <unsigned B> inline int32_t SignExtend32(uint32_t X) { + static_assert(B > 0, "Bit width can't be 0."); + static_assert(B <= 32, "Bit width out of range."); + return int32_t(X << (32 - B)) >> (32 - B); } -/// \brief Sign extend number in the bottom B bits of X to a 32-bit int. -/// Requires 0 < B <= 32. +/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. +/// Requires 0 < B < 32. inline int32_t SignExtend32(uint32_t X, unsigned B) { + assert(B > 0 && "Bit width can't be 0."); + assert(B <= 32 && "Bit width out of range."); return int32_t(X << (32 - B)) >> (32 - B); } -/// SignExtend64 - Sign extend B-bit number x to 64-bit int. -/// Usage int64_t r = SignExtend64<5>(x); +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires 0 < B < 64. template <unsigned B> inline int64_t SignExtend64(uint64_t x) { + static_assert(B > 0, "Bit width can't be 0."); + static_assert(B <= 64, "Bit width out of range."); return int64_t(x << (64 - B)) >> (64 - B); } -/// \brief Sign extend number in the bottom B bits of X to a 64-bit int. -/// Requires 0 < B <= 64. +/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. +/// Requires 0 < B < 64. inline int64_t SignExtend64(uint64_t X, unsigned B) { + assert(B > 0 && "Bit width can't be 0."); + assert(B <= 64 && "Bit width out of range."); return int64_t(X << (64 - B)) >> (64 - B); } -/// \brief Add two unsigned integers, X and Y, of type T. -/// Clamp the result to the maximum representable value of T on overflow. -/// ResultOverflowed indicates if the result is larger than the maximum -/// representable value of type T. +/// Subtract two unsigned integers, X and Y, of type T and return the absolute +/// value of the result. +template <typename T> +typename std::enable_if<std::is_unsigned<T>::value, T>::type +AbsoluteDifference(T X, T Y) { + return std::max(X, Y) - std::min(X, Y); +} + +/// Add two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. template <typename T> typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) { @@ -671,10 +731,9 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) { return Z; } -/// \brief Multiply two unsigned integers, X and Y, of type T. -/// Clamp the result to the maximum representable value of T on overflow. -/// ResultOverflowed indicates if the result is larger than the maximum -/// representable value of type T. +/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the +/// maximum representable value of T on overflow. ResultOverflowed indicates if +/// the result is larger than the maximum representable value of type T. template <typename T> typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { @@ -717,12 +776,10 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { return Z; } -/// \brief Multiply two unsigned integers, X and Y, and add the unsigned -/// integer, A to the product. Clamp the result to the maximum representable -/// value of T on overflow. ResultOverflowed indicates if the result is larger -/// than the maximum representable value of type T. -/// Note that this is purely a convenience function as there is no distinction -/// where overflow occurred in a 'fused' multiply-add for unsigned numbers. +/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to +/// the product. Clamp the result to the maximum representable value of T on +/// overflow. ResultOverflowed indicates if the result is larger than the +/// maximum representable value of type T. template <typename T> typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { @@ -736,6 +793,7 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { return SaturatingAdd(A, Product, &Overflowed); } +/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. extern const float huge_valf; } // End llvm namespace diff --git a/include/llvm/Support/OnDiskHashTable.h b/include/llvm/Support/OnDiskHashTable.h index ac978d4c242c..c28fcabe78fc 100644 --- a/include/llvm/Support/OnDiskHashTable.h +++ b/include/llvm/Support/OnDiskHashTable.h @@ -152,6 +152,22 @@ public: using namespace llvm::support; endian::Writer<little> LE(Out); + // Now we're done adding entries, resize the bucket list if it's + // significantly too large. (This only happens if the number of + // entries is small and we're within our initial allocation of + // 64 buckets.) We aim for an occupancy ratio in [3/8, 3/4). + // + // As a special case, if there are two or fewer entries, just + // form a single bucket. A linear scan is fine in that case, and + // this is very common in C++ class lookup tables. This also + // guarantees we produce at least one bucket for an empty table. + // + // FIXME: Try computing a perfect hash function at this point. + unsigned TargetNumBuckets = + NumEntries <= 2 ? 1 : NextPowerOf2(NumEntries * 4 / 3); + if (TargetNumBuckets != NumBuckets) + resize(TargetNumBuckets); + // Emit the payload of the table. for (offset_type I = 0; I < NumBuckets; ++I) { Bucket &B = Buckets[I]; @@ -309,7 +325,7 @@ public: Info *InfoObj; public: - iterator() : Data(nullptr), Len(0) {} + iterator() : Key(), Data(nullptr), Len(0), InfoObj(nullptr) {} iterator(const internal_key_type K, const unsigned char *D, offset_type L, Info *InfoObj) : Key(K), Data(D), Len(L), InfoObj(InfoObj) {} diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h index 955cc991d9b7..853f0997571c 100644 --- a/include/llvm/Support/Path.h +++ b/include/llvm/Support/Path.h @@ -16,7 +16,6 @@ #ifndef LLVM_SUPPORT_PATH_H #define LLVM_SUPPORT_PATH_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/DataTypes.h" #include <iterator> @@ -88,6 +87,9 @@ public: reverse_iterator &operator++(); // preincrement bool operator==(const reverse_iterator &RHS) const; bool operator!=(const reverse_iterator &RHS) const { return !(*this == RHS); } + + /// @brief Difference in bytes between this and RHS. + ptrdiff_t operator-(const reverse_iterator &RHS) const; }; /// @brief Get begin iterator over \a path. @@ -140,6 +142,23 @@ void remove_filename(SmallVectorImpl<char> &path); /// prepended. void replace_extension(SmallVectorImpl<char> &path, const Twine &extension); +/// @brief Replace matching path prefix with another path. +/// +/// @code +/// /foo, /old, /new => /foo +/// /old/foo, /old, /new => /new/foo +/// /foo, <empty>, /new => /new/foo +/// /old/foo, /old, <empty> => /foo +/// @endcode +/// +/// @param Path If \a Path starts with \a OldPrefix modify to instead +/// start with \a NewPrefix. +/// @param OldPrefix The path prefix to strip from \a Path. +/// @param NewPrefix The path prefix to replace \a NewPrefix with. +void replace_path_prefix(SmallVectorImpl<char> &Path, + const StringRef &OldPrefix, + const StringRef &NewPrefix); + /// @brief Append to path. /// /// @code diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h index c12d237b2796..96cdaed142c2 100644 --- a/include/llvm/Support/PointerLikeTypeTraits.h +++ b/include/llvm/Support/PointerLikeTypeTraits.h @@ -37,7 +37,8 @@ template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {}; } // Provide PointerLikeTypeTraits for non-cvr pointers. -template <typename T> struct PointerLikeTypeTraits<T *> { +template <typename T> class PointerLikeTypeTraits<T *> { +public: static inline void *getAsVoidPointer(T *P) { return P; } static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); } @@ -46,7 +47,8 @@ template <typename T> struct PointerLikeTypeTraits<T *> { }; }; -template <> struct PointerLikeTypeTraits<void *> { +template <> class PointerLikeTypeTraits<void *> { +public: static inline void *getAsVoidPointer(void *P) { return P; } static inline void *getFromVoidPointer(void *P) { return P; } diff --git a/include/llvm/Support/PrettyStackTrace.h b/include/llvm/Support/PrettyStackTrace.h index 027f9433969d..62e3bbc0ddbc 100644 --- a/include/llvm/Support/PrettyStackTrace.h +++ b/include/llvm/Support/PrettyStackTrace.h @@ -29,9 +29,11 @@ namespace llvm { /// constructed and destructed, they will add their symbolic frames to a /// virtual stack trace. This gets dumped out if the program crashes. class PrettyStackTraceEntry { - const PrettyStackTraceEntry *NextEntry; + friend PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *); + + PrettyStackTraceEntry *NextEntry; PrettyStackTraceEntry(const PrettyStackTraceEntry &) = delete; - void operator=(const PrettyStackTraceEntry&) = delete; + void operator=(const PrettyStackTraceEntry &) = delete; public: PrettyStackTraceEntry(); virtual ~PrettyStackTraceEntry(); @@ -67,7 +69,7 @@ namespace llvm { }; /// Returns the topmost element of the "pretty" stack state. - const void* SavePrettyStackState(); + const void *SavePrettyStackState(); /// Restores the topmost element of the "pretty" stack state to State, which /// should come from a previous call to SavePrettyStackState(). This is @@ -76,7 +78,7 @@ namespace llvm { /// happens after a crash that's been recovered by CrashRecoveryContext /// doesn't have frames on it that were added in code unwound by the /// CrashRecoveryContext. - void RestorePrettyStackState(const void* State); + void RestorePrettyStackState(const void *State); } // end namespace llvm diff --git a/include/llvm/Support/Printable.h b/include/llvm/Support/Printable.h index 5c1b8d5070d4..83b8f0998ae6 100644 --- a/include/llvm/Support/Printable.h +++ b/include/llvm/Support/Printable.h @@ -38,8 +38,8 @@ class raw_ostream; class Printable { public: std::function<void(raw_ostream &OS)> Print; - Printable(const std::function<void(raw_ostream &OS)> Print) - : Print(Print) {} + Printable(std::function<void(raw_ostream &OS)> Print) + : Print(std::move(Print)) {} }; static inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) { diff --git a/include/llvm/Support/Process.h b/include/llvm/Support/Process.h index cfdd06c62f33..06fd0af10aa4 100644 --- a/include/llvm/Support/Process.h +++ b/include/llvm/Support/Process.h @@ -25,7 +25,6 @@ #ifndef LLVM_SUPPORT_PROCESS_H #define LLVM_SUPPORT_PROCESS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/Allocator.h" @@ -34,6 +33,7 @@ #include <system_error> namespace llvm { +template <typename T> class ArrayRef; class StringRef; namespace sys { @@ -69,6 +69,9 @@ public: /// @brief Prevent core file generation. static void PreventCoreFiles(); + /// \brief true if PreventCoreFiles has been called, false otherwise. + static bool AreCoreFilesPrevented(); + // This function returns the environment variable \arg name's value as a UTF-8 // string. \arg Name is assumed to be in UTF-8 encoding too. static Optional<std::string> GetEnv(StringRef name); diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h index 727864df2721..055f016d8243 100644 --- a/include/llvm/Support/Program.h +++ b/include/llvm/Support/Program.h @@ -44,6 +44,8 @@ struct ProcessInfo { #error "ProcessInfo is not defined for this platform!" #endif + enum : ProcessId { InvalidPid = 0 }; + /// The process identifier. ProcessId Pid; @@ -88,7 +90,7 @@ struct ProcessInfo { /// -2 indicates a crash during execution or timeout int ExecuteAndWait( StringRef Program, ///< Path of the program to be executed. It is - /// presumed this is the result of the findProgramByName method. + ///< presumed this is the result of the findProgramByName method. const char **args, ///< A vector of strings that are passed to the ///< program. The first element should be the name of the program. ///< The list *must* be terminated by a null char* entry. diff --git a/include/llvm/Support/RandomNumberGenerator.h b/include/llvm/Support/RandomNumberGenerator.h index 7446558f0c88..f146e350fe62 100644 --- a/include/llvm/Support/RandomNumberGenerator.h +++ b/include/llvm/Support/RandomNumberGenerator.h @@ -16,12 +16,12 @@ #ifndef LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_ #define LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_ -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" // Needed for uint64_t on Windows. #include <random> namespace llvm { +class StringRef; /// A random number generator. /// diff --git a/include/llvm/Support/Registry.h b/include/llvm/Support/Registry.h index bbea97b289a6..27f025fcd080 100644 --- a/include/llvm/Support/Registry.h +++ b/include/llvm/Support/Registry.h @@ -14,9 +14,10 @@ #ifndef LLVM_SUPPORT_REGISTRY_H #define LLVM_SUPPORT_REGISTRY_H -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DynamicLibrary.h" #include <memory> namespace llvm { @@ -37,69 +38,45 @@ namespace llvm { std::unique_ptr<T> instantiate() const { return Ctor(); } }; - /// Traits for registry entries. If using other than SimpleRegistryEntry, it - /// is necessary to define an alternate traits class. - template <typename T> - class RegistryTraits { - RegistryTraits() = delete; - - public: - typedef SimpleRegistryEntry<T> entry; - - /// nameof/descof - Accessors for name and description of entries. These are - // used to generate help for command-line options. - static const char *nameof(const entry &Entry) { return Entry.getName(); } - static const char *descof(const entry &Entry) { return Entry.getDesc(); } - }; - /// A global registry used in conjunction with static constructors to make /// pluggable components (like targets or garbage collectors) "just work" when /// linked with an executable. - template <typename T, typename U = RegistryTraits<T> > + template <typename T> class Registry { public: - typedef U traits; - typedef typename U::entry entry; + typedef SimpleRegistryEntry<T> entry; class node; - class listener; class iterator; private: Registry() = delete; - static void Announce(const entry &E) { - for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next) - Cur->registered(E); - } - friend class node; static node *Head, *Tail; - friend class listener; - static listener *ListenerHead, *ListenerTail; - public: /// Node in linked list of entries. /// class node { friend class iterator; + friend Registry<T>; node *Next; const entry& Val; public: - node(const entry& V) : Next(nullptr), Val(V) { - if (Tail) - Tail->Next = this; - else - Head = this; - Tail = this; - - Announce(V); - } + node(const entry &V) : Next(nullptr), Val(V) {} }; + static void add_node(node *N) { + if (Tail) + Tail->Next = N; + else + Head = N; + Tail = N; + } + /// Iterators for registry entries. /// class iterator { @@ -122,60 +99,6 @@ namespace llvm { return make_range(begin(), end()); } - /// Abstract base class for registry listeners, which are informed when new - /// entries are added to the registry. Simply subclass and instantiate: - /// - /// \code - /// class CollectorPrinter : public Registry<Collector>::listener { - /// protected: - /// void registered(const Registry<Collector>::entry &e) { - /// cerr << "collector now available: " << e->getName() << "\n"; - /// } - /// - /// public: - /// CollectorPrinter() { init(); } // Print those already registered. - /// }; - /// - /// CollectorPrinter Printer; - /// \endcode - class listener { - listener *Prev, *Next; - - friend void Registry::Announce(const entry &E); - - protected: - /// Called when an entry is added to the registry. - /// - virtual void registered(const entry &) = 0; - - /// Calls 'registered' for each pre-existing entry. - /// - void init() { - for (iterator I = begin(), E = end(); I != E; ++I) - registered(*I); - } - - public: - listener() : Prev(ListenerTail), Next(nullptr) { - if (Prev) - Prev->Next = this; - else - ListenerHead = this; - ListenerTail = this; - } - - virtual ~listener() { - if (Next) - Next->Prev = Prev; - else - ListenerTail = Prev; - if (Prev) - Prev->Next = Next; - else - ListenerHead = Next; - } - }; - /// A static registration template. Use like such: /// /// Registry<Collector>::Add<FancyGC> @@ -184,14 +107,6 @@ namespace llvm { /// Use of this template requires that: /// /// 1. The registered subclass has a default constructor. - // - /// 2. The registry entry type has a constructor compatible with this - /// signature: - /// - /// entry(const char *Name, const char *ShortDesc, T *(*Ctor)()); - /// - /// If you have more elaborate requirements, then copy and modify. - /// template <typename V> class Add { entry Entry; @@ -201,27 +116,65 @@ namespace llvm { public: Add(const char *Name, const char *Desc) - : Entry(Name, Desc, CtorFn), Node(Entry) {} + : Entry(Name, Desc, CtorFn), Node(Entry) { + add_node(&Node); + } }; - /// Registry::Parser now lives in llvm/Support/RegistryParser.h. + /// A dynamic import facility. This is used on Windows to + /// import the entries added in the plugin. + static void import(sys::DynamicLibrary &DL, const char *RegistryName) { + typedef void *(*GetRegistry)(); + std::string Name("LLVMGetRegistry_"); + Name.append(RegistryName); + GetRegistry Getter = + (GetRegistry)(intptr_t)DL.getAddressOfSymbol(Name.c_str()); + if (Getter) { + // Call the getter function in order to get the full copy of the + // registry defined in the plugin DLL, and copy them over to the + // current Registry. + typedef std::pair<const node *, const node *> Info; + Info *I = static_cast<Info *>(Getter()); + iterator begin(I->first); + iterator end(I->second); + for (++end; begin != end; ++begin) { + // This Node object needs to remain alive for the + // duration of the program. + add_node(new node(*begin)); + } + } + } + + /// Retrieve the data to be passed across DLL boundaries when + /// importing registries from another DLL on Windows. + static void *exportRegistry() { + static std::pair<const node *, const node *> Info(Head, Tail); + return &Info; + } }; + // Since these are defined in a header file, plugins must be sure to export // these symbols. + template <typename T> + typename Registry<T>::node *Registry<T>::Head; - template <typename T, typename U> - typename Registry<T,U>::node *Registry<T,U>::Head; - - template <typename T, typename U> - typename Registry<T,U>::node *Registry<T,U>::Tail; - - template <typename T, typename U> - typename Registry<T,U>::listener *Registry<T,U>::ListenerHead; - - template <typename T, typename U> - typename Registry<T,U>::listener *Registry<T,U>::ListenerTail; - + template <typename T> + typename Registry<T>::node *Registry<T>::Tail; } // end namespace llvm +#ifdef LLVM_ON_WIN32 +#define LLVM_EXPORT_REGISTRY(REGISTRY_CLASS) \ + extern "C" { \ + __declspec(dllexport) void *__cdecl LLVMGetRegistry_##REGISTRY_CLASS() { \ + return REGISTRY_CLASS::exportRegistry(); \ + } \ + } +#define LLVM_IMPORT_REGISTRY(REGISTRY_CLASS, DL) \ + REGISTRY_CLASS::import(DL, #REGISTRY_CLASS) +#else +#define LLVM_EXPORT_REGISTRY(REGISTRY_CLASS) +#define LLVM_IMPORT_REGISTRY(REGISTRY_CLASS, DL) +#endif + #endif // LLVM_SUPPORT_REGISTRY_H diff --git a/include/llvm/Support/RegistryParser.h b/include/llvm/Support/RegistryParser.h deleted file mode 100644 index a6997b6fe774..000000000000 --- a/include/llvm/Support/RegistryParser.h +++ /dev/null @@ -1,55 +0,0 @@ -//=== RegistryParser.h - Linker-supported plugin registries -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines a command-line parser for a registry. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_REGISTRYPARSER_H -#define LLVM_SUPPORT_REGISTRYPARSER_H - -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Registry.h" - -namespace llvm { - - /// A command-line parser for a registry. Use like such: - /// - /// static cl::opt<Registry<Collector>::entry, false, - /// RegistryParser<Collector> > - /// GCOpt("gc", cl::desc("Garbage collector to use."), - /// cl::value_desc()); - /// - /// To make use of the value: - /// - /// Collector *TheCollector = GCOpt->instantiate(); - /// - template <typename T, typename U = RegistryTraits<T> > - class RegistryParser : - public cl::parser<const typename U::entry*>, - public Registry<T, U>::listener { - typedef U traits; - typedef typename U::entry entry; - typedef typename Registry<T, U>::listener listener; - - protected: - void registered(const entry &E) { - addLiteralOption(traits::nameof(E), &E, traits::descof(E)); - } - - public: - void initialize(cl::Option &O) { - listener::init(); - cl::parser<const typename U::entry*>::initialize(O); - } - }; - -} - -#endif // LLVM_SUPPORT_REGISTRYPARSER_H diff --git a/include/llvm/Support/SHA1.h b/include/llvm/Support/SHA1.h new file mode 100644 index 000000000000..8347a713f272 --- /dev/null +++ b/include/llvm/Support/SHA1.h @@ -0,0 +1,82 @@ +//==- SHA1.h - SHA1 implementation for LLVM --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This code is taken from public domain +// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) +// and modified by wrapping it in a C++ interface for LLVM, +// and removing unnecessary code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SHA1_H +#define LLVM_SUPPORT_SHA1_H + +#include "llvm/ADT/ArrayRef.h" + +#include <cstdint> + +namespace llvm { +template <typename T> class ArrayRef; +class StringRef; + +/// A class that wrap the SHA1 algorithm. +class SHA1 { +public: + SHA1() { init(); } + + /// Reinitialize the internal state + void init(); + + /// Digest more data. + void update(ArrayRef<uint8_t> Data); + + /// Digest more data. + void update(StringRef Str) { + update(ArrayRef<uint8_t>((uint8_t *)const_cast<char *>(Str.data()), + Str.size())); + } + + /// Return a reference to the current raw 160-bits SHA1 for the digested data + /// since the last call to init(). This call will add data to the internal + /// state and as such is not suited for getting an intermediate result + /// (see result()). + StringRef final(); + + /// Return a reference to the current raw 160-bits SHA1 for the digested data + /// since the last call to init(). This is suitable for getting the SHA1 at + /// any time without invalidating the internal state so that more calls can be + /// made into update. + StringRef result(); + +private: + /// Define some constants. + /// "static constexpr" would be cleaner but MSVC does not support it yet. + enum { BLOCK_LENGTH = 64 }; + enum { HASH_LENGTH = 20 }; + + // Internal State + struct { + uint32_t Buffer[BLOCK_LENGTH / 4]; + uint32_t State[HASH_LENGTH / 4]; + uint32_t ByteCount; + uint8_t BufferOffset; + } InternalState; + + // Internal copy of the hash, populated and accessed on calls to result() + uint32_t HashResult[HASH_LENGTH / 4]; + + // Helper + void writebyte(uint8_t data); + void hashBlock(); + void addUncounted(uint8_t data); + void pad(); +}; + +} // end llvm namespace + +#endif diff --git a/include/llvm/Support/ScaledNumber.h b/include/llvm/Support/ScaledNumber.h index c6421efc8b49..910174732994 100644 --- a/include/llvm/Support/ScaledNumber.h +++ b/include/llvm/Support/ScaledNumber.h @@ -859,7 +859,6 @@ template <class DigitsT> void ScaledNumber<DigitsT>::shiftLeft(int32_t Shift) { } Digits <<= Shift; - return; } template <class DigitsT> void ScaledNumber<DigitsT>::shiftRight(int32_t Shift) { @@ -886,7 +885,6 @@ template <class DigitsT> void ScaledNumber<DigitsT>::shiftRight(int32_t Shift) { } Digits >>= Shift; - return; } template <typename T> struct isPodLike; @@ -896,4 +894,4 @@ template <typename T> struct isPodLike<ScaledNumber<T>> { } // end namespace llvm -#endif +#endif // LLVM_SUPPORT_SCALEDNUMBER_H diff --git a/include/llvm/Support/ScopedPrinter.h b/include/llvm/Support/ScopedPrinter.h new file mode 100644 index 000000000000..a2f2e0985431 --- /dev/null +++ b/include/llvm/Support/ScopedPrinter.h @@ -0,0 +1,378 @@ +//===-- ScopedPrinter.h ---------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H +#define LLVM_SUPPORT_SCOPEDPRINTER_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +namespace llvm { + +template <typename T> struct EnumEntry { + StringRef Name; + // While Name suffices in most of the cases, in certain cases + // GNU style and LLVM style of ELFDumper do not + // display same string for same enum. The AltName if initialized appropriately + // will hold the string that GNU style emits. + // Example: + // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to + // "Advanced Micro Devices X86-64" on GNU style + StringRef AltName; + T Value; + EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {} + EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {} +}; + +struct HexNumber { + // To avoid sign-extension we have to explicitly cast to the appropriate + // unsigned type. The overloads are here so that every type that is implicitly + // convertible to an integer (including enums and endian helpers) can be used + // without requiring type traits or call-site changes. + HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {} + HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {} + HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {} + HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {} + HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {} + HexNumber(signed long long Value) + : Value(static_cast<unsigned long long>(Value)) {} + HexNumber(unsigned char Value) : Value(Value) {} + HexNumber(unsigned short Value) : Value(Value) {} + HexNumber(unsigned int Value) : Value(Value) {} + HexNumber(unsigned long Value) : Value(Value) {} + HexNumber(unsigned long long Value) : Value(Value) {} + uint64_t Value; +}; + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value); +const std::string to_hexString(uint64_t Value, bool UpperCase = true); + +template <class T> const std::string to_string(const T &Value) { + std::string number; + llvm::raw_string_ostream stream(number); + stream << Value; + return stream.str(); +} + +class ScopedPrinter { +public: + ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + + void flush() { OS.flush(); } + + void indent(int Levels = 1) { IndentLevel += Levels; } + + void unindent(int Levels = 1) { + IndentLevel = std::max(0, IndentLevel - Levels); + } + + void resetIndent() { IndentLevel = 0; } + + void setPrefix(StringRef P) { Prefix = P; } + + void printIndent() { + OS << Prefix; + for (int i = 0; i < IndentLevel; ++i) + OS << " "; + } + + template <typename T> HexNumber hex(T Value) { return HexNumber(Value); } + + template <typename T, typename TEnum> + void printEnum(StringRef Label, T Value, + ArrayRef<EnumEntry<TEnum>> EnumValues) { + StringRef Name; + bool Found = false; + for (const auto &EnumItem : EnumValues) { + if (EnumItem.Value == Value) { + Name = EnumItem.Name; + Found = true; + break; + } + } + + if (Found) { + startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + } else { + startLine() << Label << ": " << hex(Value) << "\n"; + } + } + + template <typename T, typename TFlag> + void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags, + TFlag EnumMask1 = {}, TFlag EnumMask2 = {}, + TFlag EnumMask3 = {}) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (const auto &Flag : Flags) { + if (Flag.Value == 0) + continue; + + TFlag EnumMask{}; + if (Flag.Value & EnumMask1) + EnumMask = EnumMask1; + else if (Flag.Value & EnumMask2) + EnumMask = EnumMask2; + else if (Flag.Value & EnumMask3) + EnumMask = EnumMask3; + bool IsEnum = (Flag.Value & EnumMask) != 0; + if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || + (IsEnum && (Value & EnumMask) == Flag.Value)) { + SetFlags.push_back(Flag); + } + } + + std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); + + startLine() << Label << " [ (" << hex(Value) << ")\n"; + for (const auto &Flag : SetFlags) { + startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; + } + startLine() << "]\n"; + } + + template <typename T> void printFlags(StringRef Label, T Value) { + startLine() << Label << " [ (" << hex(Value) << ")\n"; + uint64_t Flag = 1; + uint64_t Curr = Value; + while (Curr > 0) { + if (Curr & 1) + startLine() << " " << hex(Flag) << "\n"; + Curr >>= 1; + Flag <<= 1; + } + startLine() << "]\n"; + } + + void printNumber(StringRef Label, uint64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint8_t Value) { + startLine() << Label << ": " << unsigned(Value) << "\n"; + } + + void printNumber(StringRef Label, int64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int8_t Value) { + startLine() << Label << ": " << int(Value) << "\n"; + } + + void printNumber(StringRef Label, const APSInt &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printBoolean(StringRef Label, bool Value) { + startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; + } + + template <typename... T> void printVersion(StringRef Label, T... Version) { + startLine() << Label << ": "; + printVersionInternal(Version...); + getOStream() << "\n"; + } + + template <typename T> void printList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << Item; + Comma = true; + } + OS << "]\n"; + } + + template <typename T, typename U> + void printList(StringRef Label, const T &List, const U &Printer) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + Printer(OS, Item); + Comma = true; + } + OS << "]\n"; + } + + template <typename T> void printHexList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << hex(Item); + Comma = true; + } + OS << "]\n"; + } + + template <typename T> void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template <typename T> void printHex(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + } + + template <typename T> + void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) { + startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n'; + } + + void printString(StringRef Value) { startLine() << Value << "\n"; } + + void printString(StringRef Label, StringRef Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printString(StringRef Label, const std::string &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + template <typename T> + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef<char> Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, true); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + template <typename T> void printObject(StringRef Label, const T &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + raw_ostream &startLine() { + printIndent(); + return OS; + } + + raw_ostream &getOStream() { return OS; } + +private: + template <typename T> void printVersionInternal(T Value) { + getOStream() << Value; + } + + template <typename S, typename T, typename... TArgs> + void printVersionInternal(S Value, T Value2, TArgs... Args) { + getOStream() << Value << "."; + printVersionInternal(Value2, Args...); + } + + template <typename T> + static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, + bool Block); + + raw_ostream &OS; + int IndentLevel; + StringRef Prefix; +}; + +template <> +inline void +ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label, + support::ulittle16_t Value) { + startLine() << Label << ": " << hex(Value) << "\n"; +} + +template<char Open, char Close> +struct DelimitedScope { + explicit DelimitedScope(ScopedPrinter &W) : W(W) { + W.startLine() << Open << '\n'; + W.indent(); + } + + DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) { + W.startLine() << N; + if (!N.empty()) + W.getOStream() << ' '; + W.getOStream() << Open << '\n'; + W.indent(); + } + + ~DelimitedScope() { + W.unindent(); + W.startLine() << Close << '\n'; + } + + ScopedPrinter &W; +}; + +using DictScope = DelimitedScope<'{', '}'>; +using ListScope = DelimitedScope<'[', ']'>; + +} // namespace llvm + +#endif diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h index 2a4d84bd891a..cbd6f686a778 100644 --- a/include/llvm/Support/Signals.h +++ b/include/llvm/Support/Signals.h @@ -38,8 +38,14 @@ namespace sys { /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the /// process, print a stack trace and then exit. - /// @brief Print a stack trace if a fatal signal occurs. - void PrintStackTraceOnErrorSignal(bool DisableCrashReporting = false); + /// \brief Print a stack trace if a fatal signal occurs. + /// \param Argv0 the current binary name, used to find the symbolizer + /// relative to the current binary before searching $PATH; can be + /// StringRef(), in which case we will only search $PATH. + /// \param DisableCrashReporting if \c true, disable the normal crash + /// reporting mechanisms on the underlying operating system. + void PrintStackTraceOnErrorSignal(StringRef Argv0, + bool DisableCrashReporting = false); /// Disable all system dialog boxes that appear when the process crashes. void DisableSystemDialogsOnCrash(); diff --git a/include/llvm/Support/StreamingMemoryObject.h b/include/llvm/Support/StreamingMemoryObject.h index a5980c235946..1ab85372cd20 100644 --- a/include/llvm/Support/StreamingMemoryObject.h +++ b/include/llvm/Support/StreamingMemoryObject.h @@ -28,15 +28,7 @@ public: uint64_t getExtent() const override; uint64_t readBytes(uint8_t *Buf, uint64_t Size, uint64_t Address) const override; - const uint8_t *getPointer(uint64_t address, uint64_t size) const override { - // FIXME: This could be fixed by ensuring the bytes are fetched and - // making a copy, requiring that the bitcode size be known, or - // otherwise ensuring that the memory doesn't go away/get reallocated, - // but it's not currently necessary. Users that need the pointer (any - // that need Blobs) don't stream. - report_fatal_error("getPointer in streaming memory objects not allowed"); - return nullptr; - } + const uint8_t *getPointer(uint64_t Address, uint64_t Size) const override; bool isValidAddress(uint64_t address) const override; /// Drop s bytes from the front of the stream, pushing the positions of the diff --git a/include/llvm/Support/SwapByteOrder.h b/include/llvm/Support/SwapByteOrder.h index 7761fa1d7e01..91693aceb27d 100644 --- a/include/llvm/Support/SwapByteOrder.h +++ b/include/llvm/Support/SwapByteOrder.h @@ -18,7 +18,6 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include <cstddef> -#include <limits> namespace llvm { namespace sys { diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h index c21019d0c5b8..0e2141f6d46f 100644 --- a/include/llvm/Support/TargetParser.h +++ b/include/llvm/Support/TargetParser.h @@ -83,6 +83,7 @@ enum ArchExtKind : unsigned { AEK_VIRT = 0x200, AEK_DSP = 0x400, AEK_FP16 = 0x800, + AEK_RAS = 0x1000, // Unsupported extensions. AEK_OS = 0x8000000, AEK_IWMMXT = 0x10000000, @@ -140,6 +141,61 @@ unsigned parseArchProfile(StringRef Arch); unsigned parseArchVersion(StringRef Arch); } // namespace ARM + +// FIXME:This should be made into class design,to avoid dupplication. +namespace AArch64 { + +// Arch extension modifiers for CPUs. +enum ArchExtKind : unsigned { + AEK_INVALID = 0x0, + AEK_NONE = 0x1, + AEK_CRC = 0x2, + AEK_CRYPTO = 0x4, + AEK_FP = 0x8, + AEK_SIMD = 0x10, + AEK_FP16 = 0x20, + AEK_PROFILE = 0x40, + AEK_RAS = 0x80 +}; + +StringRef getCanonicalArchName(StringRef Arch); + +// Information by ID +StringRef getFPUName(unsigned FPUKind); +unsigned getFPUVersion(unsigned FPUKind); +unsigned getFPUNeonSupportLevel(unsigned FPUKind); +unsigned getFPURestriction(unsigned FPUKind); + +// FIXME: These should be moved to TargetTuple once it exists +bool getFPUFeatures(unsigned FPUKind, std::vector<const char *> &Features); +bool getExtensionFeatures(unsigned Extensions, + std::vector<const char*> &Features); +bool getArchFeatures(unsigned ArchKind, std::vector<const char *> &Features); + +StringRef getArchName(unsigned ArchKind); +unsigned getArchAttr(unsigned ArchKind); +StringRef getCPUAttr(unsigned ArchKind); +StringRef getSubArch(unsigned ArchKind); +StringRef getArchExtName(unsigned ArchExtKind); +const char *getArchExtFeature(StringRef ArchExt); +unsigned checkArchVersion(StringRef Arch); + +// Information by Name +unsigned getDefaultFPU(StringRef CPU, unsigned ArchKind); +unsigned getDefaultExtensions(StringRef CPU, unsigned ArchKind); +StringRef getDefaultCPU(StringRef Arch); + +// Parser +unsigned parseFPU(StringRef FPU); +unsigned parseArch(StringRef Arch); +unsigned parseArchExt(StringRef ArchExt); +unsigned parseCPUArch(StringRef CPU); +unsigned parseArchISA(StringRef Arch); +unsigned parseArchEndian(StringRef Arch); +unsigned parseArchProfile(StringRef Arch); +unsigned parseArchVersion(StringRef Arch); + +} // namespace AArch64 } // namespace llvm #endif diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index aec181b1d266..076558e4df77 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -20,6 +20,7 @@ #define LLVM_SUPPORT_TARGETREGISTRY_H #include "llvm-c/Disassembler.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/FormattedStream.h" @@ -33,7 +34,6 @@ class MCAsmBackend; class MCAsmInfo; class MCAsmParser; class MCCodeEmitter; -class MCCodeGenInfo; class MCContext; class MCDisassembler; class MCInstrAnalysis; @@ -92,10 +92,9 @@ public: typedef MCAsmInfo *(*MCAsmInfoCtorFnTy)(const MCRegisterInfo &MRI, const Triple &TT); - typedef MCCodeGenInfo *(*MCCodeGenInfoCtorFnTy)(const Triple &TT, - Reloc::Model RM, - CodeModel::Model CM, - CodeGenOpt::Level OL); + typedef void (*MCAdjustCodeGenOptsFnTy)(const Triple &TT, Reloc::Model RM, + CodeModel::Model &CM); + typedef MCInstrInfo *(*MCInstrInfoCtorFnTy)(void); typedef MCInstrAnalysis *(*MCInstrAnalysisCtorFnTy)(const MCInstrInfo *Info); typedef MCRegisterInfo *(*MCRegInfoCtorFnTy)(const Triple &TT); @@ -104,8 +103,8 @@ public: StringRef Features); typedef TargetMachine *(*TargetMachineCtorTy)( const Target &T, const Triple &TT, StringRef CPU, StringRef Features, - const TargetOptions &Options, Reloc::Model RM, CodeModel::Model CM, - CodeGenOpt::Level OL); + const TargetOptions &Options, Optional<Reloc::Model> RM, + CodeModel::Model CM, CodeGenOpt::Level OL); // If it weren't for layering issues (this header is in llvm/Support, but // depends on MC?) this should take the Streamer by value rather than rvalue // reference. @@ -177,9 +176,7 @@ private: /// registered. MCAsmInfoCtorFnTy MCAsmInfoCtorFn; - /// MCCodeGenInfoCtorFn - Constructor function for this target's - /// MCCodeGenInfo, if registered. - MCCodeGenInfoCtorFnTy MCCodeGenInfoCtorFn; + MCAdjustCodeGenOptsFnTy MCAdjustCodeGenOptsFn; /// MCInstrInfoCtorFn - Constructor function for this target's MCInstrInfo, /// if registered. @@ -300,14 +297,10 @@ public: return MCAsmInfoCtorFn(MRI, Triple(TheTriple)); } - /// createMCCodeGenInfo - Create a MCCodeGenInfo implementation. - /// - MCCodeGenInfo *createMCCodeGenInfo(StringRef TT, Reloc::Model RM, - CodeModel::Model CM, - CodeGenOpt::Level OL) const { - if (!MCCodeGenInfoCtorFn) - return nullptr; - return MCCodeGenInfoCtorFn(Triple(TT), RM, CM, OL); + void adjustCodeGenOpts(const Triple &TT, Reloc::Model RM, + CodeModel::Model &CM) const { + if (MCAdjustCodeGenOptsFn) + MCAdjustCodeGenOptsFn(TT, RM, CM); } /// createMCInstrInfo - Create a MCInstrInfo implementation. @@ -359,8 +352,7 @@ public: /// host if that does not exist. TargetMachine * createTargetMachine(StringRef TT, StringRef CPU, StringRef Features, - const TargetOptions &Options, - Reloc::Model RM = Reloc::Default, + const TargetOptions &Options, Optional<Reloc::Model> RM, CodeModel::Model CM = CodeModel::Default, CodeGenOpt::Level OL = CodeGenOpt::Default) const { if (!TargetMachineCtorFn) @@ -646,18 +638,9 @@ struct TargetRegistry { T.MCAsmInfoCtorFn = Fn; } - /// RegisterMCCodeGenInfo - Register a MCCodeGenInfo implementation for the - /// given target. - /// - /// Clients are responsible for ensuring that registration doesn't occur - /// while another thread is attempting to access the registry. Typically - /// this is done by initializing all targets at program startup. - /// - /// @param T - The target being registered. - /// @param Fn - A function to construct a MCCodeGenInfo for the target. - static void RegisterMCCodeGenInfo(Target &T, - Target::MCCodeGenInfoCtorFnTy Fn) { - T.MCCodeGenInfoCtorFn = Fn; + static void registerMCAdjustCodeGenOpts(Target &T, + Target::MCAdjustCodeGenOptsFnTy Fn) { + T.MCAdjustCodeGenOptsFn = Fn; } /// RegisterMCInstrInfo - Register a MCInstrInfo implementation for the @@ -914,39 +897,9 @@ struct RegisterMCAsmInfoFn { } }; -/// RegisterMCCodeGenInfo - Helper template for registering a target codegen -/// info -/// implementation. This invokes the static "Create" method on the class -/// to actually do the construction. Usage: -/// -/// extern "C" void LLVMInitializeFooTarget() { -/// extern Target TheFooTarget; -/// RegisterMCCodeGenInfo<FooMCCodeGenInfo> X(TheFooTarget); -/// } -template <class MCCodeGenInfoImpl> struct RegisterMCCodeGenInfo { - RegisterMCCodeGenInfo(Target &T) { - TargetRegistry::RegisterMCCodeGenInfo(T, &Allocator); - } - -private: - static MCCodeGenInfo *Allocator(const Triple & /*TT*/, Reloc::Model /*RM*/, - CodeModel::Model /*CM*/, - CodeGenOpt::Level /*OL*/) { - return new MCCodeGenInfoImpl(); - } -}; - -/// RegisterMCCodeGenInfoFn - Helper template for registering a target codegen -/// info implementation. This invokes the specified function to do the -/// construction. Usage: -/// -/// extern "C" void LLVMInitializeFooTarget() { -/// extern Target TheFooTarget; -/// RegisterMCCodeGenInfoFn X(TheFooTarget, TheFunction); -/// } -struct RegisterMCCodeGenInfoFn { - RegisterMCCodeGenInfoFn(Target &T, Target::MCCodeGenInfoCtorFnTy Fn) { - TargetRegistry::RegisterMCCodeGenInfo(T, Fn); +struct RegisterMCAdjustCodeGenOptsFn { + RegisterMCAdjustCodeGenOptsFn(Target &T, Target::MCAdjustCodeGenOptsFnTy Fn) { + TargetRegistry::registerMCAdjustCodeGenOpts(T, Fn); } }; @@ -1097,7 +1050,8 @@ template <class TargetMachineImpl> struct RegisterTargetMachine { private: static TargetMachine *Allocator(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, - const TargetOptions &Options, Reloc::Model RM, + const TargetOptions &Options, + Optional<Reloc::Model> RM, CodeModel::Model CM, CodeGenOpt::Level OL) { return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL); } diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h index 745334db4450..665cec2465bf 100644 --- a/include/llvm/Support/ThreadPool.h +++ b/include/llvm/Support/ThreadPool.h @@ -33,6 +33,7 @@ #pragma warning(pop) #endif +#include <atomic> #include <condition_variable> #include <functional> #include <memory> diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h index 9007c132a99a..09b96dfb4c1c 100644 --- a/include/llvm/Support/Threading.h +++ b/include/llvm/Support/Threading.h @@ -15,6 +15,27 @@ #ifndef LLVM_SUPPORT_THREADING_H #define LLVM_SUPPORT_THREADING_H +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX +#include "llvm/Support/Compiler.h" +#include <ciso646> // So we can check the C++ standard lib macros. +#include <functional> + +// We use std::call_once on all Unix platforms except for NetBSD with +// libstdc++. That platform has a bug they are working to fix, and they'll +// remove the NetBSD checks once fixed. +#if defined(LLVM_ON_UNIX) && \ + !(defined(__NetBSD__) && !defined(_LIBCPP_VERSION)) && !defined(__ppc__) +#define LLVM_THREADING_USE_STD_CALL_ONCE 1 +#else +#define LLVM_THREADING_USE_STD_CALL_ONCE 0 +#endif + +#if LLVM_THREADING_USE_STD_CALL_ONCE +#include <mutex> +#else +#include "llvm/Support/Atomic.h" +#endif + namespace llvm { /// Returns true if LLVM is compiled with support for multi-threading, and /// false otherwise. @@ -34,6 +55,66 @@ namespace llvm { /// the thread stack. void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData, unsigned RequestedStackSize = 0); + +#if LLVM_THREADING_USE_STD_CALL_ONCE + + typedef std::once_flag once_flag; + + /// This macro is the only way you should define your once flag for LLVM's + /// call_once. +#define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag + +#else + + enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 }; + typedef volatile sys::cas_flag once_flag; + + /// This macro is the only way you should define your once flag for LLVM's + /// call_once. +#define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag = Uninitialized + +#endif + + /// \brief Execute the function specified as a parameter once. + /// + /// Typical usage: + /// \code + /// void foo() {...}; + /// ... + /// LLVM_DEFINE_ONCE_FLAG(flag); + /// call_once(flag, foo); + /// \endcode + /// + /// \param flag Flag used for tracking whether or not this has run. + /// \param F Function to call once. + template <typename Function, typename... Args> + void call_once(once_flag &flag, Function &&F, Args &&... ArgList) { +#if LLVM_THREADING_USE_STD_CALL_ONCE + std::call_once(flag, std::forward<Function>(F), + std::forward<Args>(ArgList)...); +#else + // For other platforms we use a generic (if brittle) version based on our + // atomics. + sys::cas_flag old_val = sys::CompareAndSwap(&flag, Wait, Uninitialized); + if (old_val == Uninitialized) { + std::forward<Function>(F)(std::forward<Args>(ArgList)...); + sys::MemoryFence(); + TsanIgnoreWritesBegin(); + TsanHappensBefore(&flag); + flag = Done; + TsanIgnoreWritesEnd(); + } else { + // Wait until any thread doing the call has finished. + sys::cas_flag tmp = flag; + sys::MemoryFence(); + while (tmp != Done) { + tmp = flag; + sys::MemoryFence(); + } + } + TsanHappensAfter(&flag); +#endif + } } #endif diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index 499fe7b7e70c..f0cb07599b86 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -104,6 +104,9 @@ public: const std::string &getName() const { return Name; } bool isInitialized() const { return TG != nullptr; } + /// Check if the timer is currently running. + bool isRunning() const { return Running; } + /// Check if startTimer() has ever been called on this timer. bool hasTriggered() const { return Triggered; } diff --git a/include/llvm/Support/TrailingObjects.h b/include/llvm/Support/TrailingObjects.h index 8529746eeccc..5a21cddf9731 100644 --- a/include/llvm/Support/TrailingObjects.h +++ b/include/llvm/Support/TrailingObjects.h @@ -197,7 +197,7 @@ struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { return additionalSizeToAllocImpl( (requiresRealignment() - ? llvm::RoundUpToAlignment(SizeSoFar, llvm::alignOf<NextTy>()) + ? llvm::alignTo(SizeSoFar, llvm::alignOf<NextTy>()) : SizeSoFar) + sizeof(NextTy) * Count1, MoreCounts...); @@ -290,7 +290,7 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< } public: - // make this (privately inherited) class public. + // Make this (privately inherited) member public. using ParentType::OverloadToken; /// Returns a pointer to the trailing object array of the given type @@ -342,6 +342,51 @@ public: TrailingTys, size_t>::type... Counts) { return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); } + + /// A type where its ::with_counts template member has a ::type member + /// suitable for use as uninitialized storage for an object with the given + /// trailing object counts. The template arguments are similar to those + /// of additionalSizeToAlloc. + /// + /// Use with FixedSizeStorageOwner, e.g.: + /// + /// \code{.cpp} + /// + /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage; + /// MyObj::FixedSizeStorageOwner + /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj); + /// MyObj *const myStackObjPtr = myStackObjOwner.get(); + /// + /// \endcode + template <typename... Tys> struct FixedSizeStorage { + template <size_t... Counts> struct with_counts { + enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; + typedef llvm::AlignedCharArray< + llvm::AlignOf<BaseTy>::Alignment, Size + > type; + }; + }; + + /// A type that acts as the owner for an object placed into fixed storage. + class FixedSizeStorageOwner { + public: + FixedSizeStorageOwner(BaseTy *p) : p(p) {} + ~FixedSizeStorageOwner() { + assert(p && "FixedSizeStorageOwner owns null?"); + p->~BaseTy(); + } + + BaseTy *get() { return p; } + const BaseTy *get() const { return p; } + + private: + FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete; + FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete; + FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete; + FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete; + + BaseTy *const p; + }; }; } // end namespace llvm diff --git a/include/llvm/Support/TypeName.h b/include/llvm/Support/TypeName.h new file mode 100644 index 000000000000..0eb7ead98b21 --- /dev/null +++ b/include/llvm/Support/TypeName.h @@ -0,0 +1,65 @@ +//===- TypeName.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPENAME_H +#define LLVM_SUPPORT_TYPENAME_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +/// We provide a function which tries to compute the (demangled) name of a type +/// statically. +/// +/// This routine may fail on some platforms or for particularly unusual types. +/// Do not use it for anything other than logging and debugging aids. It isn't +/// portable or dependendable in any real sense. +/// +/// The returned StringRef will point into a static storage duration string. +/// However, it may not be null terminated and may be some strangely aligned +/// inner substring of a larger string. +template <typename DesiredTypeName> +inline StringRef getTypeName() { +#if defined(__clang__) || defined(__GNUC__) + StringRef Name = __PRETTY_FUNCTION__; + + StringRef Key = "DesiredTypeName = "; + Name = Name.substr(Name.find(Key)); + assert(!Name.empty() && "Unable to find the template parameter!"); + Name = Name.drop_front(Key.size()); + + assert(Name.endswith("]") && "Name doesn't end in the substitution key!"); + return Name.drop_back(1); +#elif defined(_MSC_VER) + StringRef Name = __FUNCSIG__; + + StringRef Key = "getTypeName<"; + Name = Name.substr(Name.find(Key)); + assert(!Name.empty() && "Unable to find the function name!"); + Name = Name.drop_front(Key.size()); + + for (StringRef Prefix : {"class ", "struct ", "union ", "enum "}) + if (Name.startswith(Prefix)) { + Name = Name.drop_front(Prefix.size()); + break; + } + + auto AnglePos = Name.rfind('>'); + assert(AnglePos != StringRef::npos && "Unable to find the closing '>'!"); + return Name.substr(0, AnglePos); +#else + // No known technique for statically extracting a type name on this compiler. + // We return a string that is unlikely to look like any type in LLVM. + return "UNKNOWN_TYPE"; +#endif +} + +} + +#endif diff --git a/include/llvm/Support/Unicode.h b/include/llvm/Support/Unicode.h index f668a5bc88df..adedb1ed83a6 100644 --- a/include/llvm/Support/Unicode.h +++ b/include/llvm/Support/Unicode.h @@ -15,9 +15,9 @@ #ifndef LLVM_SUPPORT_UNICODE_H #define LLVM_SUPPORT_UNICODE_H -#include "llvm/ADT/StringRef.h" - namespace llvm { +class StringRef; + namespace sys { namespace unicode { diff --git a/include/llvm/Support/Valgrind.h b/include/llvm/Support/Valgrind.h index 12b0dc961daa..084b901b326c 100644 --- a/include/llvm/Support/Valgrind.h +++ b/include/llvm/Support/Valgrind.h @@ -1,4 +1,4 @@ -//===- llvm/Support/Valgrind.h - Communication with Valgrind -----*- C++ -*-===// +//===- llvm/Support/Valgrind.h - Communication with Valgrind ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,9 +16,7 @@ #ifndef LLVM_SUPPORT_VALGRIND_H #define LLVM_SUPPORT_VALGRIND_H -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/Compiler.h" -#include <stddef.h> +#include <cstddef> namespace llvm { namespace sys { @@ -28,7 +26,7 @@ namespace sys { // Discard valgrind's translation of code in the range [Addr .. Addr + Len). // Otherwise valgrind may continue to execute the old version of the code. void ValgrindDiscardTranslations(const void *Addr, size_t Len); -} -} +} // namespace sys +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_VALGRIND_H diff --git a/include/llvm/Support/YAMLParser.h b/include/llvm/Support/YAMLParser.h index a5addfa3c7ae..23014fc10a3f 100644 --- a/include/llvm/Support/YAMLParser.h +++ b/include/llvm/Support/YAMLParser.h @@ -41,7 +41,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/SMLoc.h" -#include <limits> #include <map> #include <utility> diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index fb2badfd93ba..bc3fa8ad11da 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -10,8 +10,6 @@ #ifndef LLVM_SUPPORT_YAMLTRAITS_H #define LLVM_SUPPORT_YAMLTRAITS_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" @@ -19,6 +17,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" @@ -512,11 +511,11 @@ public: template <typename FBT, typename T> void enumFallback(T &Val) { - if ( matchEnumFallback() ) { + if (matchEnumFallback()) { // FIXME: Force integral conversion to allow strong typedefs to convert. - FBT Res = (uint64_t)Val; + FBT Res = static_cast<typename FBT::BaseType>(Val); yamlize(*this, Res, true); - Val = (uint64_t)Res; + Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); } } @@ -858,6 +857,32 @@ struct ScalarTraits<double> { static bool mustQuote(StringRef) { return false; } }; +// For endian types, we just use the existing ScalarTraits for the underlying +// type. This way endian aware types are supported whenever a ScalarTraits +// is defined for the underlying type. +template <typename value_type, support::endianness endian, size_t alignment> +struct ScalarTraits<support::detail::packed_endian_specific_integral< + value_type, endian, alignment>> { + typedef support::detail::packed_endian_specific_integral<value_type, endian, + alignment> + endian_type; + + static void output(const endian_type &E, void *Ctx, + llvm::raw_ostream &Stream) { + ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); + } + static StringRef input(StringRef Str, void *Ctx, endian_type &E) { + value_type V; + auto R = ScalarTraits<value_type>::input(Str, Ctx, V); + E = static_cast<endian_type>(V); + return R; + } + + static bool mustQuote(StringRef Str) { + return ScalarTraits<value_type>::mustQuote(Str); + } +}; + // Utility for use within MappingTraits<>::mapping() method // to [de]normalize an object for use with YAML conversion. template <typename TNorm, typename TFinal> @@ -894,12 +919,16 @@ private: // to [de]normalize an object for use with YAML conversion. template <typename TNorm, typename TFinal> struct MappingNormalizationHeap { - MappingNormalizationHeap(IO &i_o, TFinal &Obj) + MappingNormalizationHeap(IO &i_o, TFinal &Obj, + llvm::BumpPtrAllocator *allocator) : io(i_o), BufPtr(nullptr), Result(Obj) { if ( io.outputting() ) { BufPtr = new (&Buffer) TNorm(io, Obj); } - else { + else if (allocator) { + BufPtr = allocator->Allocate<TNorm>(); + new (BufPtr) TNorm(io); + } else { BufPtr = new TNorm(io); } } @@ -1166,6 +1195,7 @@ private: bool operator==(const _base &rhs) const { return value == rhs; } \ bool operator<(const _type &rhs) const { return value < rhs.value; } \ _base value; \ + typedef _base BaseType; \ }; /// diff --git a/include/llvm/Support/raw_sha1_ostream.h b/include/llvm/Support/raw_sha1_ostream.h new file mode 100644 index 000000000000..329ef9fd069b --- /dev/null +++ b/include/llvm/Support/raw_sha1_ostream.h @@ -0,0 +1,47 @@ +//==- raw_sha1_ostream.h - raw_ostream that compute SHA1 --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the raw_sha1_ostream class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RAW_SHA1_OSTREAM_H +#define LLVM_SUPPORT_RAW_SHA1_OSTREAM_H + +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SHA1.h" +#include "llvm/ADT/ArrayRef.h" + +namespace llvm { + +/// A raw_ostream that hash the content using the sha1 algorithm. +class raw_sha1_ostream : public raw_ostream { + SHA1 State; + + /// See raw_ostream::write_impl. + void write_impl(const char *Ptr, size_t Size) override { + State.update(ArrayRef<uint8_t>((const uint8_t *)Ptr, Size)); + } + +public: + /// Return the current SHA1 hash for the content of the stream + StringRef sha1() { + flush(); + return State.result(); + } + + /// Reset the internal state to start over from scratch. + void resetHash() { State.init(); } + + uint64_t current_pos() const override { return 0; } +}; + +} // end llvm namespace + +#endif diff --git a/include/llvm/Support/thread.h b/include/llvm/Support/thread.h index 2d130418a57f..9c45418df55c 100644 --- a/include/llvm/Support/thread.h +++ b/include/llvm/Support/thread.h @@ -57,6 +57,7 @@ struct thread { thread(const thread &) = delete; void join() {} + static unsigned hardware_concurrency() { return 1; }; }; } diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 88385c3fae1e..7706ff527197 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -17,6 +17,8 @@ #include <type_traits> #include <utility> +#include "llvm/Support/Compiler.h" + #ifndef __has_feature #define LLVM_DEFINED_HAS_FEATURE #define __has_feature(x) 0 @@ -54,11 +56,12 @@ struct isPodLike<std::pair<T, U> > { }; /// \brief Metafunction that determines whether the given type is either an -/// integral type or an enumeration type. +/// integral type or an enumeration type, including enum classes. /// /// Note that this accepts potentially more integral types than is_integral -/// because it is based on merely being convertible implicitly to an integral -/// type. +/// because it is based on being implicitly convertible to an integral type. +/// Also note that enum classes aren't implicitly convertible to integral types, +/// the value may therefore need to be explicitly converted before being used. template <typename T> class is_integral_or_enum { typedef typename std::remove_reference<T>::type UnderlyingT; @@ -67,7 +70,8 @@ public: !std::is_class<UnderlyingT>::value && // Filter conversion operators. !std::is_pointer<UnderlyingT>::value && !std::is_floating_point<UnderlyingT>::value && - std::is_convertible<UnderlyingT, unsigned long long>::value; + (std::is_enum<UnderlyingT>::value || + std::is_convertible<UnderlyingT, unsigned long long>::value); }; /// \brief If T is a pointer, just return it. If it is not, return T&. diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h index 4c1ef4013dda..393cafa7924a 100644 --- a/include/llvm/TableGen/Record.h +++ b/include/llvm/TableGen/Record.h @@ -22,6 +22,7 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/TrailingObjects.h" #include "llvm/Support/raw_ostream.h" #include <map> @@ -43,6 +44,7 @@ public: enum RecTyKind { BitRecTyKind, BitsRecTyKind, + CodeRecTyKind, IntRecTyKind, StringRecTyKind, ListRecTyKind, @@ -64,11 +66,11 @@ public: void print(raw_ostream &OS) const { OS << getAsString(); } void dump() const; - /// typeIsConvertibleTo - Return true if all values of 'this' type can be - /// converted to the specified type. + /// Return true if all values of 'this' type can be converted to the specified + /// type. virtual bool typeIsConvertibleTo(const RecTy *RHS) const; - /// getListTy - Returns the type representing list<this>. + /// Returns the type representing list<this>. ListRecTy *getListTy(); }; @@ -77,7 +79,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RecTy &Ty) { return OS; } -/// BitRecTy - 'bit' - Represent a single bit +/// 'bit' - Represent a single bit /// class BitRecTy : public RecTy { static BitRecTy Shared; @@ -95,7 +97,7 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// BitsRecTy - 'bits<n>' - Represent a fixed number of bits +/// 'bits<n>' - Represent a fixed number of bits /// class BitsRecTy : public RecTy { unsigned Size; @@ -115,7 +117,23 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// IntRecTy - 'int' - Represent an integer value of no particular size +/// 'code' - Represent a code fragment +/// +class CodeRecTy : public RecTy { + static CodeRecTy Shared; + CodeRecTy() : RecTy(CodeRecTyKind) {} + +public: + static bool classof(const RecTy *RT) { + return RT->getRecTyKind() == CodeRecTyKind; + } + + static CodeRecTy *get() { return &Shared; } + + std::string getAsString() const override { return "code"; } +}; + +/// 'int' - Represent an integer value of no particular size /// class IntRecTy : public RecTy { static IntRecTy Shared; @@ -133,7 +151,7 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// StringRecTy - 'string' - Represent an string value +/// 'string' - Represent an string value /// class StringRecTy : public RecTy { static StringRecTy Shared; @@ -141,7 +159,8 @@ class StringRecTy : public RecTy { public: static bool classof(const RecTy *RT) { - return RT->getRecTyKind() == StringRecTyKind; + return RT->getRecTyKind() == StringRecTyKind || + RT->getRecTyKind() == CodeRecTyKind; } static StringRecTy *get() { return &Shared; } @@ -149,7 +168,7 @@ public: std::string getAsString() const override; }; -/// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of +/// 'list<Ty>' - Represent a list of values, all of which must be of /// the specified type. /// class ListRecTy : public RecTy { @@ -170,7 +189,7 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// DagRecTy - 'dag' - Represent a dag fragment +/// 'dag' - Represent a dag fragment /// class DagRecTy : public RecTy { static DagRecTy Shared; @@ -186,7 +205,7 @@ public: std::string getAsString() const override; }; -/// RecordRecTy - '[classname]' - Represent an instance of a class, such as: +/// '[classname]' - Represent an instance of a class, such as: /// (R32 X = EAX). /// class RecordRecTy : public RecTy { @@ -208,7 +227,7 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// resolveTypes - Find a common type that T1 and T2 convert to. +/// Find a common type that T1 and T2 convert to. /// Return 0 if no such type exists. /// RecTy *resolveTypes(RecTy *T1, RecTy *T2); @@ -236,6 +255,7 @@ protected: IK_BitInit, IK_FirstTypedInit, IK_BitsInit, + IK_CodeInit, IK_DagInit, IK_DefInit, IK_FieldInit, @@ -272,30 +292,30 @@ protected: public: virtual ~Init() {} - /// isComplete - This virtual method should be overridden by values that may + /// This virtual method should be overridden by values that may /// not be completely specified yet. virtual bool isComplete() const { return true; } - /// print - Print out this value. + /// Print out this value. void print(raw_ostream &OS) const { OS << getAsString(); } - /// getAsString - Convert this value to a string form. + /// Convert this value to a string form. virtual std::string getAsString() const = 0; - /// getAsUnquotedString - Convert this value to a string form, + /// Convert this value to a string form, /// without adding quote markers. This primaruly affects /// StringInits where we will not surround the string value with /// quotes. virtual std::string getAsUnquotedString() const { return getAsString(); } - /// dump - Debugging method that may be called through a debugger, just + /// Debugging method that may be called through a debugger, just /// invokes print on stderr. void dump() const; - /// convertInitializerTo - This virtual function converts to the appropriate + /// This virtual function converts to the appropriate /// Init based on the passed in type. virtual Init *convertInitializerTo(RecTy *Ty) const = 0; - /// convertInitializerBitRange - This method is used to implement the bitrange + /// This method is used to implement the bitrange /// selection operator. Given an initializer, it selects the specified bits /// out, returning them as a new init of bits type. If it is not legal to use /// the bit subscript operator on this initializer, return null. @@ -305,7 +325,7 @@ public: return nullptr; } - /// convertInitListSlice - This method is used to implement the list slice + /// This method is used to implement the list slice /// selection operator. Given an initializer, it selects the specified list /// elements, returning them as a new init of list type. If it is not legal /// to take a slice of this, return null. @@ -315,7 +335,7 @@ public: return nullptr; } - /// getFieldType - This method is used to implement the FieldInit class. + /// This method is used to implement the FieldInit class. /// Implementors of this method should return the type of the named field if /// they are of record type. /// @@ -323,7 +343,7 @@ public: return nullptr; } - /// getFieldInit - This method complements getFieldType to return the + /// This method complements getFieldType to return the /// initializer for the specified field. If getFieldType returns non-null /// this method should return non-null, otherwise it returns null. /// @@ -332,7 +352,7 @@ public: return nullptr; } - /// resolveReferences - This method is used by classes that refer to other + /// This method is used by classes that refer to other /// variables which may not be defined at the time the expression is formed. /// If a value is set for the variable later, this method will be called on /// users of the value to allow the value to propagate out. @@ -341,15 +361,15 @@ public: return const_cast<Init *>(this); } - /// getBit - This method is used to return the initializer for the specified + /// This method is used to return the initializer for the specified /// bit. virtual Init *getBit(unsigned Bit) const = 0; - /// getBitVar - This method is used to retrieve the initializer for bit + /// This method is used to retrieve the initializer for bit /// reference. For non-VarBitInit, it simply returns itself. virtual Init *getBitVar() const { return const_cast<Init*>(this); } - /// getBitNum - This method is used to retrieve the bit number of a bit + /// This method is used to retrieve the bit number of a bit /// reference. For non-VarBitInit, it simply returns 0. virtual unsigned getBitNum() const { return 0; } }; @@ -358,7 +378,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Init &I) { I.print(OS); return OS; } -/// TypedInit - This is the common super-class of types that have a specific, +/// This is the common super-class of types that have a specific, /// explicit, type. /// class TypedInit : public Init { @@ -390,20 +410,20 @@ public: Init * convertInitListSlice(const std::vector<unsigned> &Elements) const override; - /// getFieldType - This method is used to implement the FieldInit class. + /// This method is used to implement the FieldInit class. /// Implementors of this method should return the type of the named field if /// they are of record type. /// RecTy *getFieldType(const std::string &FieldName) const override; - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, unsigned Elt) const = 0; }; -/// UnsetInit - ? - Represents an uninitialized value +/// '?' - Represents an uninitialized value /// class UnsetInit : public Init { UnsetInit() : Init(IK_UnsetInit) {} @@ -426,7 +446,7 @@ public: std::string getAsString() const override { return "?"; } }; -/// BitInit - true/false - Represent a concrete initializer for a bit. +/// 'true'/'false' - Represent a concrete initializer for a bit. /// class BitInit : public Init { bool Value; @@ -453,20 +473,23 @@ public: std::string getAsString() const override { return Value ? "1" : "0"; } }; -/// BitsInit - { a, b, c } - Represents an initializer for a BitsRecTy value. +/// '{ a, b, c }' - Represents an initializer for a BitsRecTy value. /// It contains a vector of bits, whose size is determined by the type. /// -class BitsInit : public TypedInit, public FoldingSetNode { - std::vector<Init*> Bits; +class BitsInit final : public TypedInit, public FoldingSetNode, + public TrailingObjects<BitsInit, Init *> { + unsigned NumBits; - BitsInit(ArrayRef<Init *> Range) - : TypedInit(IK_BitsInit, BitsRecTy::get(Range.size())), - Bits(Range.begin(), Range.end()) {} + BitsInit(unsigned N) + : TypedInit(IK_BitsInit, BitsRecTy::get(N)), NumBits(N) {} BitsInit(const BitsInit &Other) = delete; BitsInit &operator=(const BitsInit &Other) = delete; public: + // Do not use sized deallocation due to trailing objects. + void operator delete(void *p) { ::operator delete(p); } + static bool classof(const Init *I) { return I->getKind() == IK_BitsInit; } @@ -474,7 +497,7 @@ public: void Profile(FoldingSetNodeID &ID) const; - unsigned getNumBits() const { return Bits.size(); } + unsigned getNumBits() const { return NumBits; } Init *convertInitializerTo(RecTy *Ty) const override; Init * @@ -492,7 +515,7 @@ public: } std::string getAsString() const override; - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. Init *resolveListElementReference(Record &R, const RecordVal *RV, @@ -503,12 +526,12 @@ public: Init *resolveReferences(Record &R, const RecordVal *RV) const override; Init *getBit(unsigned Bit) const override { - assert(Bit < Bits.size() && "Bit index out of range!"); - return Bits[Bit]; + assert(Bit < NumBits && "Bit index out of range!"); + return getTrailingObjects<Init *>()[Bit]; } }; -/// IntInit - 7 - Represent an initialization by a literal integer value. +/// '7' - Represent an initialization by a literal integer value. /// class IntInit : public TypedInit { int64_t Value; @@ -533,7 +556,7 @@ public: std::string getAsString() const override; - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. Init *resolveListElementReference(Record &R, const RecordVal *RV, @@ -546,13 +569,13 @@ public: } }; -/// StringInit - "foo" - Represent an initialization by a string value. +/// "foo" - Represent an initialization by a string value. /// class StringInit : public TypedInit { std::string Value; explicit StringInit(StringRef V) - : TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {} + : TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {} StringInit(const StringInit &Other) = delete; StringInit &operator=(const StringInit &Other) = delete; @@ -568,6 +591,7 @@ public: Init *convertInitializerTo(RecTy *Ty) const override; std::string getAsString() const override { return "\"" + Value + "\""; } + std::string getAsUnquotedString() const override { return Value; } /// resolveListElementReference - This method is used to implement @@ -583,23 +607,65 @@ public: } }; -/// ListInit - [AL, AH, CL] - Represent a list of defs +class CodeInit : public TypedInit { + std::string Value; + + explicit CodeInit(StringRef V) + : TypedInit(IK_CodeInit, static_cast<RecTy *>(CodeRecTy::get())), + Value(V) {} + + CodeInit(const StringInit &Other) = delete; + CodeInit &operator=(const StringInit &Other) = delete; + +public: + static bool classof(const Init *I) { + return I->getKind() == IK_CodeInit; + } + static CodeInit *get(StringRef); + + const std::string &getValue() const { return Value; } + + Init *convertInitializerTo(RecTy *Ty) const override; + + std::string getAsString() const override { + return "[{" + Value + "}]"; + } + + std::string getAsUnquotedString() const override { return Value; } + + /// This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) const override { + llvm_unreachable("Illegal element reference off string"); + } + + Init *getBit(unsigned Bit) const override { + llvm_unreachable("Illegal bit reference off string"); + } +}; + +/// [AL, AH, CL] - Represent a list of defs /// -class ListInit : public TypedInit, public FoldingSetNode { - std::vector<Init*> Values; +class ListInit final : public TypedInit, public FoldingSetNode, + public TrailingObjects<BitsInit, Init *> { + unsigned NumValues; public: - typedef std::vector<Init*>::const_iterator const_iterator; + typedef Init *const *const_iterator; private: - explicit ListInit(ArrayRef<Init *> Range, RecTy *EltTy) - : TypedInit(IK_ListInit, ListRecTy::get(EltTy)), - Values(Range.begin(), Range.end()) {} + explicit ListInit(unsigned N, RecTy *EltTy) + : TypedInit(IK_ListInit, ListRecTy::get(EltTy)), NumValues(N) {} ListInit(const ListInit &Other) = delete; ListInit &operator=(const ListInit &Other) = delete; public: + // Do not use sized deallocation due to trailing objects. + void operator delete(void *p) { ::operator delete(p); } + static bool classof(const Init *I) { return I->getKind() == IK_ListInit; } @@ -608,8 +674,8 @@ public: void Profile(FoldingSetNodeID &ID) const; Init *getElement(unsigned i) const { - assert(i < Values.size() && "List element index out of range!"); - return Values[i]; + assert(i < NumValues && "List element index out of range!"); + return getTrailingObjects<Init *>()[i]; } Record *getElementAsRecord(unsigned i) const; @@ -619,7 +685,7 @@ public: Init *convertInitializerTo(RecTy *Ty) const override; - /// resolveReferences - This method is used by classes that refer to other + /// This method is used by classes that refer to other /// variables which may not be defined at the time they expression is formed. /// If a value is set for the variable later, this method will be called on /// users of the value to allow the value to propagate out. @@ -628,15 +694,17 @@ public: std::string getAsString() const override; - ArrayRef<Init*> getValues() const { return Values; } + ArrayRef<Init*> getValues() const { + return makeArrayRef(getTrailingObjects<Init *>(), NumValues); + } - const_iterator begin() const { return Values.begin(); } - const_iterator end () const { return Values.end(); } + const_iterator begin() const { return getTrailingObjects<Init *>(); } + const_iterator end () const { return begin() + NumValues; } - size_t size () const { return Values.size(); } - bool empty() const { return Values.empty(); } + size_t size () const { return NumValues; } + bool empty() const { return NumValues == 0; } - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. Init *resolveListElementReference(Record &R, const RecordVal *RV, @@ -647,7 +715,7 @@ public: } }; -/// OpInit - Base class for operators +/// Base class for operators /// class OpInit : public TypedInit { OpInit(const OpInit &Other) = delete; @@ -678,9 +746,9 @@ public: Init *getBit(unsigned Bit) const override; }; -/// UnOpInit - !op (X) - Transform an init. +/// !op (X) - Transform an init. /// -class UnOpInit : public OpInit { +class UnOpInit : public OpInit, public FoldingSetNode { public: enum UnaryOp : uint8_t { CAST, HEAD, TAIL, EMPTY }; @@ -699,6 +767,8 @@ public: } static UnOpInit *get(UnaryOp opc, Init *lhs, RecTy *Type); + void Profile(FoldingSetNodeID &ID) const; + // Clone - Clone this operator, replacing arguments with the new list OpInit *clone(std::vector<Init *> &Operands) const override { assert(Operands.size() == 1 && @@ -724,9 +794,9 @@ public: std::string getAsString() const override; }; -/// BinOpInit - !op (X, Y) - Combine two inits. +/// !op (X, Y) - Combine two inits. /// -class BinOpInit : public OpInit { +class BinOpInit : public OpInit, public FoldingSetNode { public: enum BinaryOp : uint8_t { ADD, AND, SHL, SRA, SRL, LISTCONCAT, STRCONCAT, CONCAT, EQ }; @@ -747,6 +817,8 @@ public: static BinOpInit *get(BinaryOp opc, Init *lhs, Init *rhs, RecTy *Type); + void Profile(FoldingSetNodeID &ID) const; + // Clone - Clone this operator, replacing arguments with the new list OpInit *clone(std::vector<Init *> &Operands) const override { assert(Operands.size() == 2 && @@ -776,9 +848,9 @@ public: std::string getAsString() const override; }; -/// TernOpInit - !op (X, Y, Z) - Combine two inits. +/// !op (X, Y, Z) - Combine two inits. /// -class TernOpInit : public OpInit { +class TernOpInit : public OpInit, public FoldingSetNode { public: enum TernaryOp : uint8_t { SUBST, FOREACH, IF }; @@ -800,6 +872,8 @@ public: Init *mhs, Init *rhs, RecTy *Type); + void Profile(FoldingSetNodeID &ID) const; + // Clone - Clone this operator, replacing arguments with the new list OpInit *clone(std::vector<Init *> &Operands) const override { assert(Operands.size() == 3 && @@ -834,7 +908,7 @@ public: std::string getAsString() const override; }; -/// VarInit - 'Opcode' - Represent a reference to an entire variable object. +/// 'Opcode' - Represent a reference to an entire variable object. /// class VarInit : public TypedInit { Init *VarName; @@ -865,7 +939,7 @@ public: Init *getFieldInit(Record &R, const RecordVal *RV, const std::string &FieldName) const override; - /// resolveReferences - This method is used by classes that refer to other + /// This method is used by classes that refer to other /// variables which may not be defined at the time they expression is formed. /// If a value is set for the variable later, this method will be called on /// users of the value to allow the value to propagate out. @@ -877,7 +951,7 @@ public: std::string getAsString() const override { return getName(); } }; -/// VarBitInit - Opcode{0} - Represent access to one bit of a variable or field. +/// Opcode{0} - Represent access to one bit of a variable or field. /// class VarBitInit : public Init { TypedInit *TI; @@ -914,7 +988,7 @@ public: } }; -/// VarListElementInit - List[4] - Represent access to one element of a var or +/// List[4] - Represent access to one element of a var or /// field. class VarListElementInit : public TypedInit { TypedInit *TI; @@ -940,7 +1014,7 @@ public: TypedInit *getVariable() const { return TI; } unsigned getElementNum() const { return Element; } - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. Init *resolveListElementReference(Record &R, const RecordVal *RV, @@ -952,7 +1026,7 @@ public: Init *getBit(unsigned Bit) const override; }; -/// DefInit - AL - Represent a reference to a 'def' in the description +/// AL - Represent a reference to a 'def' in the description /// class DefInit : public TypedInit { Record *Def; @@ -985,7 +1059,7 @@ public: llvm_unreachable("Illegal bit reference off def"); } - /// resolveListElementReference - This method is used to implement + /// This method is used to implement /// VarListElementInit::resolveReferences. If the list element is resolvable /// now, we return the resolved value, otherwise we return null. Init *resolveListElementReference(Record &R, const RecordVal *RV, @@ -994,7 +1068,7 @@ public: } }; -/// FieldInit - X.Y - Represent a reference to a subfield of a variable +/// X.Y - Represent a reference to a subfield of a variable /// class FieldInit : public TypedInit { Init *Rec; // Record we are referring to @@ -1026,7 +1100,7 @@ public: } }; -/// DagInit - (v a, b) - Represent a DAG tree value. DAG inits are required +/// (v a, b) - Represent a DAG tree value. DAG inits are required /// to have at least one value then a (possibly empty) list of arguments. Each /// argument can have a name associated with it. /// @@ -1148,21 +1222,22 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RecordVal &RV) { class Record { static unsigned LastID; - // Unique record ID. - unsigned ID; Init *Name; // Location where record was instantiated, followed by the location of // multiclass prototypes used. SmallVector<SMLoc, 4> Locs; - std::vector<Init *> TemplateArgs; - std::vector<RecordVal> Values; - std::vector<Record *> SuperClasses; - std::vector<SMRange> SuperClassRanges; + SmallVector<Init *, 0> TemplateArgs; + SmallVector<RecordVal, 0> Values; + SmallVector<std::pair<Record *, SMRange>, 0> SuperClasses; // Tracks Record instances. Not owned by Record. RecordKeeper &TrackedRecords; std::unique_ptr<DefInit> TheInit; + + // Unique record ID. + unsigned ID; + bool IsAnonymous; // Class-instance values can be used by other defs. For example, Struct<i> @@ -1184,8 +1259,8 @@ public: // Constructs a record. explicit Record(Init *N, ArrayRef<SMLoc> locs, RecordKeeper &records, bool Anonymous = false) : - ID(LastID++), Name(N), Locs(locs.begin(), locs.end()), - TrackedRecords(records), IsAnonymous(Anonymous), ResolveFirst(false) { + Name(N), Locs(locs.begin(), locs.end()), TrackedRecords(records), + ID(LastID++), IsAnonymous(Anonymous), ResolveFirst(false) { init(); } explicit Record(const std::string &N, ArrayRef<SMLoc> locs, @@ -1197,11 +1272,10 @@ public: // ID number. Don't copy TheInit either since it's owned by the original // record. All other fields can be copied normally. Record(const Record &O) : - ID(LastID++), Name(O.Name), Locs(O.Locs), TemplateArgs(O.TemplateArgs), + Name(O.Name), Locs(O.Locs), TemplateArgs(O.TemplateArgs), Values(O.Values), SuperClasses(O.SuperClasses), - SuperClassRanges(O.SuperClassRanges), TrackedRecords(O.TrackedRecords), - IsAnonymous(O.IsAnonymous), - ResolveFirst(O.ResolveFirst) { } + TrackedRecords(O.TrackedRecords), ID(LastID++), + IsAnonymous(O.IsAnonymous), ResolveFirst(O.ResolveFirst) { } static unsigned getNewUID() { return LastID++; } @@ -1227,8 +1301,9 @@ public: return TemplateArgs; } ArrayRef<RecordVal> getValues() const { return Values; } - ArrayRef<Record *> getSuperClasses() const { return SuperClasses; } - ArrayRef<SMRange> getSuperClassRanges() const { return SuperClassRanges; } + ArrayRef<std::pair<Record *, SMRange>> getSuperClasses() const { + return SuperClasses; + } bool isTemplateArg(Init *Name) const { for (Init *TA : TemplateArgs) @@ -1290,31 +1365,35 @@ public: } bool isSubClassOf(const Record *R) const { - for (const Record *SC : SuperClasses) - if (SC == R) + for (const auto &SCPair : SuperClasses) + if (SCPair.first == R) return true; return false; } bool isSubClassOf(StringRef Name) const { - for (const Record *SC : SuperClasses) - if (SC->getNameInitAsString() == Name) + for (const auto &SCPair : SuperClasses) { + if (const auto *SI = dyn_cast<StringInit>(SCPair.first->getNameInit())) { + if (SI->getValue() == Name) + return true; + } else if (SCPair.first->getNameInitAsString() == Name) { return true; + } + } return false; } void addSuperClass(Record *R, SMRange Range) { assert(!isSubClassOf(R) && "Already subclassing record!"); - SuperClasses.push_back(R); - SuperClassRanges.push_back(Range); + SuperClasses.push_back(std::make_pair(R, Range)); } - /// resolveReferences - If there are any field references that refer to fields + /// If there are any field references that refer to fields /// that have been filled in, we can propagate the values now. /// void resolveReferences() { resolveReferencesTo(nullptr); } - /// resolveReferencesTo - If anything in this record refers to RV, replace the + /// If anything in this record refers to RV, replace the /// reference to RV with the RHS of RV. If RV is null, we resolve all /// possible references. void resolveReferencesTo(const RecordVal *RV); @@ -1341,7 +1420,7 @@ public: // High-level methods useful to tablegen back-ends // - /// getValueInit - Return the initializer for a value with the specified name, + /// Return the initializer for a value with the specified name, /// or throw an exception if the field does not exist. /// Init *getValueInit(StringRef FieldName) const; @@ -1351,67 +1430,67 @@ public: return isa<UnsetInit>(getValueInit(FieldName)); } - /// getValueAsString - This method looks up the specified field and returns + /// This method looks up the specified field and returns /// its value as a string, throwing an exception if the field does not exist /// or if the value is not a string. /// std::string getValueAsString(StringRef FieldName) const; - /// getValueAsBitsInit - This method looks up the specified field and returns + /// This method looks up the specified field and returns /// its value as a BitsInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// BitsInit *getValueAsBitsInit(StringRef FieldName) const; - /// getValueAsListInit - This method looks up the specified field and returns + /// This method looks up the specified field and returns /// its value as a ListInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// ListInit *getValueAsListInit(StringRef FieldName) const; - /// getValueAsListOfDefs - This method looks up the specified field and + /// This method looks up the specified field and /// returns its value as a vector of records, throwing an exception if the /// field does not exist or if the value is not the right type. /// std::vector<Record*> getValueAsListOfDefs(StringRef FieldName) const; - /// getValueAsListOfInts - This method looks up the specified field and + /// This method looks up the specified field and /// returns its value as a vector of integers, throwing an exception if the /// field does not exist or if the value is not the right type. /// std::vector<int64_t> getValueAsListOfInts(StringRef FieldName) const; - /// getValueAsListOfStrings - This method looks up the specified field and + /// This method looks up the specified field and /// returns its value as a vector of strings, throwing an exception if the /// field does not exist or if the value is not the right type. /// std::vector<std::string> getValueAsListOfStrings(StringRef FieldName) const; - /// getValueAsDef - This method looks up the specified field and returns its + /// This method looks up the specified field and returns its /// value as a Record, throwing an exception if the field does not exist or if /// the value is not the right type. /// Record *getValueAsDef(StringRef FieldName) const; - /// getValueAsBit - This method looks up the specified field and returns its + /// This method looks up the specified field and returns its /// value as a bit, throwing an exception if the field does not exist or if /// the value is not the right type. /// bool getValueAsBit(StringRef FieldName) const; - /// getValueAsBitOrUnset - This method looks up the specified field and + /// This method looks up the specified field and /// returns its value as a bit. If the field is unset, sets Unset to true and /// returns false. /// bool getValueAsBitOrUnset(StringRef FieldName, bool &Unset) const; - /// getValueAsInt - This method looks up the specified field and returns its + /// This method looks up the specified field and returns its /// value as an int64_t, throwing an exception if the field does not exist or /// if the value is not the right type. /// int64_t getValueAsInt(StringRef FieldName) const; - /// getValueAsDag - This method looks up the specified field and returns its + /// This method looks up the specified field and returns its /// value as an Dag, throwing an exception if the field does not exist or if /// the value is not the right type. /// @@ -1463,16 +1542,16 @@ public: //===--------------------------------------------------------------------===// // High-level helper methods, useful for tablegen backends... - /// getAllDerivedDefinitions - This method returns all concrete definitions - /// that derive from the specified class name. If a class with the specified - /// name does not exist, an exception is thrown. - std::vector<Record*> + /// This method returns all concrete definitions + /// that derive from the specified class name. A class with the specified + /// name must exist. + std::vector<Record *> getAllDerivedDefinitions(const std::string &ClassName) const; void dump() const; }; -/// LessRecord - Sorting predicate to sort record pointers by name. +/// Sorting predicate to sort record pointers by name. /// struct LessRecord { bool operator()(const Record *Rec1, const Record *Rec2) const { @@ -1480,7 +1559,7 @@ struct LessRecord { } }; -/// LessRecordByID - Sorting predicate to sort record pointers by their +/// Sorting predicate to sort record pointers by their /// unique ID. If you just need a deterministic order, use this, since it /// just compares two `unsigned`; the other sorting predicates require /// string manipulation. @@ -1490,7 +1569,7 @@ struct LessRecordByID { } }; -/// LessRecordFieldName - Sorting predicate to sort record pointers by their +/// Sorting predicate to sort record pointers by their /// name field. /// struct LessRecordFieldName { @@ -1580,12 +1659,12 @@ struct LessRecordRegister { raw_ostream &operator<<(raw_ostream &OS, const RecordKeeper &RK); -/// QualifyName - Return an Init with a qualifier prefix referring +/// Return an Init with a qualifier prefix referring /// to CurRec's name. Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, Init *Name, const std::string &Scoper); -/// QualifyName - Return an Init with a qualifier prefix referring +/// Return an Init with a qualifier prefix referring /// to CurRec's name. Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, const std::string &Name, const std::string &Scoper); diff --git a/include/llvm/TableGen/SearchableTable.td b/include/llvm/TableGen/SearchableTable.td new file mode 100644 index 000000000000..12aaf6000c31 --- /dev/null +++ b/include/llvm/TableGen/SearchableTable.td @@ -0,0 +1,41 @@ +//===- SearchableTable.td ----------------------------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the key top-level classes needed to produce a reasonably +// generic table that can be binary-searched via int and string entries. +// +// Each table must instantiate "Mappingkind", listing the fields that should be +// included and fields that shoould be searchable. Only two kinds of fields are +// searchable at the moment: "strings" (which are compared case-insensitively), +// and "bits". +// +// For each "MappingKind" the generated header will create GET_MAPPINGKIND_DECL +// and GET_MAPPINGKIND_IMPL guards. +// +// Inside the DECL guard will be a set of function declarations: +// "lookup{InstanceClass}By{SearchableField}", returning "const {InstanceClass} +// *" and accepting either a StringRef or a uintN_t. Additionally, if +// EnumNameField is still defined, there will be an "enum {InstanceClass}Values" +// allowing C++ code to reference either the primary data table's entries (if +// EnumValueField is not defined) or some other field (e.g. encoding) if it is. +// +// Inside the IMPL guard will be a primary data table "{InstanceClass}sList" and +// as many searchable indexes as requested +// ("{InstanceClass}sBy{SearchableField}"). Additionally implementations of the +// lookup function will be provided. +// +// See AArch64SystemOperands.td and its generated header for example uses. +// +//===----------------------------------------------------------------------===// + +class SearchableTable { + list<string> SearchableFields; + string EnumNameField = "Name"; + string EnumValueField; +} diff --git a/include/llvm/TableGen/StringToOffsetTable.h b/include/llvm/TableGen/StringToOffsetTable.h index e3277036dc76..e5b61ed1195e 100644 --- a/include/llvm/TableGen/StringToOffsetTable.h +++ b/include/llvm/TableGen/StringToOffsetTable.h @@ -76,6 +76,26 @@ public: } O << "\""; } + + /// Emit the string using character literals. MSVC has a limitation that + /// string literals cannot be longer than 64K. + void EmitCharArray(raw_ostream &O) { + assert(AggregateString.find(')') == std::string::npos && + "can't emit raw string with closing parens"); + int Count = 0; + O << ' '; + for (char C : AggregateString) { + O << " \'"; + O.write_escaped(StringRef(&C, 1)); + O << "\',"; + Count++; + if (Count > 14) { + O << "\n "; + Count = 0; + } + } + O << '\n'; + } }; } // end namespace llvm diff --git a/include/llvm/Target/GenericOpcodes.td b/include/llvm/Target/GenericOpcodes.td new file mode 100644 index 000000000000..b4d95508f0a5 --- /dev/null +++ b/include/llvm/Target/GenericOpcodes.td @@ -0,0 +1,46 @@ +//===-- GenericOpcodes.td - Opcodes used with GlobalISel ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the generic opcodes used with GlobalISel. +// After instruction selection, these opcodes should not appear. +// +//===----------------------------------------------------------------------===// + +//------------------------------------------------------------------------------ +// Binary ops. +//------------------------------------------------------------------------------ +// Generic addition. +def G_ADD : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins unknown:$src1, unknown:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +// Generic bitwise or. +def G_OR : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins unknown:$src1, unknown:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +//------------------------------------------------------------------------------ +// Branches. +//------------------------------------------------------------------------------ +// Generic unconditional branch. +def G_BR : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins unknown:$src1); + let hasSideEffects = 0; + let isBranch = 1; + let isTerminator = 1; +} + +// TODO: Add the other generic opcodes. diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index c869341c384f..c71435a2564c 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -427,6 +427,11 @@ class Instruction { // Is this instruction a pseudo instruction for use by the assembler parser. bit isAsmParserOnly = 0; + // This instruction is not expected to be queried for scheduling latencies + // and therefore needs no scheduling information even for a complete + // scheduling model. + bit hasNoSchedulingInfo = 0; + InstrItinClass Itinerary = NoItinerary;// Execution steps used for scheduling. // Scheduling information from TargetSchedule.td. @@ -605,6 +610,22 @@ class AsmOperandClass { // match failure error message. By default, use a generic "invalid operand" // diagnostic. The target AsmParser maps these codes to text. string DiagnosticType = ""; + + /// Set to 1 if this operand is optional and not always required. Typically, + /// the AsmParser will emit an error when it finishes parsing an + /// instruction if it hasn't matched all the operands yet. However, this + /// error will be suppressed if all of the remaining unmatched operands are + /// marked as IsOptional. + /// + /// Optional arguments must be at the end of the operand list. + bit IsOptional = 0; + + /// The name of the method on the target specific asm parser that returns the + /// default operand for this optional operand. This method is only used if + /// IsOptional == 1. If not set, this will default to "defaultFooOperands", + /// where Foo is the AsmOperandClass name. The method signature should be: + /// std::unique_ptr<MCParsedAsmOperand> defaultFooOperands() const; + string DefaultMethod = ?; } def ImmAsmOperand : AsmOperandClass { @@ -756,9 +777,10 @@ class InstrInfo { // Standard Pseudo Instructions. // This list must match TargetOpcodes.h and CodeGenTarget.cpp. // Only these instructions are allowed in the TargetOpcode namespace. -let isCodeGenOnly = 1, isPseudo = 1, Namespace = "TargetOpcode" in { +let isCodeGenOnly = 1, isPseudo = 1, hasNoSchedulingInfo = 1, + Namespace = "TargetOpcode" in { def PHI : Instruction { - let OutOperandList = (outs); + let OutOperandList = (outs unknown:$dst); let InOperandList = (ins variable_ops); let AsmString = "PHINODE"; } @@ -848,6 +870,7 @@ def COPY : Instruction { let AsmString = ""; let hasSideEffects = 0; let isAsCheapAsAMove = 1; + let hasNoSchedulingInfo = 0; } def BUNDLE : Instruction { let OutOperandList = (outs); @@ -912,7 +935,36 @@ def FAULTING_LOAD_OP : Instruction { let InOperandList = (ins variable_ops); let usesCustomInserter = 1; let mayLoad = 1; + let isTerminator = 1; + let isBranch = 1; } +def PATCHABLE_OP : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins variable_ops); + let usesCustomInserter = 1; + let mayLoad = 1; + let mayStore = 1; + let hasSideEffects = 1; +} +def PATCHABLE_FUNCTION_ENTER : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = "# XRay Function Enter."; + let usesCustomInserter = 1; + let hasSideEffects = 0; +} +def PATCHABLE_RET : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins variable_ops); + let AsmString = "# XRay Function Exit."; + let usesCustomInserter = 1; + let hasSideEffects = 1; + let isReturn = 1; +} + +// Generic opcodes used in GlobalISel. +include "llvm/Target/GenericOpcodes.td" + } //===----------------------------------------------------------------------===// @@ -937,6 +989,14 @@ class AsmParser { // written register name matcher bit ShouldEmitMatchRegisterName = 1; + // Set to true if the target needs a generated 'alternative register name' + // matcher. + // + // This generates a function which can be used to lookup registers from + // their aliases. This function will fail when called on targets where + // several registers share the same alias (i.e. not a 1:1 mapping). + bit ShouldEmitMatchRegisterAltName = 0; + // HasMnemonicFirst - Set to false if target instructions don't always // start with a mnemonic as the first token. bit HasMnemonicFirst = 1; diff --git a/include/llvm/Target/TargetCallingConv.h b/include/llvm/Target/TargetCallingConv.h index 0c6c1f1468c4..19d8917f17d3 100644 --- a/include/llvm/Target/TargetCallingConv.h +++ b/include/llvm/Target/TargetCallingConv.h @@ -17,8 +17,7 @@ #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" -#include <string> -#include <limits.h> +#include <climits> namespace llvm { @@ -48,6 +47,10 @@ namespace ISD { static const uint64_t InAllocaOffs = 12; static const uint64_t SplitEnd = 1ULL<<13; ///< Last part of a split static const uint64_t SplitEndOffs = 13; + static const uint64_t SwiftSelf = 1ULL<<14; ///< Swift self parameter + static const uint64_t SwiftSelfOffs = 14; + static const uint64_t SwiftError = 1ULL<<15; ///< Swift error parameter + static const uint64_t SwiftErrorOffs = 15; static const uint64_t OrigAlign = 0x1FULL<<27; static const uint64_t OrigAlignOffs = 27; static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size @@ -60,6 +63,7 @@ namespace ISD { static const uint64_t One = 1ULL; ///< 1 of this type, for shifts uint64_t Flags; + public: ArgFlagsTy() : Flags(0) { } @@ -81,6 +85,12 @@ namespace ISD { bool isInAlloca() const { return Flags & InAlloca; } void setInAlloca() { Flags |= One << InAllocaOffs; } + bool isSwiftSelf() const { return Flags & SwiftSelf; } + void setSwiftSelf() { Flags |= One << SwiftSelfOffs; } + + bool isSwiftError() const { return Flags & SwiftError; } + void setSwiftError() { Flags |= One << SwiftErrorOffs; } + bool isNest() const { return Flags & Nest; } void setNest() { Flags |= One << NestOffs; } @@ -195,8 +205,8 @@ namespace ISD { ArgVT = argvt; } }; -} +} // end namespace ISD } // end llvm namespace -#endif +#endif // LLVM_TARGET_TARGETCALLINGCONV_H diff --git a/include/llvm/Target/TargetCallingConv.td b/include/llvm/Target/TargetCallingConv.td index 2e766c448b34..3d8639dfe1da 100644 --- a/include/llvm/Target/TargetCallingConv.td +++ b/include/llvm/Target/TargetCallingConv.td @@ -42,6 +42,16 @@ class CCIf<string predicate, CCAction A> : CCPredicateAction<A> { class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> { } +/// CCIfSwiftSelf - If the current argument has swiftself parameter attribute, +/// apply Action A. +class CCIfSwiftSelf<CCAction A> : CCIf<"ArgFlags.isSwiftSelf()", A> { +} + +/// CCIfSwiftError - If the current argument has swifterror parameter attribute, +/// apply Action A. +class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> { +} + /// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs /// parameter attribute, apply Action A. class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> { diff --git a/include/llvm/Target/TargetFrameLowering.h b/include/llvm/Target/TargetFrameLowering.h index cadd07d71f12..98065aca16f3 100644 --- a/include/llvm/Target/TargetFrameLowering.h +++ b/include/llvm/Target/TargetFrameLowering.h @@ -75,9 +75,9 @@ public: /// int alignSPAdjust(int SPAdj) const { if (SPAdj < 0) { - SPAdj = -RoundUpToAlignment(-SPAdj, StackAlignment); + SPAdj = -alignTo(-SPAdj, StackAlignment); } else { - SPAdj = RoundUpToAlignment(SPAdj, StackAlignment); + SPAdj = alignTo(SPAdj, StackAlignment); } return SPAdj; } @@ -151,6 +151,13 @@ public: return false; } + /// Returns true if the stack slot holes in the fixed and callee-save stack + /// area should be used when allocating other stack locations to reduce stack + /// size. + virtual bool enableStackSlotScavenging(const MachineFunction &MF) const { + return false; + } + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. virtual void emitPrologue(MachineFunction &MF, @@ -239,15 +246,17 @@ public: virtual int getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const; - /// Same as above, except that the 'base register' will always be RSP, not - /// RBP on x86. This is generally used for emitting statepoint or EH tables - /// that use offsets from RSP. - /// TODO: This should really be a parameterizable choice. - virtual int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, - unsigned &FrameReg) const { - // default to calling normal version, we override this on x86 only - llvm_unreachable("unimplemented for non-x86"); - return 0; + /// Same as \c getFrameIndexReference, except that the stack pointer (as + /// opposed to the frame pointer) will be the preferred value for \p + /// FrameReg. This is generally used for emitting statepoint or EH tables that + /// use offsets from RSP. If \p IgnoreSPUpdates is true, the returned + /// offset is only guaranteed to be valid with respect to the value of SP at + /// the end of the prologue. + virtual int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI, + unsigned &FrameReg, + bool IgnoreSPUpdates) const { + // Always safe to dispatch to getFrameIndexReference. + return getFrameIndexReference(MF, FI, FrameReg); } /// This method determines which of the registers reported by @@ -273,14 +282,13 @@ public: report_fatal_error("WinEH not implemented for this target"); } - /// eliminateCallFramePseudoInstr - This method is called during prolog/epilog - /// code insertion to eliminate call frame setup and destroy pseudo - /// instructions (but only if the Target is using them). It is responsible - /// for eliminating these instructions, replacing them with concrete - /// instructions. This method need only be implemented if using call frame - /// setup/destroy pseudo instructions. - /// - virtual void + /// This method is called during prolog/epilog code insertion to eliminate + /// call frame setup and destroy pseudo instructions (but only if the Target + /// is using them). It is responsible for eliminating these instructions, + /// replacing them with concrete instructions. This method need only be + /// implemented if using call frame setup/destroy pseudo instructions. + /// Returns an iterator pointing to the instruction after the replaced one. + virtual MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { @@ -288,6 +296,18 @@ public: "target!"); } + + /// Order the symbols in the local stack frame. + /// The list of objects that we want to order is in \p objectsToAllocate as + /// indices into the MachineFrameInfo. The array can be reordered in any way + /// upon return. The contents of the array, however, may not be modified (i.e. + /// only their order may be changed). + /// By default, just maintain the original order. + virtual void + orderFrameObjects(const MachineFunction &MF, + SmallVectorImpl<int> &objectsToAllocate) const { + } + /// Check whether or not the given \p MBB can be used as a prologue /// for the target. /// The prologue will be inserted first in this basic block. @@ -311,6 +331,20 @@ public: virtual bool canUseAsEpilogue(const MachineBasicBlock &MBB) const { return true; } + + /// Check if given function is safe for not having callee saved registers. + /// This is used when interprocedural register allocation is enabled. + static bool isSafeForNoCSROpt(const Function *F) { + if (!F->hasLocalLinkage() || F->hasAddressTaken() || + !F->hasFnAttribute(Attribute::NoRecurse)) + return false; + // Function should not be optimized as tail call. + for (const User *U : F->users()) + if (auto CS = ImmutableCallSite(U)) + if (CS.isTailCall()) + return false; + return true; + } }; } // End llvm namespace diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h index 0cebcf1c6b5d..e0b9a22ed5d0 100644 --- a/include/llvm/Target/TargetInstrInfo.h +++ b/include/llvm/Target/TargetInstrInfo.h @@ -21,6 +21,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" namespace llvm { @@ -45,7 +46,6 @@ class DFAPacketizer; template<class T> class SmallVectorImpl; - //--------------------------------------------------------------------------- /// /// TargetInstrInfo - Interface to description of machine instruction set @@ -55,10 +55,11 @@ class TargetInstrInfo : public MCInstrInfo { void operator=(const TargetInstrInfo &) = delete; public: TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, - unsigned CatchRetOpcode = ~0u) + unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u) : CallFrameSetupOpcode(CFSetupOpcode), CallFrameDestroyOpcode(CFDestroyOpcode), - CatchRetOpcode(CatchRetOpcode) {} + CatchRetOpcode(CatchRetOpcode), + ReturnOpcode(ReturnOpcode) {} virtual ~TargetInstrInfo(); @@ -78,10 +79,10 @@ public: /// This means the only allowed uses are constants and unallocatable physical /// registers so that the instructions result is independent of the place /// in the function. - bool isTriviallyReMaterializable(const MachineInstr *MI, + bool isTriviallyReMaterializable(const MachineInstr &MI, AliasAnalysis *AA = nullptr) const { - return MI->getOpcode() == TargetOpcode::IMPLICIT_DEF || - (MI->getDesc().isRematerializable() && + return MI.getOpcode() == TargetOpcode::IMPLICIT_DEF || + (MI.getDesc().isRematerializable() && (isReallyTriviallyReMaterializable(MI, AA) || isReallyTriviallyReMaterializableGeneric(MI, AA))); } @@ -94,7 +95,7 @@ protected: /// than producing a value, or if it requres any address registers that are /// not always available. /// Requirements must be check as stated in isTriviallyReMaterializable() . - virtual bool isReallyTriviallyReMaterializable(const MachineInstr *MI, + virtual bool isReallyTriviallyReMaterializable(const MachineInstr &MI, AliasAnalysis *AA) const { return false; } @@ -114,8 +115,7 @@ protected: /// Do not call this method for a non-commutable instruction. /// Even though the instruction is commutable, the method may still /// fail to commute the operands, null pointer is returned in such cases. - virtual MachineInstr *commuteInstructionImpl(MachineInstr *MI, - bool NewMI, + virtual MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const; @@ -139,7 +139,7 @@ private: /// set and the target hook isReallyTriviallyReMaterializable returns false, /// this function does target-independent tests to determine if the /// instruction is really trivially rematerializable. - bool isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI, + bool isReallyTriviallyReMaterializableGeneric(const MachineInstr &MI, AliasAnalysis *AA) const; public: @@ -152,12 +152,13 @@ public: unsigned getCallFrameDestroyOpcode() const { return CallFrameDestroyOpcode; } unsigned getCatchReturnOpcode() const { return CatchRetOpcode; } + unsigned getReturnOpcode() const { return ReturnOpcode; } /// Returns the actual stack pointer adjustment made by an instruction /// as part of a call sequence. By default, only call frame setup/destroy /// instructions adjust the stack, but targets may want to override this /// to enable more fine-grained adjustment, or adjust by a different value. - virtual int getSPAdjust(const MachineInstr *MI) const; + virtual int getSPAdjust(const MachineInstr &MI) const; /// Return true if the instruction is a "coalescable" extension instruction. /// That is, it's like a copy where it's legal for the source to overlap the @@ -175,14 +176,14 @@ public: /// the destination along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than loading from the stack slot. - virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + virtual unsigned isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const { return 0; } /// Check for post-frame ptr elimination stack locations as well. /// This uses a heuristic so it isn't reliable for correctness. - virtual unsigned isLoadFromStackSlotPostFE(const MachineInstr *MI, + virtual unsigned isLoadFromStackSlotPostFE(const MachineInstr &MI, int &FrameIndex) const { return 0; } @@ -193,7 +194,7 @@ public: /// If not, return false. Unlike isLoadFromStackSlot, this returns true for /// any instructions that loads from the stack. This is just a hint, as some /// cases may be missed. - virtual bool hasLoadFromStackSlot(const MachineInstr *MI, + virtual bool hasLoadFromStackSlot(const MachineInstr &MI, const MachineMemOperand *&MMO, int &FrameIndex) const; @@ -202,14 +203,14 @@ public: /// the source reg along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than storing to the stack slot. - virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + virtual unsigned isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const { return 0; } /// Check for post-frame ptr elimination stack locations as well. /// This uses a heuristic, so it isn't reliable for correctness. - virtual unsigned isStoreToStackSlotPostFE(const MachineInstr *MI, + virtual unsigned isStoreToStackSlotPostFE(const MachineInstr &MI, int &FrameIndex) const { return 0; } @@ -220,14 +221,14 @@ public: /// If not, return false. Unlike isStoreToStackSlot, /// this returns true for any instructions that stores to the /// stack. This is just a hint, as some cases may be missed. - virtual bool hasStoreToStackSlot(const MachineInstr *MI, + virtual bool hasStoreToStackSlot(const MachineInstr &MI, const MachineMemOperand *&MMO, int &FrameIndex) const; /// Return true if the specified machine instruction /// is a copy of one stack slot to another and has no other effect. /// Provide the identity of the two frame indices. - virtual bool isStackSlotCopy(const MachineInstr *MI, int &DestFrameIndex, + virtual bool isStackSlotCopy(const MachineInstr &MI, int &DestFrameIndex, int &SrcFrameIndex) const { return false; } @@ -253,8 +254,20 @@ public: /// /// Targets for different archs need to override this, and different /// micro-architectures can also be finely tuned inside. - virtual bool isAsCheapAsAMove(const MachineInstr *MI) const { - return MI->isAsCheapAsAMove(); + virtual bool isAsCheapAsAMove(const MachineInstr &MI) const { + return MI.isAsCheapAsAMove(); + } + + /// Return true if the instruction should be sunk by MachineSink. + /// + /// MachineSink determines on its own whether the instruction is safe to sink; + /// this gives the target a hook to override the default behavior with regards + /// to which instructions should be sunk. + /// The default behavior is to not sink insert_subreg, subreg_to_reg, and + /// reg_sequence. These are meant to be close to the source to make it easier + /// to coalesce. + virtual bool shouldSink(const MachineInstr &MI) const { + return !MI.isInsertSubreg() && !MI.isSubregToReg() && !MI.isRegSequence(); } /// Re-issue the specified 'original' instruction at the @@ -263,9 +276,8 @@ public: /// DestReg:SubIdx. Any existing subreg index is preserved or composed with /// SubIdx. virtual void reMaterialize(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, unsigned SubIdx, - const MachineInstr *Orig, + MachineBasicBlock::iterator MI, unsigned DestReg, + unsigned SubIdx, const MachineInstr &Orig, const TargetRegisterInfo &TRI) const; /// Create a duplicate of the Orig instruction in MF. This is like @@ -273,7 +285,7 @@ public: /// that are required to be unique. /// /// The instruction must be duplicable as indicated by isNotDuplicable(). - virtual MachineInstr *duplicate(MachineInstr *Orig, + virtual MachineInstr *duplicate(MachineInstr &Orig, MachineFunction &MF) const; /// This method must be implemented by targets that @@ -286,9 +298,9 @@ public: /// This method returns a null pointer if the transformation cannot be /// performed, otherwise it returns the last new instruction. /// - virtual MachineInstr * - convertToThreeAddress(MachineFunction::iterator &MFI, - MachineBasicBlock::iterator &MBBI, LiveVariables *LV) const { + virtual MachineInstr *convertToThreeAddress(MachineFunction::iterator &MFI, + MachineInstr &MI, + LiveVariables *LV) const { return nullptr; } @@ -315,8 +327,7 @@ public: /// Even though the instruction is commutable, the method may still /// fail to commute the operands, null pointer is returned in such cases. MachineInstr * - commuteInstruction(MachineInstr *MI, - bool NewMI = false, + commuteInstruction(MachineInstr &MI, bool NewMI = false, unsigned OpIdx1 = CommuteAnyOperandIndex, unsigned OpIdx2 = CommuteAnyOperandIndex) const; @@ -337,7 +348,7 @@ public: /// findCommutedOpIndices(MI, Op1, Op2); /// can be interpreted as a query asking to find an operand that would be /// commutable with the operand#1. - virtual bool findCommutedOpIndices(MachineInstr *MI, unsigned &SrcOpIdx1, + virtual bool findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const; /// A pair composed of a register and a sub-register index. @@ -424,8 +435,8 @@ public: /// are deemed identical except for defs. If this function is called when the /// IR is still in SSA form, the caller can pass the MachineRegisterInfo for /// aggressive checks. - virtual bool produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1, + virtual bool produceSameValue(const MachineInstr &MI0, + const MachineInstr &MI1, const MachineRegisterInfo *MRI = nullptr) const; /// Analyze the branching code at the end of MBB, returning @@ -453,7 +464,9 @@ public: /// If AllowModify is true, then this routine is allowed to modify the basic /// block (e.g. delete instructions after the unconditional branch). /// - virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + /// The CFG information in MBB.Predecessors and MBB.Successors must be valid + /// before calling this function. + virtual bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, bool AllowModify = false) const { @@ -499,7 +512,7 @@ public: /// If AllowModify is true, then this routine is allowed to modify the basic /// block (e.g. delete instructions after the unconditional branch). /// - virtual bool AnalyzeBranchPredicate(MachineBasicBlock &MBB, + virtual bool analyzeBranchPredicate(MachineBasicBlock &MBB, MachineBranchPredicate &MBP, bool AllowModify = false) const { return true; @@ -522,10 +535,13 @@ public: /// cases where AnalyzeBranch doesn't apply because there was no original /// branch to analyze. At least this much must be implemented, else tail /// merging needs to be disabled. + /// + /// The CFG information in MBB.Predecessors and MBB.Successors must be valid + /// before calling this function. virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, - DebugLoc DL) const { + const DebugLoc &DL) const { llvm_unreachable("Target didn't implement TargetInstrInfo::InsertBranch!"); } @@ -672,7 +688,7 @@ public: /// @param TrueReg Virtual register to copy when Cond is true. /// @param FalseReg Virtual register to copy when Cons is false. virtual void insertSelect(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, DebugLoc DL, + MachineBasicBlock::iterator I, const DebugLoc &DL, unsigned DstReg, ArrayRef<MachineOperand> Cond, unsigned TrueReg, unsigned FalseReg) const { llvm_unreachable("Target didn't implement TargetInstrInfo::insertSelect!"); @@ -696,11 +712,11 @@ public: /// @param FalseOp Operand number of the value selected when Cond is false. /// @param Optimizable Returned as true if MI is optimizable. /// @returns False on success. - virtual bool analyzeSelect(const MachineInstr *MI, + virtual bool analyzeSelect(const MachineInstr &MI, SmallVectorImpl<MachineOperand> &Cond, unsigned &TrueOp, unsigned &FalseOp, bool &Optimizable) const { - assert(MI && MI->getDesc().isSelect() && "MI must be a select instruction"); + assert(MI.getDesc().isSelect() && "MI must be a select instruction"); return true; } @@ -719,7 +735,7 @@ public: /// MI. Has to be updated with any newly created MI or deleted ones. /// @param PreferFalse Try to optimize FalseOp instead of TrueOp. /// @returns Optimized instruction or NULL. - virtual MachineInstr *optimizeSelect(MachineInstr *MI, + virtual MachineInstr *optimizeSelect(MachineInstr &MI, SmallPtrSetImpl<MachineInstr *> &NewMIs, bool PreferFalse = false) const { // This function must be implemented if Optimizable is ever set. @@ -735,7 +751,7 @@ public: /// careful implementation when multiple copy instructions are required for /// large registers. See for example the ARM target. virtual void copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, DebugLoc DL, + MachineBasicBlock::iterator MI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { llvm_unreachable("Target didn't implement TargetInstrInfo::copyPhysReg!"); @@ -772,9 +788,7 @@ public: /// into real instructions. The target can edit MI in place, or it can insert /// new instructions and erase MI. The function should return true if /// anything was changed. - virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const { - return false; - } + virtual bool expandPostRAPseudo(MachineInstr &MI) const { return false; } /// Attempt to fold a load or store of the specified stack /// slot into the specified machine instruction for the specified operand(s). @@ -782,14 +796,15 @@ public: /// operand folded, otherwise NULL is returned. /// The new instruction is inserted before MI, and the client is responsible /// for removing the old instruction. - MachineInstr *foldMemoryOperand(MachineBasicBlock::iterator MI, - ArrayRef<unsigned> Ops, int FrameIndex) const; + MachineInstr *foldMemoryOperand(MachineInstr &MI, ArrayRef<unsigned> Ops, + int FrameIndex, + LiveIntervals *LIS = nullptr) const; /// Same as the previous version except it allows folding of any load and /// store from / to any address, not just from a specific stack slot. - MachineInstr *foldMemoryOperand(MachineBasicBlock::iterator MI, - ArrayRef<unsigned> Ops, - MachineInstr *LoadMI) const; + MachineInstr *foldMemoryOperand(MachineInstr &MI, ArrayRef<unsigned> Ops, + MachineInstr &LoadMI, + LiveIntervals *LIS = nullptr) const; /// Return true when there is potentially a faster code sequence /// for an instruction chain ending in \p Root. All potential patterns are @@ -802,6 +817,11 @@ public: MachineInstr &Root, SmallVectorImpl<MachineCombinerPattern> &Patterns) const; + /// Return true when a code sequence can improve throughput. It + /// should be called only for instructions in loops. + /// \param Pattern - combiner pattern + virtual bool isThroughputPattern(MachineCombinerPattern Pattern) const; + /// Return true if the input \P Inst is part of a chain of dependent ops /// that are suitable for reassociation, otherwise return false. /// If the instruction's operands must be commuted to have a previous @@ -850,8 +870,7 @@ public: virtual void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2, MachineInstr &NewMI1, MachineInstr &NewMI2) const { - return; - }; + } /// Return true when a target supports MachineCombiner. virtual bool useMachineCombiner() const { return false; } @@ -862,9 +881,11 @@ protected: /// take care of adding a MachineMemOperand to the newly created instruction. /// The instruction and any auxiliary instructions necessary will be inserted /// at InsertPt. - virtual MachineInstr *foldMemoryOperandImpl( - MachineFunction &MF, MachineInstr *MI, ArrayRef<unsigned> Ops, - MachineBasicBlock::iterator InsertPt, int FrameIndex) const { + virtual MachineInstr * + foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, + ArrayRef<unsigned> Ops, + MachineBasicBlock::iterator InsertPt, int FrameIndex, + LiveIntervals *LIS = nullptr) const { return nullptr; } @@ -874,8 +895,9 @@ protected: /// The instruction and any auxiliary instructions necessary will be inserted /// at InsertPt. virtual MachineInstr *foldMemoryOperandImpl( - MachineFunction &MF, MachineInstr *MI, ArrayRef<unsigned> Ops, - MachineBasicBlock::iterator InsertPt, MachineInstr *LoadMI) const { + MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops, + MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI, + LiveIntervals *LIS = nullptr) const { return nullptr; } @@ -926,9 +948,10 @@ public: /// unfoldMemoryOperand - Separate a single instruction which folded a load or /// a store or a load and a store into two or more instruction. If this is /// possible, returns true as well as the new instructions by reference. - virtual bool unfoldMemoryOperand(MachineFunction &MF, MachineInstr *MI, - unsigned Reg, bool UnfoldLoad, bool UnfoldStore, - SmallVectorImpl<MachineInstr*> &NewMIs) const{ + virtual bool + unfoldMemoryOperand(MachineFunction &MF, MachineInstr &MI, unsigned Reg, + bool UnfoldLoad, bool UnfoldStore, + SmallVectorImpl<MachineInstr *> &NewMIs) const { return false; } @@ -974,24 +997,26 @@ public: /// Get the base register and byte offset of an instruction that reads/writes /// memory. - virtual bool getMemOpBaseRegImmOfs(MachineInstr *MemOp, unsigned &BaseReg, - unsigned &Offset, + virtual bool getMemOpBaseRegImmOfs(MachineInstr &MemOp, unsigned &BaseReg, + int64_t &Offset, const TargetRegisterInfo *TRI) const { return false; } virtual bool enableClusterLoads() const { return false; } - virtual bool shouldClusterLoads(MachineInstr *FirstLdSt, - MachineInstr *SecondLdSt, - unsigned NumLoads) const { + virtual bool enableClusterStores() const { return false; } + + virtual bool shouldClusterMemOps(MachineInstr &FirstLdSt, + MachineInstr &SecondLdSt, + unsigned NumLoads) const { return false; } /// Can this target fuse the given instructions if they are scheduled /// adjacent. - virtual bool shouldScheduleAdjacent(MachineInstr* First, - MachineInstr *Second) const { + virtual bool shouldScheduleAdjacent(MachineInstr &First, + MachineInstr &Second) const { return false; } @@ -1012,19 +1037,18 @@ public: /// Returns true if the instruction is already predicated. - virtual bool isPredicated(const MachineInstr *MI) const { + virtual bool isPredicated(const MachineInstr &MI) const { return false; } /// Returns true if the instruction is a /// terminator instruction that has not been predicated. - virtual bool isUnpredicatedTerminator(const MachineInstr *MI) const; + virtual bool isUnpredicatedTerminator(const MachineInstr &MI) const; /// Convert the instruction into a predicated instruction. /// It returns true if the operation was successful. - virtual - bool PredicateInstruction(MachineInstr *MI, - ArrayRef<MachineOperand> Pred) const; + virtual bool PredicateInstruction(MachineInstr &MI, + ArrayRef<MachineOperand> Pred) const; /// Returns true if the first specified predicate /// subsumes the second, e.g. GE subsumes GT. @@ -1037,7 +1061,7 @@ public: /// If the specified instruction defines any predicate /// or condition code register(s) used for predication, returns true as well /// as the definition predicate(s) by reference. - virtual bool DefinesPredicate(MachineInstr *MI, + virtual bool DefinesPredicate(MachineInstr &MI, std::vector<MachineOperand> &Pred) const { return false; } @@ -1045,8 +1069,8 @@ public: /// Return true if the specified instruction can be predicated. /// By default, this returns true for every instruction with a /// PredicateOperand. - virtual bool isPredicable(MachineInstr *MI) const { - return MI->getDesc().isPredicable(); + virtual bool isPredicable(MachineInstr &MI) const { + return MI.getDesc().isPredicable(); } /// Return true if it's safe to move a machine @@ -1057,7 +1081,7 @@ public: /// Test if the given instruction should be considered a scheduling boundary. /// This primarily includes labels and terminators. - virtual bool isSchedulingBoundary(const MachineInstr *MI, + virtual bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const; @@ -1084,6 +1108,13 @@ public: CreateTargetPostRAHazardRecognizer(const InstrItineraryData*, const ScheduleDAG *DAG) const; + /// Allocate and return a hazard recognizer to use for by non-scheduling + /// passes. + virtual ScheduleHazardRecognizer* + CreateTargetPostRAHazardRecognizer(const MachineFunction &MF) const { + return nullptr; + } + /// Provide a global flag for disabling the PreRA hazard recognizer that /// targets may choose to honor. bool usePreRAHazardRecognizer() const; @@ -1092,22 +1123,20 @@ public: /// in SrcReg and SrcReg2 if having two register operands, and the value it /// compares against in CmpValue. Return true if the comparison instruction /// can be analyzed. - virtual bool analyzeCompare(const MachineInstr *MI, - unsigned &SrcReg, unsigned &SrcReg2, - int &Mask, int &Value) const { + virtual bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg, + unsigned &SrcReg2, int &Mask, int &Value) const { return false; } /// See if the comparison instruction can be converted /// into something more efficient. E.g., on ARM most instructions can set the /// flags register, obviating the need for a separate CMP. - virtual bool optimizeCompareInstr(MachineInstr *CmpInstr, - unsigned SrcReg, unsigned SrcReg2, - int Mask, int Value, + virtual bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg, + unsigned SrcReg2, int Mask, int Value, const MachineRegisterInfo *MRI) const { return false; } - virtual bool optimizeCondBranch(MachineInstr *MI) const { return false; } + virtual bool optimizeCondBranch(MachineInstr &MI) const { return false; } /// Try to remove the load by folding it to a register operand at the use. /// We fold the load instructions if and only if the @@ -1116,10 +1145,10 @@ public: /// defined by the load we are trying to fold. DefMI returns the machine /// instruction that defines FoldAsLoadDefReg, and the function returns /// the machine instruction generated due to folding. - virtual MachineInstr* optimizeLoadInstr(MachineInstr *MI, - const MachineRegisterInfo *MRI, - unsigned &FoldAsLoadDefReg, - MachineInstr *&DefMI) const { + virtual MachineInstr *optimizeLoadInstr(MachineInstr &MI, + const MachineRegisterInfo *MRI, + unsigned &FoldAsLoadDefReg, + MachineInstr *&DefMI) const { return nullptr; } @@ -1129,7 +1158,7 @@ public: /// then the caller may assume that DefMI has been erased from its parent /// block. The caller may assume that it will not be erased by this /// function otherwise. - virtual bool FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, + virtual bool FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, unsigned Reg, MachineRegisterInfo *MRI) const { return false; } @@ -1139,7 +1168,7 @@ public: /// IssueWidth is the number of microops that can be dispatched each /// cycle. An instruction with zero microops takes no dispatch resources. virtual unsigned getNumMicroOps(const InstrItineraryData *ItinData, - const MachineInstr *MI) const; + const MachineInstr &MI) const; /// Return true for pseudo instructions that don't consume any /// machine resources in their current form. These are common cases that the @@ -1162,35 +1191,44 @@ public: /// by a target. Use computeOperandLatency to get the best estimate of /// latency. virtual int getOperandLatency(const InstrItineraryData *ItinData, - const MachineInstr *DefMI, unsigned DefIdx, - const MachineInstr *UseMI, + const MachineInstr &DefMI, unsigned DefIdx, + const MachineInstr &UseMI, unsigned UseIdx) const; - /// Compute and return the latency of the given data - /// dependent def and use when the operand indices are already known. + /// Compute and return the latency of the given data dependent def and use + /// when the operand indices are already known. UseMI may be \c nullptr for + /// an unknown use. + /// + /// FindMin may be set to get the minimum vs. expected latency. Minimum + /// latency is used for scheduling groups, while expected latency is for + /// instruction cost and critical path. + /// + /// Depending on the subtarget's itinerary properties, this may or may not + /// need to call getOperandLatency(). For most subtargets, we don't need + /// DefIdx or UseIdx to compute min latency. unsigned computeOperandLatency(const InstrItineraryData *ItinData, - const MachineInstr *DefMI, unsigned DefIdx, - const MachineInstr *UseMI, unsigned UseIdx) - const; + const MachineInstr &DefMI, unsigned DefIdx, + const MachineInstr *UseMI, + unsigned UseIdx) const; /// Compute the instruction latency of a given instruction. /// If the instruction has higher cost when predicated, it's returned via /// PredCost. virtual unsigned getInstrLatency(const InstrItineraryData *ItinData, - const MachineInstr *MI, + const MachineInstr &MI, unsigned *PredCost = nullptr) const; - virtual unsigned getPredicationCost(const MachineInstr *MI) const; + virtual unsigned getPredicationCost(const MachineInstr &MI) const; virtual int getInstrLatency(const InstrItineraryData *ItinData, SDNode *Node) const; - /// Return the default expected latency for a def based on it's opcode. + /// Return the default expected latency for a def based on its opcode. unsigned defaultDefLatency(const MCSchedModel &SchedModel, - const MachineInstr *DefMI) const; + const MachineInstr &DefMI) const; int computeDefOperandLatency(const InstrItineraryData *ItinData, - const MachineInstr *DefMI) const; + const MachineInstr &DefMI) const; /// Return true if this opcode has high latency to its result. virtual bool isHighLatencyDef(int opc) const { return false; } @@ -1200,23 +1238,23 @@ public: /// it 'high'. This is used by optimization passes such as machine LICM to /// determine whether it makes sense to hoist an instruction out even in a /// high register pressure situation. - virtual - bool hasHighOperandLatency(const TargetSchedModel &SchedModel, - const MachineRegisterInfo *MRI, - const MachineInstr *DefMI, unsigned DefIdx, - const MachineInstr *UseMI, unsigned UseIdx) const { + virtual bool hasHighOperandLatency(const TargetSchedModel &SchedModel, + const MachineRegisterInfo *MRI, + const MachineInstr &DefMI, unsigned DefIdx, + const MachineInstr &UseMI, + unsigned UseIdx) const { return false; } /// Compute operand latency of a def of 'Reg'. Return true /// if the target considered it 'low'. - virtual - bool hasLowDefLatency(const TargetSchedModel &SchedModel, - const MachineInstr *DefMI, unsigned DefIdx) const; + virtual bool hasLowDefLatency(const TargetSchedModel &SchedModel, + const MachineInstr &DefMI, + unsigned DefIdx) const; /// Perform target-specific instruction verification. - virtual - bool verifyInstruction(const MachineInstr *MI, StringRef &ErrInfo) const { + virtual bool verifyInstruction(const MachineInstr &MI, + StringRef &ErrInfo) const { return true; } @@ -1240,7 +1278,7 @@ public: /// execution domain. /// virtual std::pair<uint16_t, uint16_t> - getExecutionDomain(const MachineInstr *MI) const { + getExecutionDomain(const MachineInstr &MI) const { return std::make_pair(0, 0); } @@ -1248,8 +1286,7 @@ public: /// /// The bit (1 << Domain) must be set in the mask returned from /// getExecutionDomain(MI). - virtual void setExecutionDomain(MachineInstr *MI, unsigned Domain) const {} - + virtual void setExecutionDomain(MachineInstr &MI, unsigned Domain) const {} /// Returns the preferred minimum clearance /// before an instruction with an unwanted partial register update. @@ -1291,7 +1328,7 @@ public: /// allows the target to insert a dependency breaking instruction. /// virtual unsigned - getPartialRegUpdateClearance(const MachineInstr *MI, unsigned OpNum, + getPartialRegUpdateClearance(const MachineInstr &MI, unsigned OpNum, const TargetRegisterInfo *TRI) const { // The default implementation returns 0 for no partial register dependency. return 0; @@ -1311,7 +1348,7 @@ public: /// This hook works similarly to getPartialRegUpdateClearance, except that it /// does not take an operand index. Instead sets \p OpNum to the index of the /// unused register. - virtual unsigned getUndefRegClearance(const MachineInstr *MI, unsigned &OpNum, + virtual unsigned getUndefRegClearance(const MachineInstr &MI, unsigned &OpNum, const TargetRegisterInfo *TRI) const { // The default implementation returns 0 for no undef register dependency. return 0; @@ -1334,9 +1371,8 @@ public: /// An <imp-kill> operand should be added to MI if an instruction was /// inserted. This ties the instructions together in the post-ra scheduler. /// - virtual void - breakPartialRegDependency(MachineBasicBlock::iterator MI, unsigned OpNum, - const TargetRegisterInfo *TRI) const {} + virtual void breakPartialRegDependency(MachineInstr &MI, unsigned OpNum, + const TargetRegisterInfo *TRI) const {} /// Create machine specific model for scheduling. virtual DFAPacketizer * @@ -1349,11 +1385,11 @@ public: // memory addresses. This function returns true if two MIs access different // memory addresses and false otherwise. virtual bool - areMemAccessesTriviallyDisjoint(MachineInstr *MIa, MachineInstr *MIb, + areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb, AliasAnalysis *AA = nullptr) const { - assert(MIa && (MIa->mayLoad() || MIa->mayStore()) && + assert((MIa.mayLoad() || MIa.mayStore()) && "MIa must load from or modify a memory location"); - assert(MIb && (MIb->mayLoad() || MIb->mayStore()) && + assert((MIb.mayLoad() || MIb.mayStore()) && "MIb must load from or modify a memory location"); return false; } @@ -1406,6 +1442,7 @@ public: private: unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode; unsigned CatchRetOpcode; + unsigned ReturnOpcode; }; /// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair. @@ -1435,6 +1472,6 @@ struct DenseMapInfo<TargetInstrInfo::RegSubRegPair> { } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TARGET_TARGETINSTRINFO_H diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 304da4f87519..d21d3215860e 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -41,8 +41,10 @@ #include <vector> namespace llvm { + class BranchProbability; class CallInst; class CCState; + class CCValAssign; class FastISel; class FunctionLoweringInfo; class ImmutableCallSite; @@ -52,6 +54,7 @@ namespace llvm { class MachineInstr; class MachineJumpTableInfo; class MachineLoop; + class MachineRegisterInfo; class Mangler; class MCContext; class MCExpr; @@ -235,6 +238,11 @@ public: return false; } + /// Return true if the target can handle a standalone remainder operation. + virtual bool hasStandaloneRem(EVT VT) const { + return true; + } + /// Return true if sqrt(x) is as cheap or cheaper than 1 / rsqrt(x) bool isFsqrtCheap() const { return FsqrtIsCheap; @@ -259,18 +267,41 @@ public: return PredictableSelectIsExpensive; } - /// isLoadBitCastBeneficial() - Return true if the following transform - /// is beneficial. + /// If a branch or a select condition is skewed in one direction by more than + /// this factor, it is very likely to be predicted correctly. + virtual BranchProbability getPredictableBranchThreshold() const; + + /// Return true if the following transform is beneficial: /// fold (conv (load x)) -> (load (conv*)x) /// On architectures that don't natively support some vector loads /// efficiently, casting the load to a smaller vector of larger types and /// loading is more efficient, however, this can be undone by optimizations in /// dag combiner. - virtual bool isLoadBitCastBeneficial(EVT /* Load */, - EVT /* Bitcast */) const { + virtual bool isLoadBitCastBeneficial(EVT LoadVT, + EVT BitcastVT) const { + // Don't do if we could do an indexed load on the original type, but not on + // the new one. + if (!LoadVT.isSimple() || !BitcastVT.isSimple()) + return true; + + MVT LoadMVT = LoadVT.getSimpleVT(); + + // Don't bother doing this if it's just going to be promoted again later, as + // doing so might interfere with other combines. + if (getOperationAction(ISD::LOAD, LoadMVT) == Promote && + getTypeToPromoteTo(ISD::LOAD, LoadMVT) == BitcastVT.getSimpleVT()) + return false; + return true; } + /// Return true if the following transform is beneficial: + /// (store (y (conv x)), y*)) -> (store x, (x*)) + virtual bool isStoreBitCastBeneficial(EVT StoreVT, EVT BitcastVT) const { + // Default to the same logic as loads. + return isLoadBitCastBeneficial(StoreVT, BitcastVT); + } + /// Return true if it is expected to be cheaper to do a store of a non-zero /// vector constant with the given size and type for the address space than to /// store the individual scalar element constants. @@ -290,6 +321,14 @@ public: return false; } + /// Return true if it is safe to transform an integer-domain bitwise operation + /// into the equivalent floating-point operation. This should be set to true + /// if the target has IEEE-754-compliant fabs/fneg operations for the input + /// type. + virtual bool hasBitPreservingFPLogic(EVT VT) const { + return false; + } + /// \brief Return if the target supports combining a /// chain like: /// \code @@ -305,6 +344,22 @@ public: return MaskAndBranchFoldingIsLegal; } + /// Return true if the target should transform: + /// (X & Y) == Y ---> (~X & Y) == 0 + /// (X & Y) != Y ---> (~X & Y) != 0 + /// + /// This may be profitable if the target has a bitwise and-not operation that + /// sets comparison flags. A target may want to limit the transformation based + /// on the type of Y or if Y is a constant. + /// + /// Note that the transform will not occur if Y is known to be a power-of-2 + /// because a mask and compare of a single bit can be handled by inverting the + /// predicate, for example: + /// (X & 8) == 8 ---> (X & 8) != 0 + virtual bool hasAndNotCompare(SDValue Y) const { + return false; + } + /// \brief Return true if the target wants to use the optimization that /// turns ext(promotableInst1(...(promotableInstN(load)))) into /// promotedInst1(...(promotedInstN(ext(load)))). @@ -571,6 +626,23 @@ public: getOperationAction(Op, VT) == Promote); } + /// Return true if the specified operation is legal on this target or can be + /// made legal with custom lowering or using promotion. This is used to help + /// guide high-level lowering decisions. + bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT) const { + return (VT == MVT::Other || isTypeLegal(VT)) && + (getOperationAction(Op, VT) == Legal || + getOperationAction(Op, VT) == Custom || + getOperationAction(Op, VT) == Promote); + } + + /// Return true if the specified operation is illegal but has a custom lowering + /// on that type. This is used to help guide high-level lowering + /// decisions. + bool isOperationCustom(unsigned Op, EVT VT) const { + return (!isTypeLegal(VT) && getOperationAction(Op, VT) == Custom); + } + /// Return true if the specified operation is illegal on this target or /// unlikely to be made legal with custom lowering. This is used to help guide /// high-level lowering decisions. @@ -594,21 +666,20 @@ public: unsigned MemI = (unsigned) MemVT.getSimpleVT().SimpleTy; assert(ExtType < ISD::LAST_LOADEXT_TYPE && ValI < MVT::LAST_VALUETYPE && MemI < MVT::LAST_VALUETYPE && "Table isn't big enough!"); - return LoadExtActions[ValI][MemI][ExtType]; + unsigned Shift = 4 * ExtType; + return (LegalizeAction)((LoadExtActions[ValI][MemI] >> Shift) & 0xf); } /// Return true if the specified load with extension is legal on this target. bool isLoadExtLegal(unsigned ExtType, EVT ValVT, EVT MemVT) const { - return ValVT.isSimple() && MemVT.isSimple() && - getLoadExtAction(ExtType, ValVT, MemVT) == Legal; + return getLoadExtAction(ExtType, ValVT, MemVT) == Legal; } /// Return true if the specified load with extension is legal or custom /// on this target. bool isLoadExtLegalOrCustom(unsigned ExtType, EVT ValVT, EVT MemVT) const { - return ValVT.isSimple() && MemVT.isSimple() && - (getLoadExtAction(ExtType, ValVT, MemVT) == Legal || - getLoadExtAction(ExtType, ValVT, MemVT) == Custom); + return getLoadExtAction(ExtType, ValVT, MemVT) == Legal || + getLoadExtAction(ExtType, ValVT, MemVT) == Custom; } /// Return how this store with truncation should be treated: either it is @@ -626,8 +697,15 @@ public: /// Return true if the specified store with truncation is legal on this /// target. bool isTruncStoreLegal(EVT ValVT, EVT MemVT) const { - return isTypeLegal(ValVT) && MemVT.isSimple() && - getTruncStoreAction(ValVT.getSimpleVT(), MemVT.getSimpleVT()) == Legal; + return isTypeLegal(ValVT) && getTruncStoreAction(ValVT, MemVT) == Legal; + } + + /// Return true if the specified store with truncation has solution on this + /// target. + bool isTruncStoreLegalOrCustom(EVT ValVT, EVT MemVT) const { + return isTypeLegal(ValVT) && + (getTruncStoreAction(ValVT, MemVT) == Legal || + getTruncStoreAction(ValVT, MemVT) == Custom); } /// Return how the indexed load should be treated: either it is legal, needs @@ -672,7 +750,7 @@ public: LegalizeAction getCondCodeAction(ISD::CondCode CC, MVT VT) const { assert((unsigned)CC < array_lengthof(CondCodeActions) && - ((unsigned)VT.SimpleTy >> 4) < array_lengthof(CondCodeActions[0]) && + ((unsigned)VT.SimpleTy >> 3) < array_lengthof(CondCodeActions[0]) && "Table isn't big enough!"); // See setCondCodeAction for how this is encoded. uint32_t Shift = 4 * (VT.SimpleTy & 0x7); @@ -960,6 +1038,10 @@ public: return 0; } + virtual bool needsFixedCatchObjects() const { + report_fatal_error("Funclet EH is not implemented for this target"); + } + /// Returns the target's jmp_buf size in bytes (if never set, the default is /// 200) unsigned getJumpBufSize() const { @@ -992,19 +1074,26 @@ public: return PrefLoopAlignment; } - /// Return whether the DAG builder should automatically insert fences and - /// reduce ordering for atomics. - bool getInsertFencesForAtomic() const { - return InsertFencesForAtomic; - } + /// If the target has a standard location for the stack protector guard, + /// returns the address of that location. Otherwise, returns nullptr. + /// DEPRECATED: please override useLoadStackGuardNode and customize + /// LOAD_STACK_GUARD, or customize @llvm.stackguard(). + virtual Value *getIRStackGuard(IRBuilder<> &IRB) const; - /// Return true if the target stores stack protector cookies at a fixed offset - /// in some non-standard address space, and populates the address space and - /// offset as appropriate. - virtual bool getStackCookieLocation(unsigned &/*AddressSpace*/, - unsigned &/*Offset*/) const { - return false; - } + /// Inserts necessary declarations for SSP (stack protection) purpose. + /// Should be used only when getIRStackGuard returns nullptr. + virtual void insertSSPDeclarations(Module &M) const; + + /// Return the variable that's previously inserted by insertSSPDeclarations, + /// if any, otherwise return nullptr. Should be used only when + /// getIRStackGuard returns nullptr. + virtual Value *getSDagStackGuard(const Module &M) const; + + /// If the target has a standard stack protection check function that + /// performs validation and error handling, returns the function. Otherwise, + /// returns nullptr. Must be previously inserted by insertSSPDeclarations. + /// Should be used only when getIRStackGuard returns nullptr. + virtual Value *getSSPStackGuardCheck(const Module &M) const; /// If the target has a standard location for the unsafe stack pointer, /// returns the address of that location. Otherwise, returns nullptr. @@ -1041,6 +1130,30 @@ public: /// \name Helpers for atomic expansion. /// @{ + /// Returns the maximum atomic operation size (in bits) supported by + /// the backend. Atomic operations greater than this size (as well + /// as ones that are not naturally aligned), will be expanded by + /// AtomicExpandPass into an __atomic_* library call. + unsigned getMaxAtomicSizeInBitsSupported() const { + return MaxAtomicSizeInBitsSupported; + } + + /// Returns the size of the smallest cmpxchg or ll/sc instruction + /// the backend supports. Any smaller operations are widened in + /// AtomicExpandPass. + /// + /// Note that *unlike* operations above the maximum size, atomic ops + /// are still natively supported below the minimum; they just + /// require a more complex expansion. + unsigned getMinCmpXchgSizeInBits() const { return MinCmpXchgSizeInBits; } + + /// Whether AtomicExpandPass should automatically insert fences and reduce + /// ordering for this atomic. This should be true for most architectures with + /// weak memory ordering. Defaults to false. + virtual bool shouldInsertFencesForAtomic(const Instruction *I) const { + return false; + } + /// Perform a load-linked operation on Addr, returning a "Value *" with the /// corresponding pointee type. This may entail some non-trivial operations to /// truncate or reconstruct types that will be illegal in the backend. See @@ -1059,12 +1172,12 @@ public: /// Inserts in the IR a target-specific intrinsic specifying a fence. /// It is called by AtomicExpandPass before expanding an - /// AtomicRMW/AtomicCmpXchg/AtomicStore/AtomicLoad. + /// AtomicRMW/AtomicCmpXchg/AtomicStore/AtomicLoad + /// if shouldInsertFencesForAtomic returns true. /// RMW and CmpXchg set both IsStore and IsLoad to true. /// This function should either return a nullptr, or a pointer to an IR-level /// Instruction*. Even complex fence sequences can be represented by a /// single Instruction* through an intrinsic to be lowered later. - /// Backends with !getInsertFencesForAtomic() should keep a no-op here. /// Backends should override this method to produce target-specific intrinsic /// for their fences. /// FIXME: Please note that the default implementation here in terms of @@ -1090,10 +1203,7 @@ public: virtual Instruction *emitLeadingFence(IRBuilder<> &Builder, AtomicOrdering Ord, bool IsStore, bool IsLoad) const { - if (!getInsertFencesForAtomic()) - return nullptr; - - if (isAtLeastRelease(Ord) && IsStore) + if (isReleaseOrStronger(Ord) && IsStore) return Builder.CreateFence(Ord); else return nullptr; @@ -1102,10 +1212,7 @@ public: virtual Instruction *emitTrailingFence(IRBuilder<> &Builder, AtomicOrdering Ord, bool IsStore, bool IsLoad) const { - if (!getInsertFencesForAtomic()) - return nullptr; - - if (isAtLeastAcquire(Ord)) + if (isAcquireOrStronger(Ord)) return Builder.CreateFence(Ord); else return nullptr; @@ -1166,6 +1273,14 @@ public: return nullptr; } + /// Returns how the platform's atomic operations are extended (ZERO_EXTEND, + /// SIGN_EXTEND, or ANY_EXTEND). + virtual ISD::NodeType getExtendForAtomicOps() const { + return ISD::ZERO_EXTEND; + } + + /// @} + /// Returns true if we should normalize /// select(N0&N1, X, Y) => select(N0, select(N1, X, Y), Y) and /// select(N0|N1, X, Y) => select(N0, select(N1, X, Y, Y)) if it is likely @@ -1324,7 +1439,10 @@ protected: LegalizeAction Action) { assert(ExtType < ISD::LAST_LOADEXT_TYPE && ValVT.isValid() && MemVT.isValid() && "Table isn't big enough!"); - LoadExtActions[(unsigned)ValVT.SimpleTy][MemVT.SimpleTy][ExtType] = Action; + assert((unsigned)Action < 0x10 && "too many bits for bitfield array"); + unsigned Shift = 4 * ExtType; + LoadExtActions[ValVT.SimpleTy][MemVT.SimpleTy] &= ~((uint16_t)0xF << Shift); + LoadExtActions[ValVT.SimpleTy][MemVT.SimpleTy] |= (uint16_t)Action << Shift; } /// Indicate that the specified truncating store does not work with the @@ -1386,6 +1504,13 @@ protected: PromoteToType[std::make_pair(Opc, OrigVT.SimpleTy)] = DestVT.SimpleTy; } + /// Convenience method to set an operation to Promote and specify the type + /// in a single call. + void setOperationPromotedToType(unsigned Opc, MVT OrigVT, MVT DestVT) { + setOperationAction(Opc, OrigVT, Promote); + AddPromotedToType(Opc, OrigVT, DestVT); + } + /// Targets should invoke this method for each target independent node that /// they want to provide a custom DAG combiner for by implementing the /// PerformDAGCombine virtual method. @@ -1430,10 +1555,17 @@ protected: MinStackArgumentAlignment = Align; } - /// Set if the DAG builder should automatically insert fences and reduce the - /// order of atomic memory operations to Monotonic. - void setInsertFencesForAtomic(bool fence) { - InsertFencesForAtomic = fence; + /// Set the maximum atomic operation size supported by the + /// backend. Atomic operations greater than this size (as well as + /// ones that are not naturally aligned), will be expanded by + /// AtomicExpandPass into an __atomic_* library call. + void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits) { + MaxAtomicSizeInBitsSupported = SizeInBits; + } + + // Sets the minimum cmpxchg or ll/sc size supported by the backend. + void setMinCmpXchgSizeInBits(unsigned SizeInBits) { + MinCmpXchgSizeInBits = SizeInBits; } public: @@ -1845,10 +1977,13 @@ private: /// The preferred loop alignment. unsigned PrefLoopAlignment; - /// Whether the DAG builder should automatically insert fences and reduce - /// ordering for atomics. (This will be set for for most architectures with - /// weak memory ordering.) - bool InsertFencesForAtomic; + /// Size in bits of the maximum atomics size the backend supports. + /// Accesses larger than this will be expanded by AtomicExpandPass. + unsigned MaxAtomicSizeInBitsSupported; + + /// Size in bits of the minimum cmpxchg or ll/sc operation the + /// backend supports. + unsigned MinCmpXchgSizeInBits; /// If set to a physical register, this specifies the register that /// llvm.savestack/llvm.restorestack should save and restore. @@ -1889,9 +2024,9 @@ private: /// For each load extension type and each value type, keep a LegalizeAction /// that indicates how instruction selection should deal with a load of a - /// specific value type and extension type. - LegalizeAction LoadExtActions[MVT::LAST_VALUETYPE][MVT::LAST_VALUETYPE] - [ISD::LAST_LOADEXT_TYPE]; + /// specific value type and extension type. Uses 4-bits to store the action + /// for each of the 4 load ext types. + uint16_t LoadExtActions[MVT::LAST_VALUETYPE][MVT::LAST_VALUETYPE]; /// For each value type pair keep a LegalizeAction that indicates whether a /// truncating store of a specific value type and truncating type is legal. @@ -2026,7 +2161,7 @@ protected: /// Replace/modify any TargetFrameIndex operands with a targte-dependent /// sequence of memory operands that is recognized by PrologEpilogInserter. - MachineBasicBlock *emitPatchPoint(MachineInstr *MI, + MachineBasicBlock *emitPatchPoint(MachineInstr &MI, MachineBasicBlock *MBB) const; }; @@ -2043,6 +2178,8 @@ public: /// NOTE: The TargetMachine owns TLOF. explicit TargetLowering(const TargetMachine &TM); + bool isPositionIndependent() const; + /// Returns true by value, base pointer and offset pointer and addressing mode /// by reference if the node's address can be legally represented as /// pre-indexed load / store address. @@ -2092,18 +2229,26 @@ public: bool isInTailCallPosition(SelectionDAG &DAG, SDNode *Node, SDValue &Chain) const; - void softenSetCCOperands(SelectionDAG &DAG, EVT VT, - SDValue &NewLHS, SDValue &NewRHS, - ISD::CondCode &CCCode, SDLoc DL) const; + void softenSetCCOperands(SelectionDAG &DAG, EVT VT, SDValue &NewLHS, + SDValue &NewRHS, ISD::CondCode &CCCode, + const SDLoc &DL) const; /// Returns a pair of (return value, chain). /// It is an error to pass RTLIB::UNKNOWN_LIBCALL as \p LC. std::pair<SDValue, SDValue> makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef<SDValue> Ops, - bool isSigned, SDLoc dl, + bool isSigned, const SDLoc &dl, bool doesNotReturn = false, bool isReturnValueUsed = true) const; + /// Check whether parameters to a call that are passed in callee saved + /// registers are the same as from the calling function. This needs to be + /// checked for tail call eligibility. + bool parametersInCSRMatch(const MachineRegisterInfo &MRI, + const uint32_t *CallerPreservedMask, + const SmallVectorImpl<CCValAssign> &ArgLocs, + const SmallVectorImpl<SDValue> &OutVals) const; + //===--------------------------------------------------------------------===// // TargetLowering Optimization Methods // @@ -2141,7 +2286,7 @@ public: /// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be /// generalized for targets with other types of implicit widening casts. bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded, - SDLoc dl); + const SDLoc &dl); }; /// Look at Op. At this point, we know that only the DemandedMask bits of the @@ -2204,11 +2349,14 @@ public: /// from getBooleanContents(). bool isConstFalseVal(const SDNode *N) const; + /// Return if \p N is a True value when extended to \p VT. + bool isExtendedTrueVal(const ConstantSDNode *N, EVT VT, bool Signed) const; + /// Try to simplify a setcc built with the specified operands and cc. If it is /// unable to simplify it, return a null SDValue. - SDValue SimplifySetCC(EVT VT, SDValue N0, SDValue N1, - ISD::CondCode Cond, bool foldBooleans, - DAGCombinerInfo &DCI, SDLoc dl) const; + SDValue SimplifySetCC(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond, + bool foldBooleans, DAGCombinerInfo &DCI, + const SDLoc &dl) const; /// Returns true (and the GlobalValue and the offset) if the node is a /// GlobalAddress + offset. @@ -2263,6 +2411,12 @@ public: return false; } + /// Return true if the target supports swifterror attribute. It optimizes + /// loads and stores to reading and writing a specific register. + virtual bool supportSwiftError() const { + return false; + } + /// Return true if the target supports that a subset of CSRs for the given /// machine function is handled explicitly via copies. virtual bool supportSplitCSR(MachineFunction *MF) const { @@ -2302,12 +2456,10 @@ public: /// should fill in the InVals array with legal-type argument values, and /// return the resulting token chain value. /// - virtual SDValue - LowerFormalArguments(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, - bool /*isVarArg*/, - const SmallVectorImpl<ISD::InputArg> &/*Ins*/, - SDLoc /*dl*/, SelectionDAG &/*DAG*/, - SmallVectorImpl<SDValue> &/*InVals*/) const { + virtual SDValue LowerFormalArguments( + SDValue /*Chain*/, CallingConv::ID /*CallConv*/, bool /*isVarArg*/, + const SmallVectorImpl<ISD::InputArg> & /*Ins*/, const SDLoc & /*dl*/, + SelectionDAG & /*DAG*/, SmallVectorImpl<SDValue> & /*InVals*/) const { llvm_unreachable("Not Implemented"); } @@ -2322,11 +2474,14 @@ public: bool isByVal : 1; bool isInAlloca : 1; bool isReturned : 1; + bool isSwiftSelf : 1; + bool isSwiftError : 1; uint16_t Alignment; ArgListEntry() : isSExt(false), isZExt(false), isInReg(false), isSRet(false), isNest(false), isByVal(false), isInAlloca(false), - isReturned(false), Alignment(0) { } + isReturned(false), isSwiftSelf(false), isSwiftError(false), + Alignment(0) { } void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx); }; @@ -2345,6 +2500,7 @@ public: bool IsInReg : 1; bool DoesNotReturn : 1; bool IsReturnValueUsed : 1; + bool IsConvergent : 1; // IsTailCall should be modified by implementations of // TargetLowering::LowerCall that perform tail call conversions. @@ -2361,14 +2517,16 @@ public: SmallVector<ISD::OutputArg, 32> Outs; SmallVector<SDValue, 32> OutVals; SmallVector<ISD::InputArg, 32> Ins; + SmallVector<SDValue, 4> InVals; CallLoweringInfo(SelectionDAG &DAG) - : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false), - IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), - IsTailCall(false), NumFixedArgs(-1), CallConv(CallingConv::C), - DAG(DAG), CS(nullptr), IsPatchPoint(false) {} + : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false), + IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), + IsConvergent(false), IsTailCall(false), NumFixedArgs(-1), + CallConv(CallingConv::C), DAG(DAG), CS(nullptr), IsPatchPoint(false) { + } - CallLoweringInfo &setDebugLoc(SDLoc dl) { + CallLoweringInfo &setDebugLoc(const SDLoc &dl) { DL = dl; return *this; } @@ -2379,13 +2537,11 @@ public: } CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultType, - SDValue Target, ArgListTy &&ArgsList, - unsigned FixedArgs = -1) { + SDValue Target, ArgListTy &&ArgsList) { RetTy = ResultType; Callee = Target; CallConv = CC; - NumFixedArgs = - (FixedArgs == static_cast<unsigned>(-1) ? Args.size() : FixedArgs); + NumFixedArgs = Args.size(); Args = std::move(ArgsList); return *this; } @@ -2396,7 +2552,10 @@ public: RetTy = ResultType; IsInReg = Call.paramHasAttr(0, Attribute::InReg); - DoesNotReturn = Call.doesNotReturn(); + DoesNotReturn = + Call.doesNotReturn() || + (!Call.isInvoke() && + isa<UnreachableInst>(Call.getInstruction()->getNextNode())); IsVarArg = FTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); RetSExt = Call.paramHasAttr(0, Attribute::SExt); @@ -2438,6 +2597,11 @@ public: return *this; } + CallLoweringInfo &setConvergent(bool Value = true) { + IsConvergent = Value; + return *this; + } + CallLoweringInfo &setSExtResult(bool Value = true) { RetSExt = Value; return *this; @@ -2494,12 +2658,12 @@ public: /// This hook must be implemented to lower outgoing return values, described /// by the Outs array, into the specified DAG. The implementation should /// return the resulting token chain value. - virtual SDValue - LowerReturn(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, - bool /*isVarArg*/, - const SmallVectorImpl<ISD::OutputArg> &/*Outs*/, - const SmallVectorImpl<SDValue> &/*OutVals*/, - SDLoc /*dl*/, SelectionDAG &/*DAG*/) const { + virtual SDValue LowerReturn(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, + bool /*isVarArg*/, + const SmallVectorImpl<ISD::OutputArg> & /*Outs*/, + const SmallVectorImpl<SDValue> & /*OutVals*/, + const SDLoc & /*dl*/, + SelectionDAG & /*DAG*/) const { llvm_unreachable("Not Implemented"); } @@ -2534,12 +2698,12 @@ public: } /// Return the type that should be used to zero or sign extend a - /// zeroext/signext integer argument or return value. FIXME: Most C calling - /// convention requires the return type to be promoted, but this is not true - /// all the time, e.g. i1 on x86-64. It is also not necessary for non-C - /// calling conventions. The frontend should handle this and include all of - /// the necessary information. - virtual EVT getTypeForExtArgOrReturn(LLVMContext &Context, EVT VT, + /// zeroext/signext integer return value. FIXME: Some C calling conventions + /// require the return type to be promoted, but this is not true all the time, + /// e.g. i1/i8/i16 on x86/x86_64. It is also not necessary for non-C calling + /// conventions. The frontend should handle this and include all of the + /// necessary information. + virtual EVT getTypeForExtReturn(LLVMContext &Context, EVT VT, ISD::NodeType /*ExtendKind*/) const { EVT MinVT = getRegisterType(Context, MVT::i32); return VT.bitsLT(MinVT) ? MinVT : VT; @@ -2567,7 +2731,7 @@ public: /// which allows a CPU to reuse the result of a previous load indefinitely, /// even if a cache-coherent store is performed by another CPU. The default /// implementation does nothing. - virtual SDValue prepareVolatileOrAtomicLoad(SDValue Chain, SDLoc DL, + virtual SDValue prepareVolatileOrAtomicLoad(SDValue Chain, const SDLoc &DL, SelectionDAG &DAG) const { return Chain; } @@ -2840,6 +3004,25 @@ public: /// \returns True, if the expansion was successful, false otherwise bool expandFP_TO_SINT(SDNode *N, SDValue &Result, SelectionDAG &DAG) const; + /// Turn load of vector type into a load of the individual elements. + /// \param LD load to expand + /// \returns MERGE_VALUEs of the scalar loads with their chains. + SDValue scalarizeVectorLoad(LoadSDNode *LD, SelectionDAG &DAG) const; + + // Turn a store of a vector type into stores of the individual elements. + /// \param ST Store with a vector value type + /// \returns MERGE_VALUs of the individual store chains. + SDValue scalarizeVectorStore(StoreSDNode *ST, SelectionDAG &DAG) const; + + /// Expands an unaligned load to 2 half-size loads for an integer, and + /// possibly more for vectors. + std::pair<SDValue, SDValue> expandUnalignedLoad(LoadSDNode *LD, + SelectionDAG &DAG) const; + + /// Expands an unaligned store to 2 half-size stores for integer values, and + /// possibly more for vectors. + SDValue expandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG) const; + //===--------------------------------------------------------------------===// // Instruction Emitting Hooks // @@ -2853,14 +3036,14 @@ public: /// As long as the returned basic block is different (i.e., we created a new /// one), the custom inserter is free to modify the rest of \p MBB. virtual MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *MBB) const; /// This method should be implemented by targets that mark instructions with /// the 'hasPostISelHook' flag. These instructions must be adjusted after /// instruction selection by target hooks. e.g. To fill in optional defs for /// ARM 's' setting instructions. - virtual void - AdjustInstrPostInstrSelection(MachineInstr *MI, SDNode *Node) const; + virtual void AdjustInstrPostInstrSelection(MachineInstr &MI, + SDNode *Node) const; /// If this function returns true, SelectionDAGBuilder emits a /// LOAD_STACK_GUARD node when it is lowering Intrinsic::stackprotector. @@ -2871,6 +3054,11 @@ public: /// Lower TLS global address SDNode for target independent emulated TLS model. virtual SDValue LowerToTLSEmulatedModel(const GlobalAddressSDNode *GA, SelectionDAG &DAG) const; + +private: + SDValue simplifySetCCWithAnd(EVT VT, SDValue N0, SDValue N1, + ISD::CondCode Cond, DAGCombinerInfo &DCI, + const SDLoc &DL) const; }; /// Given an LLVM IR type and return type attributes, compute the return value diff --git a/include/llvm/Target/TargetLoweringObjectFile.h b/include/llvm/Target/TargetLoweringObjectFile.h index cb52698c58b9..189eff4f3953 100644 --- a/include/llvm/Target/TargetLoweringObjectFile.h +++ b/include/llvm/Target/TargetLoweringObjectFile.h @@ -71,7 +71,8 @@ public: /// placed in. virtual MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C) const; + const Constant *C, + unsigned &Align) const; /// Classify the specified global variable into a set of target independent /// categories embodied in SectionKind. @@ -154,8 +155,8 @@ public: virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const; virtual const MCExpr * - getExecutableRelativeSymbol(const ConstantExpr *CE, Mangler &Mang, - const TargetMachine &TM) const { + lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS, + Mangler &Mang, const TargetMachine &TM) const { return nullptr; } diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index 74e91b5790cb..563fef96acfc 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -29,15 +29,14 @@ class InstrItineraryData; class GlobalValue; class Mangler; class MachineFunctionInitializer; +class MachineModuleInfo; class MCAsmInfo; -class MCCodeGenInfo; class MCContext; class MCInstrInfo; class MCRegisterInfo; class MCSubtargetInfo; class MCSymbol; class Target; -class DataLayout; class TargetLibraryInfo; class TargetFrameLowering; class TargetIRAnalysis; @@ -45,7 +44,6 @@ class TargetIntrinsicInfo; class TargetLowering; class TargetPassConfig; class TargetRegisterInfo; -class TargetSelectionDAGInfo; class TargetSubtargetInfo; class TargetTransformInfo; class formatted_raw_ostream; @@ -90,9 +88,9 @@ protected: // Can only create subclasses. std::string TargetCPU; std::string TargetFS; - /// Low level target information such as relocation model. Non-const to - /// allow resetting optimization level per-function. - MCCodeGenInfo *CodeGenInfo; + Reloc::Model RM = Reloc::Static; + CodeModel::Model CMModel = CodeModel::Default; + CodeGenOpt::Level OptLevel = CodeGenOpt::Default; /// Contains target specific asm information. const MCAsmInfo *AsmInfo; @@ -104,11 +102,6 @@ protected: // Can only create subclasses. unsigned RequireStructuredCFG : 1; unsigned O0WantsFastISel : 1; - /// This API is here to support the C API, deprecated in 3.7 release. - /// This should never be used outside of legacy existing client. - const DataLayout &getDataLayout() const { return DL; } - friend struct C_API_PRIVATE_ACCESS; - public: mutable TargetOptions Options; @@ -181,6 +174,10 @@ public: /// target default. CodeModel::Model getCodeModel() const; + bool isPositionIndependent() const; + + bool shouldAssumeDSOLocal(const Module &M, const GlobalValue *GV) const; + /// Returns the TLS model which should be used for the given global variable. TLSModel::Model getTLSModel(const GlobalValue *GV) const; @@ -188,7 +185,7 @@ public: CodeGenOpt::Level getOptLevel() const; /// \brief Overrides the optimization level. - void setOptLevel(CodeGenOpt::Level Level) const; + void setOptLevel(CodeGenOpt::Level Level); void setFastISel(bool Enable) { Options.EnableFastISel = Enable; } bool getO0WantsFastISel() { return O0WantsFastISel; } @@ -223,6 +220,11 @@ public: /// uses this to answer queries about the IR. virtual TargetIRAnalysis getTargetIRAnalysis(); + /// Add target-specific function passes that should be run as early as + /// possible in the optimization pipeline. Most TargetMachines have no such + /// passes. + virtual void addEarlyAsPossiblePasses(PassManagerBase &) {} + /// These enums are meant to be passed into addPassesToEmitFile to indicate /// what type of file to emit, and returned by it to indicate what type of /// file could actually be made. @@ -265,6 +267,12 @@ public: void getNameWithPrefix(SmallVectorImpl<char> &Name, const GlobalValue *GV, Mangler &Mang, bool MayAlwaysUsePrivate = false) const; MCSymbol *getSymbol(const GlobalValue *GV, Mangler &Mang) const; + + /// True if the target uses physical regs at Prolog/Epilog insertion + /// time. If true (most machines), all vregs must be allocated before + /// PEI. If false (virtual-register machines), then callee-save register + /// spilling and scavenging are not needed or used. + virtual bool usesPhysRegsForPEI() const { return true; } }; /// This class describes a target machine that is implemented with the LLVM @@ -304,6 +312,13 @@ public: bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx, raw_pwrite_stream &OS, bool DisableVerify = true) override; + + /// Add MachineModuleInfo pass to pass manager. + MachineModuleInfo &addMachineModuleInfo(PassManagerBase &PM) const; + + /// Add MachineFunctionAnalysis pass to pass manager. + void addMachineFunctionAnalysis(PassManagerBase &PM, + MachineFunctionInitializer *MFInitializer) const; }; } // End llvm namespace diff --git a/include/llvm/Target/TargetOpcodes.def b/include/llvm/Target/TargetOpcodes.def new file mode 100644 index 000000000000..abab6c7a2a7c --- /dev/null +++ b/include/llvm/Target/TargetOpcodes.def @@ -0,0 +1,177 @@ +//===-- llvm/Target/TargetOpcodes.def - Target Indep Opcodes ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the target independent instruction opcodes. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +/// HANDLE_TARGET_OPCODE defines an opcode and its associated enum value. +/// +#ifndef HANDLE_TARGET_OPCODE +#define HANDLE_TARGET_OPCODE(OPC, NUM) +#endif + +/// HANDLE_TARGET_OPCODE_MARKER defines an alternative identifier for an opcode. +/// +#ifndef HANDLE_TARGET_OPCODE_MARKER +#define HANDLE_TARGET_OPCODE_MARKER(IDENT, OPC) +#endif + +/// Every instruction defined here must also appear in Target.td. +/// +HANDLE_TARGET_OPCODE(PHI, 0) +HANDLE_TARGET_OPCODE(INLINEASM, 1) +HANDLE_TARGET_OPCODE(CFI_INSTRUCTION, 2) +HANDLE_TARGET_OPCODE(EH_LABEL, 3) +HANDLE_TARGET_OPCODE(GC_LABEL, 4) + +/// KILL - This instruction is a noop that is used only to adjust the +/// liveness of registers. This can be useful when dealing with +/// sub-registers. +HANDLE_TARGET_OPCODE(KILL, 5) + +/// EXTRACT_SUBREG - This instruction takes two operands: a register +/// that has subregisters, and a subregister index. It returns the +/// extracted subregister value. This is commonly used to implement +/// truncation operations on target architectures which support it. +HANDLE_TARGET_OPCODE(EXTRACT_SUBREG, 6) + +/// INSERT_SUBREG - This instruction takes three operands: a register that +/// has subregisters, a register providing an insert value, and a +/// subregister index. It returns the value of the first register with the +/// value of the second register inserted. The first register is often +/// defined by an IMPLICIT_DEF, because it is commonly used to implement +/// anyext operations on target architectures which support it. +HANDLE_TARGET_OPCODE(INSERT_SUBREG, 7) + +/// IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef. +HANDLE_TARGET_OPCODE(IMPLICIT_DEF, 8) + +/// SUBREG_TO_REG - This instruction is similar to INSERT_SUBREG except that +/// the first operand is an immediate integer constant. This constant is +/// often zero, because it is commonly used to assert that the instruction +/// defining the register implicitly clears the high bits. +HANDLE_TARGET_OPCODE(SUBREG_TO_REG, 9) + +/// COPY_TO_REGCLASS - This instruction is a placeholder for a plain +/// register-to-register copy into a specific register class. This is only +/// used between instruction selection and MachineInstr creation, before +/// virtual registers have been created for all the instructions, and it's +/// only needed in cases where the register classes implied by the +/// instructions are insufficient. It is emitted as a COPY MachineInstr. +HANDLE_TARGET_OPCODE(COPY_TO_REGCLASS, 10) + +/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic +HANDLE_TARGET_OPCODE(DBG_VALUE, 11) + +/// REG_SEQUENCE - This variadic instruction is used to form a register that +/// represents a consecutive sequence of sub-registers. It's used as a +/// register coalescing / allocation aid and must be eliminated before code +/// emission. +// In SDNode form, the first operand encodes the register class created by +// the REG_SEQUENCE, while each subsequent pair names a vreg + subreg index +// pair. Once it has been lowered to a MachineInstr, the regclass operand +// is no longer present. +/// e.g. v1027 = REG_SEQUENCE v1024, 3, v1025, 4, v1026, 5 +/// After register coalescing references of v1024 should be replace with +/// v1027:3, v1025 with v1027:4, etc. +HANDLE_TARGET_OPCODE(REG_SEQUENCE, 12) + +/// COPY - Target-independent register copy. This instruction can also be +/// used to copy between subregisters of virtual registers. +HANDLE_TARGET_OPCODE(COPY, 13) + +/// BUNDLE - This instruction represents an instruction bundle. Instructions +/// which immediately follow a BUNDLE instruction which are marked with +/// 'InsideBundle' flag are inside the bundle. +HANDLE_TARGET_OPCODE(BUNDLE, 14) + +/// Lifetime markers. +HANDLE_TARGET_OPCODE(LIFETIME_START, 15) +HANDLE_TARGET_OPCODE(LIFETIME_END, 16) + +/// A Stackmap instruction captures the location of live variables at its +/// position in the instruction stream. It is followed by a shadow of bytes +/// that must lie within the function and not contain another stackmap. +HANDLE_TARGET_OPCODE(STACKMAP, 17) + +/// Patchable call instruction - this instruction represents a call to a +/// constant address, followed by a series of NOPs. It is intended to +/// support optimizations for dynamic languages (such as javascript) that +/// rewrite calls to runtimes with more efficient code sequences. +/// This also implies a stack map. +HANDLE_TARGET_OPCODE(PATCHPOINT, 18) + +/// This pseudo-instruction loads the stack guard value. Targets which need +/// to prevent the stack guard value or address from being spilled to the +/// stack should override TargetLowering::emitLoadStackGuardNode and +/// additionally expand this pseudo after register allocation. +HANDLE_TARGET_OPCODE(LOAD_STACK_GUARD, 19) + +/// Call instruction with associated vm state for deoptimization and list +/// of live pointers for relocation by the garbage collector. It is +/// intended to support garbage collection with fully precise relocating +/// collectors and deoptimizations in either the callee or caller. +HANDLE_TARGET_OPCODE(STATEPOINT, 20) + +/// Instruction that records the offset of a local stack allocation passed to +/// llvm.localescape. It has two arguments: the symbol for the label and the +/// frame index of the local stack allocation. +HANDLE_TARGET_OPCODE(LOCAL_ESCAPE, 21) + +/// Loading instruction that may page fault, bundled with associated +/// information on how to handle such a page fault. It is intended to support +/// "zero cost" null checks in managed languages by allowing LLVM to fold +/// comparisons into existing memory operations. +HANDLE_TARGET_OPCODE(FAULTING_LOAD_OP, 22) + +/// Wraps a machine instruction to add patchability constraints. An +/// instruction wrapped in PATCHABLE_OP has to either have a minimum +/// size or be preceded with a nop of that size. The first operand is +/// an immediate denoting the minimum size of the instruction, the +/// second operand is an immediate denoting the opcode of the original +/// instruction. The rest of the operands are the operands of the +/// original instruction. +HANDLE_TARGET_OPCODE(PATCHABLE_OP, 23) + +/// This is a marker instruction which gets translated into a nop sled, useful +/// for inserting instrumentation instructions at runtime. +HANDLE_TARGET_OPCODE(PATCHABLE_FUNCTION_ENTER, 24) + +/// Wraps a return instruction and its operands to enable adding nop sleds +/// either before or after the return. The nop sleds are useful for inserting +/// instrumentation instructions at runtime. +HANDLE_TARGET_OPCODE(PATCHABLE_RET, 25) + +/// The following generic opcodes are not supposed to appear after ISel. +/// This is something we might want to relax, but for now, this is convenient +/// to produce diagnostics. + +/// Generic ADD instruction. This is an integer add. +HANDLE_TARGET_OPCODE(G_ADD, 26) +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_START, G_ADD) + +/// Generic Bitwise-OR instruction. +HANDLE_TARGET_OPCODE(G_OR, 27) + +/// Generic BRANCH instruction. This is an unconditional branch. +HANDLE_TARGET_OPCODE(G_BR, 28) + +// TODO: Add more generic opcodes as we move along. + +/// Marker for the end of the generic opcode. +/// This is used to check if an opcode is in the range of the +/// generic opcodes. +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_BR) + +/// BUILTIN_OP_END - This must be the last enum value in this list. +/// The target-specific post-isel opcode values start here. +HANDLE_TARGET_OPCODE_MARKER(GENERIC_OP_END, PRE_ISEL_GENERIC_OPCODE_END) diff --git a/include/llvm/Target/TargetOpcodes.h b/include/llvm/Target/TargetOpcodes.h index db37bdb62582..f851fc27527b 100644 --- a/include/llvm/Target/TargetOpcodes.h +++ b/include/llvm/Target/TargetOpcodes.h @@ -18,122 +18,20 @@ namespace llvm { /// Invariant opcodes: All instruction sets have these as their low opcodes. /// -/// Every instruction defined here must also appear in Target.td and the order -/// must be the same as in CodeGenTarget.cpp. -/// namespace TargetOpcode { enum { - PHI = 0, - INLINEASM = 1, - CFI_INSTRUCTION = 2, - EH_LABEL = 3, - GC_LABEL = 4, - - /// KILL - This instruction is a noop that is used only to adjust the - /// liveness of registers. This can be useful when dealing with - /// sub-registers. - KILL = 5, - - /// EXTRACT_SUBREG - This instruction takes two operands: a register - /// that has subregisters, and a subregister index. It returns the - /// extracted subregister value. This is commonly used to implement - /// truncation operations on target architectures which support it. - EXTRACT_SUBREG = 6, - - /// INSERT_SUBREG - This instruction takes three operands: a register that - /// has subregisters, a register providing an insert value, and a - /// subregister index. It returns the value of the first register with the - /// value of the second register inserted. The first register is often - /// defined by an IMPLICIT_DEF, because it is commonly used to implement - /// anyext operations on target architectures which support it. - INSERT_SUBREG = 7, - - /// IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef. - IMPLICIT_DEF = 8, - - /// SUBREG_TO_REG - This instruction is similar to INSERT_SUBREG except that - /// the first operand is an immediate integer constant. This constant is - /// often zero, because it is commonly used to assert that the instruction - /// defining the register implicitly clears the high bits. - SUBREG_TO_REG = 9, - - /// COPY_TO_REGCLASS - This instruction is a placeholder for a plain - /// register-to-register copy into a specific register class. This is only - /// used between instruction selection and MachineInstr creation, before - /// virtual registers have been created for all the instructions, and it's - /// only needed in cases where the register classes implied by the - /// instructions are insufficient. It is emitted as a COPY MachineInstr. - COPY_TO_REGCLASS = 10, - - /// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic - DBG_VALUE = 11, - - /// REG_SEQUENCE - This variadic instruction is used to form a register that - /// represents a consecutive sequence of sub-registers. It's used as a - /// register coalescing / allocation aid and must be eliminated before code - /// emission. - // In SDNode form, the first operand encodes the register class created by - // the REG_SEQUENCE, while each subsequent pair names a vreg + subreg index - // pair. Once it has been lowered to a MachineInstr, the regclass operand - // is no longer present. - /// e.g. v1027 = REG_SEQUENCE v1024, 3, v1025, 4, v1026, 5 - /// After register coalescing references of v1024 should be replace with - /// v1027:3, v1025 with v1027:4, etc. - REG_SEQUENCE = 12, - - /// COPY - Target-independent register copy. This instruction can also be - /// used to copy between subregisters of virtual registers. - COPY = 13, - - /// BUNDLE - This instruction represents an instruction bundle. Instructions - /// which immediately follow a BUNDLE instruction which are marked with - /// 'InsideBundle' flag are inside the bundle. - BUNDLE = 14, - - /// Lifetime markers. - LIFETIME_START = 15, - LIFETIME_END = 16, - - /// A Stackmap instruction captures the location of live variables at its - /// position in the instruction stream. It is followed by a shadow of bytes - /// that must lie within the function and not contain another stackmap. - STACKMAP = 17, - - /// Patchable call instruction - this instruction represents a call to a - /// constant address, followed by a series of NOPs. It is intended to - /// support optimizations for dynamic languages (such as javascript) that - /// rewrite calls to runtimes with more efficient code sequences. - /// This also implies a stack map. - PATCHPOINT = 18, - - /// This pseudo-instruction loads the stack guard value. Targets which need - /// to prevent the stack guard value or address from being spilled to the - /// stack should override TargetLowering::emitLoadStackGuardNode and - /// additionally expand this pseudo after register allocation. - LOAD_STACK_GUARD = 19, - - /// Call instruction with associated vm state for deoptimization and list - /// of live pointers for relocation by the garbage collector. It is - /// intended to support garbage collection with fully precise relocating - /// collectors and deoptimizations in either the callee or caller. - STATEPOINT = 20, - - /// Instruction that records the offset of a local stack allocation passed to - /// llvm.localescape. It has two arguments: the symbol for the label and the - /// frame index of the local stack allocation. - LOCAL_ESCAPE = 21, - - /// Loading instruction that may page fault, bundled with associated - /// information on how to handle such a page fault. It is intended to support - /// "zero cost" null checks in managed languages by allowing LLVM to fold - /// comparisons into existing memory operations. - FAULTING_LOAD_OP = 22, - - /// BUILTIN_OP_END - This must be the last enum value in this list. - /// The target-specific post-isel opcode values start here. - GENERIC_OP_END = FAULTING_LOAD_OP, +#define HANDLE_TARGET_OPCODE(OPC, NUM) OPC = NUM, +#define HANDLE_TARGET_OPCODE_MARKER(IDENT, OPC) IDENT = OPC, +#include "llvm/Target/TargetOpcodes.def" }; } // end namespace TargetOpcode + +/// Check whether the given Opcode is a generic opcode that is not supposed +/// to appear after ISel. +static inline bool isPreISelGenericOpcode(unsigned Opcode) { + return Opcode >= TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START && + Opcode <= TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; +} } // end namespace llvm #endif diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h index d98d0fa0ed5f..57873b4bd0b4 100644 --- a/include/llvm/Target/TargetOptions.h +++ b/include/llvm/Target/TargetOptions.h @@ -17,12 +17,11 @@ #include "llvm/Target/TargetRecip.h" #include "llvm/MC/MCTargetOptions.h" -#include <string> +#include "llvm/MC/MCAsmInfo.h" namespace llvm { class MachineFunction; class Module; - class StringRef; namespace FloatABI { enum ABIType { @@ -97,14 +96,16 @@ namespace llvm { UnsafeFPMath(false), NoInfsFPMath(false), NoNaNsFPMath(false), HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false), GuaranteedTailCallOpt(false), StackAlignmentOverride(0), - EnableFastISel(false), PositionIndependentExecutable(false), - UseInitArray(false), DisableIntegratedAS(false), - CompressDebugSections(false), FunctionSections(false), + StackSymbolOrdering(true), EnableFastISel(false), UseInitArray(false), + DisableIntegratedAS(false), CompressDebugSections(false), + RelaxELFRelocations(false), FunctionSections(false), DataSections(false), UniqueSectionNames(true), TrapUnreachable(false), - EmulatedTLS(false), FloatABIType(FloatABI::Default), + EmulatedTLS(false), EnableIPRA(false), + FloatABIType(FloatABI::Default), AllowFPOpFusion(FPOpFusion::Standard), Reciprocals(TargetRecip()), JTType(JumpTable::Single), ThreadModel(ThreadModel::POSIX), - EABIVersion(EABI::Default), DebuggerTuning(DebuggerKind::Default) {} + EABIVersion(EABI::Default), DebuggerTuning(DebuggerKind::Default), + ExceptionModel(ExceptionHandling::None) {} /// PrintMachineCode - This flag is enabled when the -print-machineinstrs /// option is specified on the command line, and should enable debugging @@ -169,17 +170,17 @@ namespace llvm { /// StackAlignmentOverride - Override default stack alignment for target. unsigned StackAlignmentOverride; + /// StackSymbolOrdering - When true, this will allow CodeGen to order + /// the local stack symbols (for code size, code locality, or any other + /// heuristics). When false, the local symbols are left in whatever order + /// they were generated. Default is true. + unsigned StackSymbolOrdering : 1; + /// EnableFastISel - This flag enables fast-path instruction selection /// which trades away generated code quality in favor of reducing /// compile time. unsigned EnableFastISel : 1; - /// PositionIndependentExecutable - This flag indicates whether the code - /// will eventually be linked into a single executable, despite the PIC - /// relocation model being in use. It's value is undefined (and irrelevant) - /// if the relocation model is anything other than PIC. - unsigned PositionIndependentExecutable : 1; - /// UseInitArray - Use .init_array instead of .ctors for static /// constructors. unsigned UseInitArray : 1; @@ -190,6 +191,8 @@ namespace llvm { /// Compress DWARF debug sections. unsigned CompressDebugSections : 1; + unsigned RelaxELFRelocations : 1; + /// Emit functions into separate sections. unsigned FunctionSections : 1; @@ -205,6 +208,9 @@ namespace llvm { /// function in the runtime library.. unsigned EmulatedTLS : 1; + /// This flag enables InterProcedural Register Allocation (IPRA). + unsigned EnableIPRA : 1; + /// FloatABIType - This setting is set by -float-abi=xxx option is specfied /// on the command line. This setting may either be Default, Soft, or Hard. /// Default selects the target's default behavior. Soft selects the ABI for @@ -248,6 +254,9 @@ namespace llvm { /// Which debugger to tune for. DebuggerKind DebuggerTuning; + /// What exception model to use + ExceptionHandling ExceptionModel; + /// Machine level options. MCTargetOptions MCOptions; }; @@ -267,7 +276,6 @@ inline bool operator==(const TargetOptions &LHS, ARE_EQUAL(GuaranteedTailCallOpt) && ARE_EQUAL(StackAlignmentOverride) && ARE_EQUAL(EnableFastISel) && - ARE_EQUAL(PositionIndependentExecutable) && ARE_EQUAL(UseInitArray) && ARE_EQUAL(TrapUnreachable) && ARE_EQUAL(EmulatedTLS) && @@ -278,7 +286,9 @@ inline bool operator==(const TargetOptions &LHS, ARE_EQUAL(ThreadModel) && ARE_EQUAL(EABIVersion) && ARE_EQUAL(DebuggerTuning) && - ARE_EQUAL(MCOptions); + ARE_EQUAL(ExceptionModel) && + ARE_EQUAL(MCOptions) && + ARE_EQUAL(EnableIPRA); #undef ARE_EQUAL } diff --git a/include/llvm/Target/TargetRecip.h b/include/llvm/Target/TargetRecip.h index 210d49324848..309b96079131 100644 --- a/include/llvm/Target/TargetRecip.h +++ b/include/llvm/Target/TargetRecip.h @@ -18,9 +18,10 @@ #define LLVM_TARGET_TARGETRECIP_H #include "llvm/ADT/StringRef.h" -#include <vector> -#include <string> +#include <cstdint> #include <map> +#include <string> +#include <vector> namespace llvm { @@ -68,6 +69,6 @@ private: void parseIndividualParams(const std::vector<std::string> &Args); }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TARGET_TARGETRECIP_H diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index fccaad4705d5..e5a6c8ed2f2d 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -21,7 +21,6 @@ #include "llvm/CodeGen/MachineValueType.h" #include "llvm/IR/CallingConv.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Printable.h" #include <cassert> #include <functional> @@ -71,6 +70,9 @@ public: const uint8_t AllocationPriority; /// Whether the class supports two (or more) disjunct subregister indices. const bool HasDisjunctSubRegs; + /// Whether a combination of subregisters can cover every register in the + /// class. See also the CoveredBySubRegs description in Target.td. + const bool CoveredBySubRegs; const sc_iterator SuperClasses; ArrayRef<MCPhysReg> (*OrderFunc)(const MachineFunction&); @@ -161,8 +163,21 @@ public: } /// Returns a bit vector of subclasses, including this one. - /// The vector is indexed by class IDs, see hasSubClassEq() above for how to - /// use it. + /// The vector is indexed by class IDs. + /// + /// To use it, consider the returned array as a chunk of memory that + /// contains an array of bits of size NumRegClasses. Each 32-bit chunk + /// contains a bitset of the ID of the subclasses in big-endian style. + + /// I.e., the representation of the memory from left to right at the + /// bit level looks like: + /// [31 30 ... 1 0] [ 63 62 ... 33 32] ... + /// [ XXX NumRegClasses NumRegClasses - 1 ... ] + /// Where the number represents the class ID and XXX bits that + /// should be ignored. + /// + /// See the implementation of hasSubClassEq for an example of how it + /// can be used. const uint32_t *getSubClassMask() const { return SubClassMask; } @@ -212,7 +227,7 @@ public: /// Returns the combination of all lane masks of register in this class. /// The lane masks of the registers are the combination of all lane masks - /// of their subregisters. + /// of their subregisters. Returns 1 if there are no subregisters. LaneBitmask getLaneMask() const { return LaneMask; } @@ -457,9 +472,13 @@ public: /// Return a register mask that clobbers everything. virtual const uint32_t *getNoPreservedMask() const { - llvm_unreachable("target does not provide no presered mask"); + llvm_unreachable("target does not provide no preserved mask"); } + /// Return true if all bits that are set in mask \p mask0 are also set in + /// \p mask1. + bool regmaskSubsetEqual(const uint32_t *mask0, const uint32_t *mask1) const; + /// Return all the call-preserved register masks defined for this target. virtual ArrayRef<const uint32_t *> getRegMasks() const = 0; virtual ArrayRef<const char *> getRegMaskNames() const = 0; @@ -548,6 +567,20 @@ public: return composeSubRegIndexLaneMaskImpl(IdxA, Mask); } + /// Transform a lanemask given for a virtual register to the corresponding + /// lanemask before using subregister with index \p IdxA. + /// This is the reverse of composeSubRegIndexLaneMask(), assuming Mask is a + /// valie lane mask (no invalid bits set) the following holds: + /// X0 = composeSubRegIndexLaneMask(Idx, Mask) + /// X1 = reverseComposeSubRegIndexLaneMask(Idx, X0) + /// => X1 == Mask + LaneBitmask reverseComposeSubRegIndexLaneMask(unsigned IdxA, + LaneBitmask LaneMask) const { + if (!IdxA) + return LaneMask; + return reverseComposeSubRegIndexLaneMaskImpl(IdxA, LaneMask); + } + /// Debugging helper: dump register in human readable form to dbgs() stream. static void dumpReg(unsigned Reg, unsigned SubRegIndex = 0, const TargetRegisterInfo* TRI = nullptr); @@ -564,6 +597,11 @@ protected: llvm_unreachable("Target has no sub-registers"); } + virtual LaneBitmask reverseComposeSubRegIndexLaneMaskImpl(unsigned, + LaneBitmask) const { + llvm_unreachable("Target has no sub-registers"); + } + public: /// Find a common super-register class if it exists. /// @@ -863,6 +901,17 @@ public: int SPAdj, unsigned FIOperandNum, RegScavenger *RS = nullptr) const = 0; + /// Return the assembly name for \p Reg. + virtual StringRef getRegAsmName(unsigned Reg) const { + // FIXME: We are assuming that the assembly name is equal to the TableGen + // name converted to lower case + // + // The TableGen name is the name of the definition for this register in the + // target's tablegen files. For example, the TableGen name of + // def EAX : Register <...>; is "EAX" + return StringRef(getName(Reg)); + } + //===--------------------------------------------------------------------===// /// Subtarget Hooks @@ -926,8 +975,9 @@ public: /// Returns the current sub-register index. unsigned getSubReg() const { return SubReg; } - /// Returns the bit mask if register classes that getSubReg() projects into + /// Returns the bit mask of register classes that getSubReg() projects into /// RC. + /// See TargetRegisterClass::getSubClassMask() for how to use it. const uint32_t *getMask() const { return Mask; } /// Advance iterator to the next entry. @@ -940,6 +990,97 @@ public: } }; +//===----------------------------------------------------------------------===// +// BitMaskClassIterator +//===----------------------------------------------------------------------===// +/// This class encapuslates the logic to iterate over bitmask returned by +/// the various RegClass related APIs. +/// E.g., this class can be used to iterate over the subclasses provided by +/// TargetRegisterClass::getSubClassMask or SuperRegClassIterator::getMask. +class BitMaskClassIterator { + /// Total number of register classes. + const unsigned NumRegClasses; + /// Base index of CurrentChunk. + /// In other words, the number of bit we read to get at the + /// beginning of that chunck. + unsigned Base; + /// Adjust base index of CurrentChunk. + /// Base index + how many bit we read within CurrentChunk. + unsigned Idx; + /// Current register class ID. + unsigned ID; + /// Mask we are iterating over. + const uint32_t *Mask; + /// Current chunk of the Mask we are traversing. + uint32_t CurrentChunk; + + /// Move ID to the next set bit. + void moveToNextID() { + // If the current chunk of memory is empty, move to the next one, + // while making sure we do not go pass the number of register + // classes. + while (!CurrentChunk) { + // Move to the next chunk. + Base += 32; + if (Base >= NumRegClasses) { + ID = NumRegClasses; + return; + } + CurrentChunk = *++Mask; + Idx = Base; + } + // Otherwise look for the first bit set from the right + // (representation of the class ID is big endian). + // See getSubClassMask for more details on the representation. + unsigned Offset = countTrailingZeros(CurrentChunk); + // Add the Offset to the adjusted base number of this chunk: Idx. + // This is the ID of the register class. + ID = Idx + Offset; + + // Consume the zeros, if any, and the bit we just read + // so that we are at the right spot for the next call. + // Do not do Offset + 1 because Offset may be 31 and 32 + // will be UB for the shift, though in that case we could + // have make the chunk being equal to 0, but that would + // have introduced a if statement. + moveNBits(Offset); + moveNBits(1); + } + + /// Move \p NumBits Bits forward in CurrentChunk. + void moveNBits(unsigned NumBits) { + assert(NumBits < 32 && "Undefined behavior spotted!"); + // Consume the bit we read for the next call. + CurrentChunk >>= NumBits; + // Adjust the base for the chunk. + Idx += NumBits; + } + +public: + /// Create a BitMaskClassIterator that visits all the register classes + /// represented by \p Mask. + /// + /// \pre \p Mask != nullptr + BitMaskClassIterator(const uint32_t *Mask, const TargetRegisterInfo &TRI) + : NumRegClasses(TRI.getNumRegClasses()), Base(0), Idx(0), ID(0), + Mask(Mask), CurrentChunk(*Mask) { + // Move to the first ID. + moveToNextID(); + } + + /// Returns true if this iterator is still pointing at a valid entry. + bool isValid() const { return getID() != NumRegClasses; } + + /// Returns the current register class ID. + unsigned getID() const { return ID; } + + /// Advance iterator to the next entry. + void operator++() { + assert(isValid() && "Cannot move iterator past end."); + moveToNextID(); + } +}; + // This is useful when building IndexedMaps keyed on virtual registers struct VirtReg2IndexFunctor : public std::unary_function<unsigned, unsigned> { unsigned operator()(unsigned Reg) const { diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index 89db37ca859b..74b98ac5f6c5 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -13,7 +13,7 @@ // The SchedMachineModel is defined by subtargets for three categories of data: // 1. Basic properties for coarse grained instruction cost model. // 2. Scheduler Read/Write resources for simple per-opcode cost model. -// 3. Instruction itineraties for detailed reservation tables. +// 3. Instruction itineraries for detailed reservation tables. // // (1) Basic properties are defined by the SchedMachineModel // class. Target hooks allow subtargets to associate opcodes with @@ -55,6 +55,8 @@ include "llvm/Target/TargetItinerary.td" class Instruction; // Forward def +class Predicate; // Forward def + // DAG operator that interprets the DAG args as Instruction defs. def instrs; @@ -76,8 +78,6 @@ def instregex; // See MCSchedule.h for detailed comments. class SchedMachineModel { int IssueWidth = -1; // Max micro-ops that may be scheduled per cycle. - int MinLatency = -1; // Determines which instructions are allowed in a group. - // (-1) inorder (0) ooo, (1): inorder +var latencies. int MicroOpBufferSize = -1; // Max micro-ops that can be buffered. int LoopMicroOpBufferSize = -1; // Max micro-ops that can be buffered for // optimized loop dispatch/execution. @@ -99,11 +99,26 @@ class SchedMachineModel { // resulting from changes to the instruction definitions. bit CompleteModel = 1; + // A processor may only implement part of published ISA, due to either new ISA + // extensions, (e.g. Pentium 4 doesn't have AVX) or implementation + // (ARM/MIPS/PowerPC/SPARC soft float cores). + // + // For a processor which doesn't support some feature(s), the schedule model + // can use: + // + // let<Predicate> UnsupportedFeatures = [HaveA,..,HaveY]; + // + // to skip the checks for scheduling information when building LLVM for + // instructions which have any of the listed predicates in their Predicates + // field. + list<Predicate> UnsupportedFeatures = []; + bit NoModel = 0; // Special tag to indicate missing machine model. } def NoSchedModel : SchedMachineModel { let NoModel = 1; + let CompleteModel = 0; } // Define a kind of processor resource that may be common across @@ -392,6 +407,8 @@ class InstRW<list<SchedReadWrite> rw, dag instrlist> { list<SchedReadWrite> OperandReadWrites = rw; dag Instrs = instrlist; SchedMachineModel SchedModel = ?; + // Allow a subtarget to mark some instructions as unsupported. + bit Unsupported = 0; } // Map a set of itinerary classes to SchedReadWrite resources. This is diff --git a/include/llvm/Target/TargetSelectionDAG.td b/include/llvm/Target/TargetSelectionDAG.td index 565473658404..88375f77e230 100644 --- a/include/llvm/Target/TargetSelectionDAG.td +++ b/include/llvm/Target/TargetSelectionDAG.td @@ -116,6 +116,9 @@ def SDTIntBinOp : SDTypeProfile<1, 2, [ // add, and, or, xor, udiv, etc. def SDTIntShiftOp : SDTypeProfile<1, 2, [ // shl, sra, srl SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<2> ]>; +def SDTIntSatNoShOp : SDTypeProfile<1, 2, [ // ssat with no shift + SDTCisSameAs<0, 1>, SDTCisInt<2> +]>; def SDTIntBinHiLoOp : SDTypeProfile<2, 2, [ // mulhi, mullo, sdivrem, udivrem SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>,SDTCisInt<0> ]>; @@ -167,7 +170,7 @@ def SDTSelect : SDTypeProfile<1, 3, [ // select ]>; def SDTVSelect : SDTypeProfile<1, 3, [ // vselect - SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3> + SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTSelectCC : SDTypeProfile<1, 5, [ // select_cc @@ -300,7 +303,9 @@ def SDNPWantParent : SDNodeProperty; // ComplexPattern gets the parent //===----------------------------------------------------------------------===// // Selection DAG Pattern Operations -class SDPatternOperator; +class SDPatternOperator { + list<SDNodeProperty> Properties = []; +} //===----------------------------------------------------------------------===// // Selection DAG Node definitions. @@ -310,7 +315,7 @@ class SDNode<string opcode, SDTypeProfile typeprof, : SDPatternOperator { string Opcode = opcode; string SDClass = sdclass; - list<SDNodeProperty> Properties = props; + let Properties = props; SDTypeProfile TypeProfile = typeprof; } @@ -391,10 +396,14 @@ def subc : SDNode<"ISD::SUBC" , SDTIntBinOp, [SDNPOutGlue]>; def sube : SDNode<"ISD::SUBE" , SDTIntBinOp, [SDNPOutGlue, SDNPInGlue]>; -def smin : SDNode<"ISD::SMIN" , SDTIntBinOp>; -def smax : SDNode<"ISD::SMAX" , SDTIntBinOp>; -def umin : SDNode<"ISD::UMIN" , SDTIntBinOp>; -def umax : SDNode<"ISD::UMAX" , SDTIntBinOp>; +def smin : SDNode<"ISD::SMIN" , SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def smax : SDNode<"ISD::SMAX" , SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def umin : SDNode<"ISD::UMIN" , SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def umax : SDNode<"ISD::UMAX" , SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>; def bitreverse : SDNode<"ISD::BITREVERSE" , SDTIntUnaryOp>; @@ -421,11 +430,14 @@ def frem : SDNode<"ISD::FREM" , SDTFPBinOp>; def fma : SDNode<"ISD::FMA" , SDTFPTernaryOp>; def fmad : SDNode<"ISD::FMAD" , SDTFPTernaryOp>; def fabs : SDNode<"ISD::FABS" , SDTFPUnaryOp>; -def fminnum : SDNode<"ISD::FMINNUM" , SDTFPBinOp>; -def fmaxnum : SDNode<"ISD::FMAXNUM" , SDTFPBinOp>; +def fminnum : SDNode<"ISD::FMINNUM" , SDTFPBinOp, + [SDNPCommutative, SDNPAssociative]>; +def fmaxnum : SDNode<"ISD::FMAXNUM" , SDTFPBinOp, + [SDNPCommutative, SDNPAssociative]>; def fminnan : SDNode<"ISD::FMINNAN" , SDTFPBinOp>; def fmaxnan : SDNode<"ISD::FMAXNAN" , SDTFPBinOp>; def fgetsign : SDNode<"ISD::FGETSIGN" , SDTFPToIntOp>; +def fcanonicalize : SDNode<"ISD::FCANONICALIZE", SDTFPUnaryOp>; def fneg : SDNode<"ISD::FNEG" , SDTFPUnaryOp>; def fsqrt : SDNode<"ISD::FSQRT" , SDTFPUnaryOp>; def fsin : SDNode<"ISD::FSIN" , SDTFPUnaryOp>; @@ -944,6 +956,18 @@ def unalignednontemporalstore : PatFrag<(ops node:$val, node:$ptr), return St->getAlignment() < St->getMemoryVT().getStoreSize(); }]>; +// nontemporal load fragments. +def nontemporalload : PatFrag<(ops node:$ptr), + (load node:$ptr), [{ + return cast<LoadSDNode>(N)->isNonTemporal(); +}]>; + +def alignednontemporalload : PatFrag<(ops node:$ptr), + (nontemporalload node:$ptr), [{ + LoadSDNode *Ld = cast<LoadSDNode>(N); + return Ld->getAlignment() >= Ld->getMemoryVT().getStoreSize(); +}]>; + // setcc convenience fragments. def setoeq : PatFrag<(ops node:$lhs, node:$rhs), (setcc node:$lhs, node:$rhs, SETOEQ)>; diff --git a/include/llvm/Target/TargetSubtargetInfo.h b/include/llvm/Target/TargetSubtargetInfo.h index d50aa4932f8f..b929070484f9 100644 --- a/include/llvm/Target/TargetSubtargetInfo.h +++ b/include/llvm/Target/TargetSubtargetInfo.h @@ -16,14 +16,18 @@ #include "llvm/CodeGen/PBQPRAConstraint.h" #include "llvm/CodeGen/SchedulerRegistry.h" +#include "llvm/CodeGen/ScheduleDAGMutation.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/CodeGen.h" +#include <vector> namespace llvm { +class CallLowering; class DataLayout; class MachineFunction; class MachineInstr; +class RegisterBankInfo; class SDep; class SUnit; class TargetFrameLowering; @@ -32,7 +36,7 @@ class TargetLowering; class TargetRegisterClass; class TargetRegisterInfo; class TargetSchedModel; -class TargetSelectionDAGInfo; +class SelectionDAGTargetInfo; struct MachineSchedPolicy; template <typename T> class SmallVectorImpl; @@ -71,6 +75,7 @@ public: // -- Pipelines and scheduling information // -- Stack frame information // -- Selection DAG lowering information + // -- Call lowering information // // N.B. These objects may change during compilation. It's not safe to cache // them between functions. @@ -79,9 +84,10 @@ public: return nullptr; } virtual const TargetLowering *getTargetLowering() const { return nullptr; } - virtual const TargetSelectionDAGInfo *getSelectionDAGInfo() const { + virtual const SelectionDAGTargetInfo *getSelectionDAGInfo() const { return nullptr; } + virtual const CallLowering *getCallLowering() const { return nullptr; } /// Target can subclass this hook to select a different DAG scheduler. virtual RegisterScheduler::FunctionPassCtor getDAGScheduler(CodeGenOpt::Level) const { @@ -89,11 +95,14 @@ public: } /// getRegisterInfo - If register information is available, return it. If - /// not, return null. This is kept separate from RegInfo until RegInfo has - /// details of graph coloring register allocation removed from it. + /// not, return null. /// virtual const TargetRegisterInfo *getRegisterInfo() const { return nullptr; } + /// If the information for the register banks is available, return it. + /// Otherwise return nullptr. + virtual const RegisterBankInfo *getRegBankInfo() const { return nullptr; } + /// getInstrItineraryData - Returns instruction itinerary data for the target /// or specific subtarget. /// @@ -144,7 +153,6 @@ public: /// scheduling heuristics (no custom MachineSchedStrategy) to make /// changes to the generic scheduling policy. virtual void overrideSchedPolicy(MachineSchedPolicy &Policy, - MachineInstr *begin, MachineInstr *end, unsigned NumRegionInstrs) const {} // \brief Perform target specific adjustments to the latency of a schedule @@ -162,6 +170,12 @@ public: return CriticalPathRCs.clear(); } + // \brief Provide an ordered list of schedule DAG mutations for the post-RA + // scheduler. + virtual void getPostRAMutations( + std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const { + } + // For use with PostRAScheduling: get the minimum optimization level needed // to enable post-RA scheduling. virtual CodeGenOpt::Level getOptLevelToEnablePostRAScheduler() const { diff --git a/include/llvm/Transforms/GCOVProfiler.h b/include/llvm/Transforms/GCOVProfiler.h new file mode 100644 index 000000000000..f6521901a33e --- /dev/null +++ b/include/llvm/Transforms/GCOVProfiler.h @@ -0,0 +1,31 @@ +//===- Transforms/GCOVProfiler.h - GCOVProfiler pass ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides the interface for the GCOV style profiler pass. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_GCOVPROFILER_H +#define LLVM_TRANSFORMS_GCOVPROFILER_H + +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Instrumentation.h" + +namespace llvm { +/// The gcov-style instrumentation pass +class GCOVProfilerPass : public PassInfoMixin<GCOVProfilerPass> { +public: + GCOVProfilerPass(const GCOVOptions &Options = GCOVOptions::getDefault()) : GCOVOpts(Options) { } + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); + +private: + GCOVOptions GCOVOpts; +}; + +} // End llvm namespace +#endif diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index 78d2fadc5190..f6731884870c 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -15,12 +15,13 @@ #ifndef LLVM_TRANSFORMS_IPO_H #define LLVM_TRANSFORMS_IPO_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" +#include <functional> +#include <vector> namespace llvm { -class FunctionInfoIndex; +class StringRef; +class ModuleSummaryIndex; class ModulePass; class Pass; class Function; @@ -88,7 +89,7 @@ ModulePass *createGVExtractionPass(std::vector<GlobalValue*>& GVs, bool //===----------------------------------------------------------------------===// /// This pass performs iterative function importing from other modules. -Pass *createFunctionImportPass(const FunctionInfoIndex *Index = nullptr); +Pass *createFunctionImportPass(const ModuleSummaryIndex *Index = nullptr); //===----------------------------------------------------------------------===// /// createFunctionInliningPass - Return a new pass object that uses a heuristic @@ -119,14 +120,17 @@ Pass *createPruneEHPass(); /// createInternalizePass - This pass loops over all of the functions in the /// input module, internalizing all globals (functions and variables) it can. //// -/// The symbols in \p ExportList are never internalized. +/// Before internalizing a symbol, the callback \p MustPreserveGV is invoked and +/// gives to the client the ability to prevent internalizing specific symbols. /// /// The symbol in DSOList are internalized if it is safe to drop them from /// the symbol table. /// /// Note that commandline options that are used with the above function are not /// used now! -ModulePass *createInternalizePass(ArrayRef<const char *> ExportList); +ModulePass * +createInternalizePass(std::function<bool(const GlobalValue &)> MustPreserveGV); + /// createInternalizePass - Same as above, but with an empty exportList. ModulePass *createInternalizePass(); @@ -183,15 +187,6 @@ ModulePass *createBlockExtractorPass(); ModulePass *createStripDeadPrototypesPass(); //===----------------------------------------------------------------------===// -/// createPostOrderFunctionAttrsPass - This pass walks SCCs of the call graph -/// in post-order to deduce and propagate function attributes. It can discover -/// functions that do not access memory, or only read memory, and give them the -/// readnone/readonly attribute. It also discovers function arguments that are -/// not captured by the function and marks them with the nocapture attribute. -/// -Pass *createPostOrderFunctionAttrsPass(); - -//===----------------------------------------------------------------------===// /// createReversePostOrderFunctionAttrsPass - This pass walks SCCs of the call /// graph in RPO to deduce and propagate function attributes. Currently it /// only handles synthesizing norecurse attributes. @@ -219,13 +214,17 @@ ModulePass *createMetaRenamerPass(); /// manager. ModulePass *createBarrierNoopPass(); -/// \brief This pass lowers bitset metadata and the llvm.bitset.test intrinsic -/// to bitsets. -ModulePass *createLowerBitSetsPass(); +/// \brief This pass lowers type metadata and the llvm.type.test intrinsic to +/// bitsets. +ModulePass *createLowerTypeTestsPass(); /// \brief This pass export CFI checks for use by external modules. ModulePass *createCrossDSOCFIPass(); +/// \brief This pass implements whole-program devirtualization using type +/// metadata. +ModulePass *createWholeProgramDevirtPass(); + //===----------------------------------------------------------------------===// // SampleProfilePass - Loads sample profile data from disk and generates // IR metadata to reflect the profile. diff --git a/include/llvm/Transforms/IPO/ConstantMerge.h b/include/llvm/Transforms/IPO/ConstantMerge.h new file mode 100644 index 000000000000..1d4da43f6a7b --- /dev/null +++ b/include/llvm/Transforms/IPO/ConstantMerge.h @@ -0,0 +1,35 @@ +//===- ConstantMerge.h - Merge duplicate global constants -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to a pass that merges duplicate global +// constants together into a single constant that is shared. This is useful +// because some passes (ie TraceValues) insert a lot of string constants into +// the program, regardless of whether or not an existing string is available. +// +// Algorithm: ConstantMerge is designed to build up a map of available constants +// and eliminate duplicates when it is initialized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_CONSTANTMERGE_H +#define LLVM_TRANSFORMS_IPO_CONSTANTMERGE_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A pass that merges duplicate global constants into a single constant. +class ConstantMergePass : public PassInfoMixin<ConstantMergePass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; +} + +#endif // LLVM_TRANSFORMS_IPO_CONSTANTMERGE_H diff --git a/include/llvm/Transforms/IPO/CrossDSOCFI.h b/include/llvm/Transforms/IPO/CrossDSOCFI.h new file mode 100644 index 000000000000..409604a7f330 --- /dev/null +++ b/include/llvm/Transforms/IPO/CrossDSOCFI.h @@ -0,0 +1,28 @@ +//===-- CrossDSOCFI.cpp - Externalize this module's CFI checks --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass exports all llvm.bitset's found in the module in the form of a +// __cfi_check function, which can be used to verify cross-DSO call targets. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_CROSSDSOCFI_H +#define LLVM_TRANSFORMS_IPO_CROSSDSOCFI_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class CrossDSOCFIPass : public PassInfoMixin<CrossDSOCFIPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; +} +#endif // LLVM_TRANSFORMS_IPO_CROSSDSOCFI_H + diff --git a/include/llvm/Transforms/IPO/DeadArgumentElimination.h b/include/llvm/Transforms/IPO/DeadArgumentElimination.h new file mode 100644 index 000000000000..e179afa956f6 --- /dev/null +++ b/include/llvm/Transforms/IPO/DeadArgumentElimination.h @@ -0,0 +1,133 @@ +//===- DeadArgumentElimination.h - Eliminate Dead Args ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass deletes dead arguments from internal functions. Dead argument +// elimination removes arguments which are directly dead, as well as arguments +// only passed into function calls as dead arguments of other functions. This +// pass also deletes dead return values in a similar way. +// +// This pass is often useful as a cleanup pass to run after aggressive +// interprocedural passes, which add possibly-dead arguments or return values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_DEADARGUMENTELIMINATION_H +#define LLVM_TRANSFORMS_IPO_DEADARGUMENTELIMINATION_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +#include <map> +#include <set> +#include <string> + +namespace llvm { + +/// Eliminate dead arguments (and return values) from functions. +class DeadArgumentEliminationPass + : public PassInfoMixin<DeadArgumentEliminationPass> { +public: + /// Struct that represents (part of) either a return value or a function + /// argument. Used so that arguments and return values can be used + /// interchangeably. + struct RetOrArg { + RetOrArg(const Function *F, unsigned Idx, bool IsArg) + : F(F), Idx(Idx), IsArg(IsArg) {} + const Function *F; + unsigned Idx; + bool IsArg; + + /// Make RetOrArg comparable, so we can put it into a map. + bool operator<(const RetOrArg &O) const { + return std::tie(F, Idx, IsArg) < std::tie(O.F, O.Idx, O.IsArg); + } + + /// Make RetOrArg comparable, so we can easily iterate the multimap. + bool operator==(const RetOrArg &O) const { + return F == O.F && Idx == O.Idx && IsArg == O.IsArg; + } + + std::string getDescription() const { + return (Twine(IsArg ? "Argument #" : "Return value #") + Twine(Idx) + + " of function " + F->getName()) + .str(); + } + }; + + /// Liveness enum - During our initial pass over the program, we determine + /// that things are either alive or maybe alive. We don't mark anything + /// explicitly dead (even if we know they are), since anything not alive + /// with no registered uses (in Uses) will never be marked alive and will + /// thus become dead in the end. + enum Liveness { Live, MaybeLive }; + + /// Convenience wrapper + RetOrArg CreateRet(const Function *F, unsigned Idx) { + return RetOrArg(F, Idx, false); + } + /// Convenience wrapper + RetOrArg CreateArg(const Function *F, unsigned Idx) { + return RetOrArg(F, Idx, true); + } + + typedef std::multimap<RetOrArg, RetOrArg> UseMap; + /// This maps a return value or argument to any MaybeLive return values or + /// arguments it uses. This allows the MaybeLive values to be marked live + /// when any of its users is marked live. + /// For example (indices are left out for clarity): + /// - Uses[ret F] = ret G + /// This means that F calls G, and F returns the value returned by G. + /// - Uses[arg F] = ret G + /// This means that some function calls G and passes its result as an + /// argument to F. + /// - Uses[ret F] = arg F + /// This means that F returns one of its own arguments. + /// - Uses[arg F] = arg G + /// This means that G calls F and passes one of its own (G's) arguments + /// directly to F. + UseMap Uses; + + typedef std::set<RetOrArg> LiveSet; + typedef std::set<const Function *> LiveFuncSet; + + /// This set contains all values that have been determined to be live. + LiveSet LiveValues; + /// This set contains all values that are cannot be changed in any way. + LiveFuncSet LiveFunctions; + + typedef SmallVector<RetOrArg, 5> UseVector; + + /// This allows this pass to do double-duty as the dead arg hacking pass + /// (used only by bugpoint). + bool ShouldHackArguments = false; + +public: + DeadArgumentEliminationPass(bool ShouldHackArguments_ = false) + : ShouldHackArguments(ShouldHackArguments_) {} + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + +private: + Liveness MarkIfNotLive(RetOrArg Use, UseVector &MaybeLiveUses); + Liveness SurveyUse(const Use *U, UseVector &MaybeLiveUses, + unsigned RetValNum = -1U); + Liveness SurveyUses(const Value *V, UseVector &MaybeLiveUses); + + void SurveyFunction(const Function &F); + void MarkValue(const RetOrArg &RA, Liveness L, + const UseVector &MaybeLiveUses); + void MarkLive(const RetOrArg &RA); + void MarkLive(const Function &F); + void PropagateLiveness(const RetOrArg &RA); + bool RemoveDeadStuffFromFunction(Function *F); + bool DeleteDeadVarargs(Function &Fn); + bool RemoveDeadArgumentsFromCallers(Function &Fn); +}; +} + +#endif // LLVM_TRANSFORMS_IPO_DEADARGUMENTELIMINATION_H diff --git a/include/llvm/Transforms/IPO/ElimAvailExtern.h b/include/llvm/Transforms/IPO/ElimAvailExtern.h new file mode 100644 index 000000000000..88a0e9bd8ce0 --- /dev/null +++ b/include/llvm/Transforms/IPO/ElimAvailExtern.h @@ -0,0 +1,31 @@ +//===- ElimAvailExtern.h - Optimize Global Variables ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This transform is designed to eliminate available external global +// definitions from the program, turning them into declarations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_ELIMAVAILEXTERN_H +#define LLVM_TRANSFORMS_IPO_ELIMAVAILEXTERN_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A pass that transforms external global definitions into declarations. +class EliminateAvailableExternallyPass + : public PassInfoMixin<EliminateAvailableExternallyPass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; +} + +#endif // LLVM_TRANSFORMS_IPO_ELIMAVAILEXTERN_H diff --git a/include/llvm/Transforms/IPO/ForceFunctionAttrs.h b/include/llvm/Transforms/IPO/ForceFunctionAttrs.h index 0ff4afe79b0c..ff8a6546f059 100644 --- a/include/llvm/Transforms/IPO/ForceFunctionAttrs.h +++ b/include/llvm/Transforms/IPO/ForceFunctionAttrs.h @@ -21,10 +21,8 @@ namespace llvm { /// Pass which forces specific function attributes into the IR, primarily as /// a debugging tool. -class ForceFunctionAttrsPass { -public: - static StringRef name() { return "ForceFunctionAttrsPass"; } - PreservedAnalyses run(Module &M); +struct ForceFunctionAttrsPass : PassInfoMixin<ForceFunctionAttrsPass> { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); }; /// Create a legacy pass manager instance of a pass to force function attrs. diff --git a/include/llvm/Transforms/IPO/FunctionAttrs.h b/include/llvm/Transforms/IPO/FunctionAttrs.h new file mode 100644 index 000000000000..c44cc43fc0f6 --- /dev/null +++ b/include/llvm/Transforms/IPO/FunctionAttrs.h @@ -0,0 +1,57 @@ +//===-- FunctionAttrs.h - Compute function attrs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Provides passes for computing function attributes based on interprocedural +/// analyses. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H +#define LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H + +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Computes function attributes in post-order over the call graph. +/// +/// By operating in post-order, this pass computes precise attributes for +/// called functions prior to processsing their callers. This "bottom-up" +/// approach allows powerful interprocedural inference of function attributes +/// like memory access patterns, etc. It can discover functions that do not +/// access memory, or only read memory, and give them the readnone/readonly +/// attribute. It also discovers function arguments that are not captured by +/// the function and marks them with the nocapture attribute. +struct PostOrderFunctionAttrsPass : PassInfoMixin<PostOrderFunctionAttrsPass> { + PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM); +}; + +/// Create a legacy pass manager instance of a pass to compute function attrs +/// in post-order. +Pass *createPostOrderFunctionAttrsLegacyPass(); + +/// A pass to do RPO deduction and propagation of function attributes. +/// +/// This pass provides a general RPO or "top down" propagation of +/// function attributes. For a few (rare) cases, we can deduce significantly +/// more about function attributes by working in RPO, so this pass +/// provides the compliment to the post-order pass above where the majority of +/// deduction is performed. +// FIXME: Currently there is no RPO CGSCC pass structure to slide into and so +// this is a boring module pass, but eventually it should be an RPO CGSCC pass +// when such infrastructure is available. +class ReversePostOrderFunctionAttrsPass + : public PassInfoMixin<ReversePostOrderFunctionAttrsPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H diff --git a/include/llvm/Transforms/IPO/FunctionImport.h b/include/llvm/Transforms/IPO/FunctionImport.h index d7707790a017..ba5db2b5c739 100644 --- a/include/llvm/Transforms/IPO/FunctionImport.h +++ b/include/llvm/Transforms/IPO/FunctionImport.h @@ -11,33 +11,113 @@ #define LLVM_FUNCTIONIMPORT_H #include "llvm/ADT/StringMap.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/ModuleSummaryIndex.h" + #include <functional> +#include <map> +#include <unordered_set> +#include <utility> namespace llvm { class LLVMContext; +class GlobalValueSummary; class Module; -class FunctionInfoIndex; /// The function importer is automatically importing function from other modules /// based on the provided summary informations. class FunctionImporter { +public: + /// Set of functions to import from a source module. Each entry is a map + /// containing all the functions to import for a source module. + /// The keys is the GUID identifying a function to import, and the value + /// is the threshold applied when deciding to import it. + typedef std::map<GlobalValue::GUID, unsigned> FunctionsToImportTy; - /// The summaries index used to trigger importing. - const FunctionInfoIndex &Index; + /// The map contains an entry for every module to import from, the key being + /// the module identifier to pass to the ModuleLoader. The value is the set of + /// functions to import. + typedef StringMap<FunctionsToImportTy> ImportMapTy; - /// Factory function to load a Module for a given identifier - std::function<std::unique_ptr<Module>(StringRef Identifier)> ModuleLoader; + /// The set contains an entry for every global value the module exports. + typedef std::unordered_set<GlobalValue::GUID> ExportSetTy; -public: /// Create a Function Importer. FunctionImporter( - const FunctionInfoIndex &Index, + const ModuleSummaryIndex &Index, std::function<std::unique_ptr<Module>(StringRef Identifier)> ModuleLoader) - : Index(Index), ModuleLoader(ModuleLoader) {} + : Index(Index), ModuleLoader(std::move(ModuleLoader)) {} + + /// Import functions in Module \p M based on the supplied import list. + /// \p ForceImportReferencedDiscardableSymbols will set the ModuleLinker in + /// a mode where referenced discarable symbols in the source modules will be + /// imported as well even if they are not present in the ImportList. + bool importFunctions(Module &M, const ImportMapTy &ImportList, + bool ForceImportReferencedDiscardableSymbols = false); - /// Import functions in Module \p M based on the summary informations. - bool importFunctions(Module &M); +private: + /// The summaries index used to trigger importing. + const ModuleSummaryIndex &Index; + + /// Factory function to load a Module for a given identifier + std::function<std::unique_ptr<Module>(StringRef Identifier)> ModuleLoader; }; + +/// Compute all the imports and exports for every module in the Index. +/// +/// \p ModuleToDefinedGVSummaries contains for each Module a map +/// (GUID -> Summary) for every global defined in the module. +/// +/// \p ImportLists will be populated with an entry for every Module we are +/// importing into. This entry is itself a map that can be passed to +/// FunctionImporter::importFunctions() above (see description there). +/// +/// \p ExportLists contains for each Module the set of globals (GUID) that will +/// be imported by another module, or referenced by such a function. I.e. this +/// is the set of globals that need to be promoted/renamed appropriately. +void ComputeCrossModuleImport( + const ModuleSummaryIndex &Index, + const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries, + StringMap<FunctionImporter::ImportMapTy> &ImportLists, + StringMap<FunctionImporter::ExportSetTy> &ExportLists); + +/// Compute all the imports for the given module using the Index. +/// +/// \p ImportList will be populated with a map that can be passed to +/// FunctionImporter::importFunctions() above (see description there). +void ComputeCrossModuleImportForModule( + StringRef ModulePath, const ModuleSummaryIndex &Index, + FunctionImporter::ImportMapTy &ImportList); + +/// Compute the set of summaries needed for a ThinLTO backend compilation of +/// \p ModulePath. +// +/// This includes summaries from that module (in case any global summary based +/// optimizations were recorded) and from any definitions in other modules that +/// should be imported. +// +/// \p ModuleToSummariesForIndex will be populated with the needed summaries +/// from each required module path. Use a std::map instead of StringMap to get +/// stable order for bitcode emission. +void gatherImportedSummariesForModule( + StringRef ModulePath, + const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries, + const StringMap<FunctionImporter::ImportMapTy> &ImportLists, + std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex); + +std::error_code +EmitImportsFiles(StringRef ModulePath, StringRef OutputFilename, + const StringMap<FunctionImporter::ImportMapTy> &ImportLists); + +/// Resolve WeakForLinker values in \p TheModule based on the information +/// recorded in the summaries during global summary-based analysis. +void thinLTOResolveWeakForLinkerModule(Module &TheModule, + const GVSummaryMapTy &DefinedGlobals); + +/// Internalize \p TheModule based on the information recorded in the summaries +/// during global summary-based analysis. +void thinLTOInternalizeModule(Module &TheModule, + const GVSummaryMapTy &DefinedGlobals); } #endif // LLVM_FUNCTIONIMPORT_H diff --git a/include/llvm/Transforms/IPO/GlobalDCE.h b/include/llvm/Transforms/IPO/GlobalDCE.h new file mode 100644 index 000000000000..57e174c2a37f --- /dev/null +++ b/include/llvm/Transforms/IPO/GlobalDCE.h @@ -0,0 +1,46 @@ +//===-- GlobalDCE.h - DCE unreachable internal functions ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This transform is designed to eliminate unreachable internal globals from the +// program. It uses an aggressive algorithm, searching out globals that are +// known to be alive. After it finds all of the globals which are needed, it +// deletes whatever is left over. This allows it to delete recursive chunks of +// the program which are unreachable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_GLOBALDCE_H +#define LLVM_TRANSFORMS_IPO_GLOBALDCE_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include <unordered_map> + +namespace llvm { + +/// Pass to remove unused function declarations. +class GlobalDCEPass : public PassInfoMixin<GlobalDCEPass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + +private: + SmallPtrSet<GlobalValue*, 32> AliveGlobals; + SmallPtrSet<Constant *, 8> SeenConstants; + std::unordered_multimap<Comdat *, GlobalValue *> ComdatMembers; + + /// Mark the specific global value as needed, and + /// recursively mark anything that it uses as also needed. + void GlobalIsNeeded(GlobalValue *GV); + void MarkUsedGlobalsAsNeeded(Constant *C); + bool RemoveUnusedGlobalValue(GlobalValue &GV); +}; + +} + +#endif // LLVM_TRANSFORMS_IPO_GLOBALDCE_H diff --git a/include/llvm/Transforms/IPO/GlobalOpt.h b/include/llvm/Transforms/IPO/GlobalOpt.h new file mode 100644 index 000000000000..5a25a6db4390 --- /dev/null +++ b/include/llvm/Transforms/IPO/GlobalOpt.h @@ -0,0 +1,32 @@ +//===- GlobalOpt.h - Optimize Global Variables ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass transforms simple global variables that never have their address +// taken. If obviously true, it marks read/write globals as constant, deletes +// variables only stored to, etc. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_GLOBALOPT_H +#define LLVM_TRANSFORMS_IPO_GLOBALOPT_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Optimize globals that never have their address taken. +class GlobalOptPass : public PassInfoMixin<GlobalOptPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +} + +#endif // LLVM_TRANSFORMS_IPO_GLOBALOPT_H diff --git a/include/llvm/Transforms/IPO/InferFunctionAttrs.h b/include/llvm/Transforms/IPO/InferFunctionAttrs.h index 80afc02c62ae..f5cbf9eb0613 100644 --- a/include/llvm/Transforms/IPO/InferFunctionAttrs.h +++ b/include/llvm/Transforms/IPO/InferFunctionAttrs.h @@ -23,10 +23,8 @@ namespace llvm { /// A pass which infers function attributes from the names and signatures of /// function declarations in a module. -class InferFunctionAttrsPass { -public: - static StringRef name() { return "InferFunctionAttrsPass"; } - PreservedAnalyses run(Module &M, AnalysisManager<Module> *AM); +struct InferFunctionAttrsPass : PassInfoMixin<InferFunctionAttrsPass> { + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); }; /// Create a legacy pass manager instance of a pass to infer function diff --git a/include/llvm/Transforms/IPO/InlinerPass.h b/include/llvm/Transforms/IPO/InlinerPass.h index 58ef0cbbfb5d..59e10608a9ba 100644 --- a/include/llvm/Transforms/IPO/InlinerPass.h +++ b/include/llvm/Transforms/IPO/InlinerPass.h @@ -24,6 +24,7 @@ class AssumptionCacheTracker; class CallSite; class DataLayout; class InlineCost; +class ProfileSummaryInfo; template <class PtrType, unsigned SmallSize> class SmallPtrSet; /// Inliner - This class contains all of the helper code which is used to @@ -31,7 +32,7 @@ template <class PtrType, unsigned SmallSize> class SmallPtrSet; /// struct Inliner : public CallGraphSCCPass { explicit Inliner(char &ID); - explicit Inliner(char &ID, int Threshold, bool InsertLifetime); + explicit Inliner(char &ID, bool InsertLifetime); /// getAnalysisUsage - For this class, we declare that we require and preserve /// the call graph. If the derived class implements this method, it should @@ -47,18 +48,6 @@ struct Inliner : public CallGraphSCCPass { // processing to avoid breaking the SCC traversal. bool doFinalization(CallGraph &CG) override; - /// This method returns the value specified by the -inline-threshold value, - /// specified on the command line. This is typically not directly needed. - /// - unsigned getInlineThreshold() const { return InlineThreshold; } - - /// Calculate the inline threshold for given Caller. This threshold is lower - /// if the caller is marked with OptimizeForSize and -inline-threshold is not - /// given on the comand line. It is higher if the callee is marked with the - /// inlinehint attribute. - /// - unsigned getInlineThreshold(CallSite CS) const; - /// getInlineCost - This method must be implemented by the subclass to /// determine the cost of inlining the specified call site. If the cost /// returned is greater than the current inline threshold, the call site is @@ -74,19 +63,30 @@ struct Inliner : public CallGraphSCCPass { /// deal with that subset of the functions. bool removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly = false); -private: - // InlineThreshold - Cache the value here for easy access. - unsigned InlineThreshold; + /// This function performs the main work of the pass. The default + /// of Inlinter::runOnSCC() calls skipSCC() before calling this method, but + /// derived classes which cannot be skipped can override that method and + /// call this function unconditionally. + bool inlineCalls(CallGraphSCC &SCC); +private: // InsertLifetime - Insert @llvm.lifetime intrinsics. bool InsertLifetime; /// shouldInline - Return true if the inliner should attempt to /// inline at the given CallSite. bool shouldInline(CallSite CS); + /// Return true if inlining of CS can block the caller from being + /// inlined which is proved to be more beneficial. \p IC is the + /// estimated inline cost associated with callsite \p CS. + /// \p TotalAltCost will be set to the estimated cost of inlining the caller + /// if \p CS is suppressed for inlining. + bool shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC, + int &TotalAltCost); protected: AssumptionCacheTracker *ACT; + ProfileSummaryInfo *PSI; }; } // End llvm namespace diff --git a/include/llvm/Transforms/IPO/Internalize.h b/include/llvm/Transforms/IPO/Internalize.h new file mode 100644 index 000000000000..ba1b06877d3a --- /dev/null +++ b/include/llvm/Transforms/IPO/Internalize.h @@ -0,0 +1,79 @@ +//====- Internalize.h - Internalization API ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass loops over all of the functions and variables in the input module. +// If the function or variable does not need to be preserved according to the +// client supplied callback, it is marked as internal. +// +// This transformation would not be legal in a regular compilation, but it gets +// extra information from the linker about what is safe. +// +// For example: Internalizing a function with external linkage. Only if we are +// told it is only used from within this module, it is safe to do it. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_INTERNALIZE_H +#define LLVM_TRANSFORMS_IPO_INTERNALIZE_H + +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/PassManager.h" +#include <functional> +#include <set> + +namespace llvm { +class Module; +class CallGraph; + +/// A pass that internalizes all functions and variables other than those that +/// must be preserved according to \c MustPreserveGV. +class InternalizePass : public PassInfoMixin<InternalizePass> { + /// Client supplied callback to control wheter a symbol must be preserved. + const std::function<bool(const GlobalValue &)> MustPreserveGV; + /// Set of symbols private to the compiler that this pass should not touch. + StringSet<> AlwaysPreserved; + + /// Return false if we're allowed to internalize this GV. + bool shouldPreserveGV(const GlobalValue &GV); + /// Internalize GV if it is possible to do so, i.e. it is not externally + /// visible and is not a member of an externally visible comdat. + bool maybeInternalize(GlobalValue &GV, + const std::set<const Comdat *> &ExternalComdats); + /// If GV is part of a comdat and is externally visible, keep track of its + /// comdat so that we don't internalize any of its members. + void checkComdatVisibility(GlobalValue &GV, + std::set<const Comdat *> &ExternalComdats); + +public: + InternalizePass(); + InternalizePass(std::function<bool(const GlobalValue &)> MustPreserveGV) + : MustPreserveGV(std::move(MustPreserveGV)) {} + + /// Run the internalizer on \p TheModule, returns true if any changes was + /// made. + /// + /// If the CallGraph \p CG is supplied, it will be updated when + /// internalizing a function (by removing any edge from the "external node") + bool internalizeModule(Module &TheModule, CallGraph *CG = nullptr); + + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +/// Helper function to internalize functions and variables in a Module. +inline bool +internalizeModule(Module &TheModule, + std::function<bool(const GlobalValue &)> MustPreserveGV, + CallGraph *CG = nullptr) { + return InternalizePass(std::move(MustPreserveGV)) + .internalizeModule(TheModule, CG); +} +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_IPO_INTERNALIZE_H diff --git a/include/llvm/Transforms/IPO/LowerBitSets.h b/include/llvm/Transforms/IPO/LowerTypeTests.h index e5fb7b98fcb3..93d4fb94e2c4 100644 --- a/include/llvm/Transforms/IPO/LowerBitSets.h +++ b/include/llvm/Transforms/IPO/LowerTypeTests.h @@ -1,4 +1,4 @@ -//===- LowerBitSets.h - Bitset lowering pass --------------------*- C++ -*-===// +//===- LowerTypeTests.h - type metadata lowering pass -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,18 +7,21 @@ // //===----------------------------------------------------------------------===// // -// This file defines parts of the bitset lowering pass implementation that may -// be usefully unit tested. +// This file defines parts of the type test lowering pass implementation that +// may be usefully unit tested. // //===----------------------------------------------------------------------===// -#ifndef LLVM_TRANSFORMS_IPO_LOWERBITSETS_H -#define LLVM_TRANSFORMS_IPO_LOWERBITSETS_H +#ifndef LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H +#define LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" -#include <stdint.h> +#include <cstdint> +#include <cstring> #include <limits> #include <set> #include <vector> @@ -30,6 +33,8 @@ class GlobalObject; class Value; class raw_ostream; +namespace lowertypetests { + struct BitSetInfo { // The indices of the set bits in the bitset. std::set<uint64_t> Bits; @@ -196,6 +201,13 @@ struct ByteArrayBuilder { uint64_t &AllocByteOffset, uint8_t &AllocMask); }; -} // namespace llvm +} // end namespace lowertypetests + +class LowerTypeTestsPass : public PassInfoMixin<LowerTypeTestsPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H diff --git a/include/llvm/Transforms/IPO/PartialInlining.h b/include/llvm/Transforms/IPO/PartialInlining.h new file mode 100644 index 000000000000..48eb1e30a191 --- /dev/null +++ b/include/llvm/Transforms/IPO/PartialInlining.h @@ -0,0 +1,32 @@ +//===- PartialInlining.h - Inline parts of functions --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass performs partial inlining, typically by inlining an if statement +// that surrounds the body of the function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_PARTIALINLINING_H +#define LLVM_TRANSFORMS_IPO_PARTIALINLINING_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Pass to remove unused function declarations. +class PartialInlinerPass : public PassInfoMixin<PartialInlinerPass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + +private: + Function *unswitchFunction(Function *F); +}; +} +#endif // LLVM_TRANSFORMS_IPO_PARTIALINLINING_H diff --git a/include/llvm/Transforms/IPO/PassManagerBuilder.h b/include/llvm/Transforms/IPO/PassManagerBuilder.h index a4e7bce8ef4a..4f483deeefe5 100644 --- a/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ b/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -15,11 +15,13 @@ #ifndef LLVM_TRANSFORMS_IPO_PASSMANAGERBUILDER_H #define LLVM_TRANSFORMS_IPO_PASSMANAGERBUILDER_H +#include <functional> #include <memory> +#include <string> #include <vector> namespace llvm { -class FunctionInfoIndex; +class ModuleSummaryIndex; class Pass; class TargetLibraryInfoImpl; class TargetMachine; @@ -58,8 +60,9 @@ class PassManagerBuilder { public: /// Extensions are passed the builder itself (so they can see how it is /// configured) as well as the pass manager to add stuff to. - typedef void (*ExtensionFn)(const PassManagerBuilder &Builder, - legacy::PassManagerBase &PM); + typedef std::function<void(const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM)> + ExtensionFn; enum ExtensionPointTy { /// EP_EarlyAsPossible - This extension point allows adding passes before /// any other transformations, allowing them to see the code as it is coming @@ -116,8 +119,8 @@ public: /// added to the per-module passes. Pass *Inliner; - /// The function summary index to use for function importing. - const FunctionInfoIndex *FunctionIndex; + /// The module summary index to use for function importing. + const ModuleSummaryIndex *ModuleSummary; bool DisableTailCalls; bool DisableUnitAtATime; @@ -132,10 +135,17 @@ public: bool VerifyOutput; bool MergeFunctions; bool PrepareForLTO; + bool PrepareForThinLTO; + bool PerformThinLTO; + + /// Profile data file name that the instrumentation will be written to. + std::string PGOInstrGen; + /// Path of the profile data file. + std::string PGOInstrUse; private: /// ExtensionList - This is list of all of the extensions that are registered. - std::vector<std::pair<ExtensionPointTy, ExtensionFn> > Extensions; + std::vector<std::pair<ExtensionPointTy, ExtensionFn>> Extensions; public: PassManagerBuilder(); @@ -152,6 +162,9 @@ private: void addInitialAliasAnalysisPasses(legacy::PassManagerBase &PM) const; void addLTOOptimizationPasses(legacy::PassManagerBase &PM); void addLateLTOOptimizationPasses(legacy::PassManagerBase &PM); + void addPGOInstrPasses(legacy::PassManagerBase &MPM); + void addFunctionSimplificationPasses(legacy::PassManagerBase &MPM); + void addInstructionCombiningPass(legacy::PassManagerBase &MPM) const; public: /// populateFunctionPassManager - This fills in the function pass manager, @@ -162,6 +175,7 @@ public: /// populateModulePassManager - This sets up the primary pass manager. void populateModulePassManager(legacy::PassManagerBase &MPM); void populateLTOPassManager(legacy::PassManagerBase &PM); + void populateThinLTOPassManager(legacy::PassManagerBase &PM); }; /// Registers a function for adding a standard set of passes. This should be @@ -171,7 +185,7 @@ public: struct RegisterStandardPasses { RegisterStandardPasses(PassManagerBuilder::ExtensionPointTy Ty, PassManagerBuilder::ExtensionFn Fn) { - PassManagerBuilder::addGlobalExtension(Ty, Fn); + PassManagerBuilder::addGlobalExtension(Ty, std::move(Fn)); } }; diff --git a/include/llvm/Transforms/IPO/SCCP.h b/include/llvm/Transforms/IPO/SCCP.h new file mode 100644 index 000000000000..fab731342144 --- /dev/null +++ b/include/llvm/Transforms/IPO/SCCP.h @@ -0,0 +1,34 @@ +//===- SCCP.h - Sparse Conditional Constant Propagation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass implements interprocedural sparse conditional constant +// propagation and merging. +// +// Specifically, this: +// * Assumes values are constant unless proven otherwise +// * Assumes BasicBlocks are dead unless proven otherwise +// * Proves values to be constant, and replaces them with constants +// * Proves conditional branches to be unconditional +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_SCCP_H +#define LLVM_TRANSFORMS_IPO_SCCP_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +/// Pass to perform interprocedural constant propagation. +class IPSCCPPass : public PassInfoMixin<IPSCCPPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; +} +#endif // LLVM_TRANSFORMS_IPO_SCCP_H diff --git a/include/llvm/Transforms/IPO/StripDeadPrototypes.h b/include/llvm/Transforms/IPO/StripDeadPrototypes.h index 9dddd12871c4..5a05cd75c9d5 100644 --- a/include/llvm/Transforms/IPO/StripDeadPrototypes.h +++ b/include/llvm/Transforms/IPO/StripDeadPrototypes.h @@ -23,10 +23,8 @@ namespace llvm { /// Pass to remove unused function declarations. -class StripDeadPrototypesPass { -public: - static StringRef name() { return "StripDeadPrototypesPass"; } - PreservedAnalyses run(Module &M); +struct StripDeadPrototypesPass : PassInfoMixin<StripDeadPrototypesPass> { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); }; } diff --git a/include/llvm/Transforms/IPO/WholeProgramDevirt.h b/include/llvm/Transforms/IPO/WholeProgramDevirt.h new file mode 100644 index 000000000000..2bd20c95702c --- /dev/null +++ b/include/llvm/Transforms/IPO/WholeProgramDevirt.h @@ -0,0 +1,223 @@ +//===- WholeProgramDevirt.h - Whole-program devirt pass ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines parts of the whole-program devirtualization pass +// implementation that may be usefully unit tested. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H +#define LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include <cassert> +#include <cstdint> +#include <utility> +#include <vector> + +namespace llvm { + +template <typename T> class ArrayRef; +template <typename T> class MutableArrayRef; +class Function; +class GlobalVariable; + +namespace wholeprogramdevirt { + +// A bit vector that keeps track of which bits are used. We use this to +// pack constant values compactly before and after each virtual table. +struct AccumBitVector { + std::vector<uint8_t> Bytes; + + // Bits in BytesUsed[I] are 1 if matching bit in Bytes[I] is used, 0 if not. + std::vector<uint8_t> BytesUsed; + + std::pair<uint8_t *, uint8_t *> getPtrToData(uint64_t Pos, uint8_t Size) { + if (Bytes.size() < Pos + Size) { + Bytes.resize(Pos + Size); + BytesUsed.resize(Pos + Size); + } + return std::make_pair(Bytes.data() + Pos, BytesUsed.data() + Pos); + } + + // Set little-endian value Val with size Size at bit position Pos, + // and mark bytes as used. + void setLE(uint64_t Pos, uint64_t Val, uint8_t Size) { + assert(Pos % 8 == 0); + auto DataUsed = getPtrToData(Pos / 8, Size); + for (unsigned I = 0; I != Size; ++I) { + DataUsed.first[I] = Val >> (I * 8); + assert(!DataUsed.second[I]); + DataUsed.second[I] = 0xff; + } + } + + // Set big-endian value Val with size Size at bit position Pos, + // and mark bytes as used. + void setBE(uint64_t Pos, uint64_t Val, uint8_t Size) { + assert(Pos % 8 == 0); + auto DataUsed = getPtrToData(Pos / 8, Size); + for (unsigned I = 0; I != Size; ++I) { + DataUsed.first[Size - I - 1] = Val >> (I * 8); + assert(!DataUsed.second[Size - I - 1]); + DataUsed.second[Size - I - 1] = 0xff; + } + } + + // Set bit at bit position Pos to b and mark bit as used. + void setBit(uint64_t Pos, bool b) { + auto DataUsed = getPtrToData(Pos / 8, 1); + if (b) + *DataUsed.first |= 1 << (Pos % 8); + assert(!(*DataUsed.second & (1 << Pos % 8))); + *DataUsed.second |= 1 << (Pos % 8); + } +}; + +// The bits that will be stored before and after a particular vtable. +struct VTableBits { + // The vtable global. + GlobalVariable *GV; + + // Cache of the vtable's size in bytes. + uint64_t ObjectSize = 0; + + // The bit vector that will be laid out before the vtable. Note that these + // bytes are stored in reverse order until the globals are rebuilt. This means + // that any values in the array must be stored using the opposite endianness + // from the target. + AccumBitVector Before; + + // The bit vector that will be laid out after the vtable. + AccumBitVector After; +}; + +// Information about a member of a particular type identifier. +struct TypeMemberInfo { + // The VTableBits for the vtable. + VTableBits *Bits; + + // The offset in bytes from the start of the vtable (i.e. the address point). + uint64_t Offset; + + bool operator<(const TypeMemberInfo &other) const { + return Bits < other.Bits || (Bits == other.Bits && Offset < other.Offset); + } +}; + +// A virtual call target, i.e. an entry in a particular vtable. +struct VirtualCallTarget { + VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM); + + // For testing only. + VirtualCallTarget(const TypeMemberInfo *TM, bool IsBigEndian) + : Fn(nullptr), TM(TM), IsBigEndian(IsBigEndian) {} + + // The function stored in the vtable. + Function *Fn; + + // A pointer to the type identifier member through which the pointer to Fn is + // accessed. + const TypeMemberInfo *TM; + + // When doing virtual constant propagation, this stores the return value for + // the function when passed the currently considered argument list. + uint64_t RetVal; + + // Whether the target is big endian. + bool IsBigEndian; + + // The minimum byte offset before the address point. This covers the bytes in + // the vtable object before the address point (e.g. RTTI, access-to-top, + // vtables for other base classes) and is equal to the offset from the start + // of the vtable object to the address point. + uint64_t minBeforeBytes() const { return TM->Offset; } + + // The minimum byte offset after the address point. This covers the bytes in + // the vtable object after the address point (e.g. the vtable for the current + // class and any later base classes) and is equal to the size of the vtable + // object minus the offset from the start of the vtable object to the address + // point. + uint64_t minAfterBytes() const { return TM->Bits->ObjectSize - TM->Offset; } + + // The number of bytes allocated (for the vtable plus the byte array) before + // the address point. + uint64_t allocatedBeforeBytes() const { + return minBeforeBytes() + TM->Bits->Before.Bytes.size(); + } + + // The number of bytes allocated (for the vtable plus the byte array) after + // the address point. + uint64_t allocatedAfterBytes() const { + return minAfterBytes() + TM->Bits->After.Bytes.size(); + } + + // Set the bit at position Pos before the address point to RetVal. + void setBeforeBit(uint64_t Pos) { + assert(Pos >= 8 * minBeforeBytes()); + TM->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal); + } + + // Set the bit at position Pos after the address point to RetVal. + void setAfterBit(uint64_t Pos) { + assert(Pos >= 8 * minAfterBytes()); + TM->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal); + } + + // Set the bytes at position Pos before the address point to RetVal. + // Because the bytes in Before are stored in reverse order, we use the + // opposite endianness to the target. + void setBeforeBytes(uint64_t Pos, uint8_t Size) { + assert(Pos >= 8 * minBeforeBytes()); + if (IsBigEndian) + TM->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size); + else + TM->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size); + } + + // Set the bytes at position Pos after the address point to RetVal. + void setAfterBytes(uint64_t Pos, uint8_t Size) { + assert(Pos >= 8 * minAfterBytes()); + if (IsBigEndian) + TM->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size); + else + TM->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size); + } +}; + +// Find the minimum offset that we may store a value of size Size bits at. If +// IsAfter is set, look for an offset before the object, otherwise look for an +// offset after the object. +uint64_t findLowestOffset(ArrayRef<VirtualCallTarget> Targets, bool IsAfter, + uint64_t Size); + +// Set the stored value in each of Targets to VirtualCallTarget::RetVal at the +// given allocation offset before the vtable address. Stores the computed +// byte/bit offset to OffsetByte/OffsetBit. +void setBeforeReturnValues(MutableArrayRef<VirtualCallTarget> Targets, + uint64_t AllocBefore, unsigned BitWidth, + int64_t &OffsetByte, uint64_t &OffsetBit); + +// Set the stored value in each of Targets to VirtualCallTarget::RetVal at the +// given allocation offset after the vtable address. Stores the computed +// byte/bit offset to OffsetByte/OffsetBit. +void setAfterReturnValues(MutableArrayRef<VirtualCallTarget> Targets, + uint64_t AllocAfter, unsigned BitWidth, + int64_t &OffsetByte, uint64_t &OffsetBit); + +} // end namespace wholeprogramdevirt + +struct WholeProgramDevirtPass : public PassInfoMixin<WholeProgramDevirtPass> { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H diff --git a/include/llvm/Transforms/InstCombine/InstCombine.h b/include/llvm/Transforms/InstCombine/InstCombine.h index f48ec13107bc..d70b847c6892 100644 --- a/include/llvm/Transforms/InstCombine/InstCombine.h +++ b/include/llvm/Transforms/InstCombine/InstCombine.h @@ -24,23 +24,47 @@ namespace llvm { -class InstCombinePass { +class InstCombinePass : public PassInfoMixin<InstCombinePass> { InstCombineWorklist Worklist; + bool ExpensiveCombines; public: static StringRef name() { return "InstCombinePass"; } // Explicitly define constructors for MSVC. - InstCombinePass() {} - InstCombinePass(InstCombinePass &&Arg) : Worklist(std::move(Arg.Worklist)) {} + InstCombinePass(bool ExpensiveCombines = true) + : ExpensiveCombines(ExpensiveCombines) {} + InstCombinePass(InstCombinePass &&Arg) + : Worklist(std::move(Arg.Worklist)), + ExpensiveCombines(Arg.ExpensiveCombines) {} InstCombinePass &operator=(InstCombinePass &&RHS) { Worklist = std::move(RHS.Worklist); + ExpensiveCombines = RHS.ExpensiveCombines; return *this; } - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; +/// \brief The legacy pass manager's instcombine pass. +/// +/// This is a basic whole-function wrapper around the instcombine utility. It +/// will try to combine all instructions in the function. +class InstructionCombiningPass : public FunctionPass { + InstCombineWorklist Worklist; + const bool ExpensiveCombines; + +public: + static char ID; // Pass identification, replacement for typeid + + InstructionCombiningPass(bool ExpensiveCombines = true) + : FunctionPass(ID), ExpensiveCombines(ExpensiveCombines) { + initializeInstructionCombiningPassPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnFunction(Function &F) override; +}; } #endif diff --git a/include/llvm/Transforms/InstCombine/InstCombineWorklist.h b/include/llvm/Transforms/InstCombine/InstCombineWorklist.h index 5d2b2d000009..32af035d07d4 100644 --- a/include/llvm/Transforms/InstCombine/InstCombineWorklist.h +++ b/include/llvm/Transforms/InstCombine/InstCombineWorklist.h @@ -11,6 +11,7 @@ #define LLVM_TRANSFORMS_INSTCOMBINE_INSTCOMBINEWORKLIST_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Instruction.h" #include "llvm/Support/Compiler.h" @@ -63,7 +64,7 @@ public: void AddInitialGroup(ArrayRef<Instruction *> List) { assert(Worklist.empty() && "Worklist must be empty to add initial group"); Worklist.reserve(List.size()+16); - WorklistMap.resize(List.size()); + WorklistMap.reserve(List.size()); DEBUG(dbgs() << "IC: ADDING: " << List.size() << " instrs to worklist\n"); unsigned Idx = 0; for (Instruction *I : reverse(List)) { diff --git a/include/llvm/Transforms/InstrProfiling.h b/include/llvm/Transforms/InstrProfiling.h new file mode 100644 index 000000000000..9ac6d63b96ae --- /dev/null +++ b/include/llvm/Transforms/InstrProfiling.h @@ -0,0 +1,105 @@ +//===- Transforms/InstrProfiling.h - Instrumentation passes ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides the interface for LLVM's PGO Instrumentation lowering +/// pass. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_INSTRPROFILING_H +#define LLVM_TRANSFORMS_INSTRPROFILING_H + +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Transforms/Instrumentation.h" + +namespace llvm { + +/// Instrumenation based profiling lowering pass. This pass lowers +/// the profile instrumented code generated by FE or the IR based +/// instrumentation pass. +class InstrProfiling : public PassInfoMixin<InstrProfiling> { +public: + InstrProfiling() {} + InstrProfiling(const InstrProfOptions &Options) : Options(Options) {} + + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); + bool run(Module &M); + +private: + InstrProfOptions Options; + Module *M; + struct PerFunctionProfileData { + uint32_t NumValueSites[IPVK_Last + 1]; + GlobalVariable *RegionCounters; + GlobalVariable *DataVar; + PerFunctionProfileData() : RegionCounters(nullptr), DataVar(nullptr) { + memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last + 1)); + } + }; + DenseMap<GlobalVariable *, PerFunctionProfileData> ProfileDataMap; + std::vector<Value *> UsedVars; + std::vector<GlobalVariable *> ReferencedNames; + GlobalVariable *NamesVar; + size_t NamesSize; + + bool isMachO() const; + + /// Get the section name for the counter variables. + StringRef getCountersSection() const; + + /// Get the section name for the name variables. + StringRef getNameSection() const; + + /// Get the section name for the profile data variables. + StringRef getDataSection() const; + + /// Get the section name for the coverage mapping data. + StringRef getCoverageSection() const; + + /// Count the number of instrumented value sites for the function. + void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins); + + /// Replace instrprof_value_profile with a call to runtime library. + void lowerValueProfileInst(InstrProfValueProfileInst *Ins); + + /// Replace instrprof_increment with an increment of the appropriate value. + void lowerIncrement(InstrProfIncrementInst *Inc); + + /// Force emitting of name vars for unused functions. + void lowerCoverageData(GlobalVariable *CoverageNamesVar); + + /// Get the region counters for an increment, creating them if necessary. + /// + /// If the counter array doesn't yet exist, the profile data variables + /// referring to them will also be created. + GlobalVariable *getOrCreateRegionCounters(InstrProfIncrementInst *Inc); + + /// Emit the section with compressed function names. + void emitNameData(); + + /// Emit value nodes section for value profiling. + void emitVNodes(); + + /// Emit runtime registration functions for each profile data variable. + void emitRegistration(); + + /// Emit the necessary plumbing to pull in the runtime initialization. + void emitRuntimeHook(); + + /// Add uses of our data variables and runtime hook. + void emitUses(); + + /// Create a static initializer for our data, on platforms that need it, + /// and for any profile output file that was specified. + void emitInitialization(); +}; + +} // End llvm namespace +#endif diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 38dfeb04ace3..09eef7e0750e 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -80,9 +80,10 @@ ModulePass *createGCOVProfilerPass(const GCOVOptions &Options = GCOVOptions::getDefault()); // PGO Instrumention -ModulePass *createPGOInstrumentationGenPass(); +ModulePass *createPGOInstrumentationGenLegacyPass(); ModulePass * -createPGOInstrumentationUsePass(StringRef Filename = StringRef("")); +createPGOInstrumentationUseLegacyPass(StringRef Filename = StringRef("")); +ModulePass *createPGOIndirectCallPromotionLegacyPass(bool InLTO = false); /// Options for the frontend instrumentation based profiling pass. struct InstrProfOptions { @@ -96,12 +97,13 @@ struct InstrProfOptions { }; /// Insert frontend instrumentation based profiling. -ModulePass *createInstrProfilingPass( +ModulePass *createInstrProfilingLegacyPass( const InstrProfOptions &Options = InstrProfOptions()); // Insert AddressSanitizer (address sanity checking) instrumentation FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false, - bool Recover = false); + bool Recover = false, + bool UseAfterScope = false); ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false, bool Recover = false); @@ -116,11 +118,25 @@ ModulePass *createDataFlowSanitizerPass( const std::vector<std::string> &ABIListFiles = std::vector<std::string>(), void *(*getArgTLS)() = nullptr, void *(*getRetValTLS)() = nullptr); +// Options for EfficiencySanitizer sub-tools. +struct EfficiencySanitizerOptions { + EfficiencySanitizerOptions() : ToolType(ESAN_None) {} + enum Type { + ESAN_None = 0, + ESAN_CacheFrag, + ESAN_WorkingSet, + } ToolType; +}; + +// Insert EfficiencySanitizer instrumentation. +ModulePass *createEfficiencySanitizerPass( + const EfficiencySanitizerOptions &Options = EfficiencySanitizerOptions()); + // Options for sanitizer coverage instrumentation. struct SanitizerCoverageOptions { SanitizerCoverageOptions() : CoverageType(SCK_None), IndirectCalls(false), TraceBB(false), - TraceCmp(false), Use8bitCounters(false) {} + TraceCmp(false), Use8bitCounters(false), TracePC(false) {} enum Type { SCK_None = 0, @@ -132,6 +148,7 @@ struct SanitizerCoverageOptions { bool TraceBB; bool TraceCmp; bool Use8bitCounters; + bool TracePC; }; // Insert SanitizerCoverage instrumentation. @@ -150,10 +167,6 @@ inline ModulePass *createDataFlowSanitizerPassForJIT( // checking on loads, stores, and other memory intrinsics. FunctionPass *createBoundsCheckingPass(); -/// \brief This pass splits the stack into a safe stack and an unsafe stack to -/// protect against stack-based overflow vulnerabilities. -FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr); - /// \brief Calculate what to divide by to scale counts. /// /// Given the maximum count, calculate a divisor that will scale all the diff --git a/include/llvm/Transforms/PGOInstrumentation.h b/include/llvm/Transforms/PGOInstrumentation.h new file mode 100644 index 000000000000..f6b5639e5aad --- /dev/null +++ b/include/llvm/Transforms/PGOInstrumentation.h @@ -0,0 +1,48 @@ +//===- Transforms/PGOInstrumentation.h - PGO gen/use passes ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides the interface for IR based instrumentation passes ( +/// (profile-gen, and profile-use). +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_PGOINSTRUMENTATION_H +#define LLVM_TRANSFORMS_PGOINSTRUMENTATION_H + +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Instrumentation.h" + +namespace llvm { + +/// The instrumentation (profile-instr-gen) pass for IR based PGO. +class PGOInstrumentationGen : public PassInfoMixin<PGOInstrumentationGen> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +/// The profile annotation (profile-instr-use) pass for IR based PGO. +class PGOInstrumentationUse : public PassInfoMixin<PGOInstrumentationUse> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); + PGOInstrumentationUse(std::string Filename = ""); + +private: + std::string ProfileFileName; +}; + +/// The indirect function call promotion pass. +class PGOIndirectCallPromotion : public PassInfoMixin<PGOIndirectCallPromotion> { +public: + PGOIndirectCallPromotion(bool IsInLTO = false) : InLTO(IsInLTO) {} + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +private: + bool InLTO; +}; + +} // End llvm namespace +#endif diff --git a/include/llvm/Transforms/SampleProfile.h b/include/llvm/Transforms/SampleProfile.h new file mode 100644 index 000000000000..0fdfa2f85e54 --- /dev/null +++ b/include/llvm/Transforms/SampleProfile.h @@ -0,0 +1,27 @@ +//===- Transforms/SampleProfile.h - SamplePGO pass--------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides the interface for the sampled PGO loader pass. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SAMPLEPROFILE_H +#define LLVM_TRANSFORMS_SAMPLEPROFILE_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// The sample profiler data loader pass. +class SampleProfileLoaderPass : public PassInfoMixin<SampleProfileLoaderPass> { +public: + PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM); +}; + +} // End llvm namespace +#endif diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 9173de1112f3..167cc94ec81f 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -15,7 +15,6 @@ #ifndef LLVM_TRANSFORMS_SCALAR_H #define LLVM_TRANSFORMS_SCALAR_H -#include "llvm/ADT/StringRef.h" #include <functional> namespace llvm { @@ -82,6 +81,16 @@ FunctionPass *createDeadStoreEliminationPass(); // FunctionPass *createAggressiveDCEPass(); + +//===----------------------------------------------------------------------===// +// +// GuardWidening - An optimization over the @llvm.experimental.guard intrinsic +// that (optimistically) combines multiple guards into one to have fewer checks +// at runtime. +// +FunctionPass *createGuardWideningPass(); + + //===----------------------------------------------------------------------===// // // BitTrackingDCE - This pass uses a bit-tracking DCE algorithm in order to @@ -97,17 +106,6 @@ FunctionPass *createSROAPass(); //===----------------------------------------------------------------------===// // -// ScalarReplAggregates - Break up alloca's of aggregates into multiple allocas -// if possible. -// -FunctionPass *createScalarReplAggregatesPass(signed Threshold = -1, - bool UseDomTree = true, - signed StructMemberThreshold = -1, - signed ArrayElementThreshold = -1, - signed ScalarLoadThreshold = -1); - -//===----------------------------------------------------------------------===// -// // InductiveRangeCheckElimination - Transform loops to elide range checks on // linear functions of the induction variable. // @@ -132,7 +130,7 @@ Pass *createIndVarSimplifyPass(); // into: // %Z = add int 2, %X // -FunctionPass *createInstructionCombiningPass(); +FunctionPass *createInstructionCombiningPass(bool ExpensiveCombines = true); //===----------------------------------------------------------------------===// // @@ -156,16 +154,6 @@ Pass *createLoopStrengthReducePass(); //===----------------------------------------------------------------------===// // -// GlobalMerge - This pass merges internal (by default) globals into structs -// to enable reuse of a base pointer by indexed addressing modes. -// It can also be configured to focus on size optimizations only. -// -Pass *createGlobalMergePass(const TargetMachine *TM, unsigned MaximalOffset, - bool OnlyOptimizeForSize = false, - bool MergeExternalByDefault = false); - -//===----------------------------------------------------------------------===// -// // LoopUnswitch - This pass is a simple loop unswitching pass. // Pass *createLoopUnswitchPass(bool OptimizeForSize = false); @@ -205,6 +193,12 @@ Pass *createLoopIdiomPass(); //===----------------------------------------------------------------------===// // +// LoopVersioningLICM - This pass is a loop versioning pass for LICM. +// +Pass *createLoopVersioningLICMPass(); + +//===----------------------------------------------------------------------===// +// // PromoteMemoryToRegister - This pass is used to promote memory references to // be register references. A simple example of the transformation performed by // this pass is: @@ -262,7 +256,10 @@ FunctionPass *createFlattenCFGPass(); // // CFG Structurization - Remove irreducible control flow // -Pass *createStructurizeCFGPass(); +/// +/// When \p SkipUniformRegions is true the structizer will not structurize +/// regions that only contain uniform branches. +Pass *createStructurizeCFGPass(bool SkipUniformRegions = false); //===----------------------------------------------------------------------===// // @@ -329,17 +326,17 @@ FunctionPass *createEarlyCSEPass(); //===----------------------------------------------------------------------===// // -// MergedLoadStoreMotion - This pass merges loads and stores in diamonds. Loads -// are hoisted into the header, while stores sink into the footer. +// GVNHoist - This pass performs a simple and fast GVN pass over the dominator +// tree to hoist common expressions from sibling branches. // -FunctionPass *createMergedLoadStoreMotionPass(); +FunctionPass *createGVNHoistPass(); //===----------------------------------------------------------------------===// // -// GVN - This pass performs global value numbering and redundant load -// elimination cotemporaneously. +// MergedLoadStoreMotion - This pass merges loads and stores in diamonds. Loads +// are hoisted into the header, while stores sink into the footer. // -FunctionPass *createGVNPass(bool NoLoads = false); +FunctionPass *createMergedLoadStoreMotionPass(); //===----------------------------------------------------------------------===// // @@ -382,6 +379,12 @@ Pass *createLowerAtomicPass(); //===----------------------------------------------------------------------===// // +// LowerGuardIntrinsic - Lower guard intrinsics to normal control flow. +// +Pass *createLowerGuardIntrinsicPass(); + +//===----------------------------------------------------------------------===// +// // ValuePropagation - Propagate CFG-derived value information // Pass *createCorrelatedValuePropagationPass(); @@ -432,6 +435,10 @@ createSeparateConstOffsetFromGEPPass(const TargetMachine *TM = nullptr, // FunctionPass *createSpeculativeExecutionPass(); +// Same as createSpeculativeExecutionPass, but does nothing unless +// TargetTransformInfo::hasBranchDivergence() is true. +FunctionPass *createSpeculativeExecutionIfHasBranchDivergencePass(); + //===----------------------------------------------------------------------===// // // LoadCombine - Combine loads into bigger loads. @@ -478,7 +485,10 @@ FunctionPass *createNaryReassociatePass(); // // LoopDistribute - Distribute loops. // -FunctionPass *createLoopDistributePass(); +// ProcessAllLoopsByDefault instructs the pass to look for distribution +// opportunities in all loops unless -enable-loop-distribute or the +// llvm.loop.distribute.enable metadata data override this default. +FunctionPass *createLoopDistributePass(bool ProcessAllLoopsByDefault); //===----------------------------------------------------------------------===// // @@ -486,6 +496,28 @@ FunctionPass *createLoopDistributePass(); // FunctionPass *createLoopLoadEliminationPass(); +//===----------------------------------------------------------------------===// +// +// LoopSimplifyCFG - This pass performs basic CFG simplification on loops, +// primarily to help other loop passes. +// +Pass *createLoopSimplifyCFGPass(); + +//===----------------------------------------------------------------------===// +// +// LoopVersioning - Perform loop multi-versioning. +// +FunctionPass *createLoopVersioningPass(); + +//===----------------------------------------------------------------------===// +// +// LoopDataPrefetch - Perform data prefetching in loops. +// +FunctionPass *createLoopDataPrefetchPass(); + +///===---------------------------------------------------------------------===// +ModulePass *createNameAnonFunctionPass(); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Scalar/ADCE.h b/include/llvm/Transforms/Scalar/ADCE.h index f9bc7b77c14a..b9b7e1c0c99f 100644 --- a/include/llvm/Transforms/Scalar/ADCE.h +++ b/include/llvm/Transforms/Scalar/ADCE.h @@ -28,10 +28,8 @@ namespace llvm { /// instructions are dead until proven otherwise. This allows it to eliminate /// dead computations that other DCE passes do not catch, particularly involving /// loop computations. -class ADCEPass { -public: - static StringRef name() { return "ADCEPass"; } - PreservedAnalyses run(Function &F); +struct ADCEPass : PassInfoMixin<ADCEPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); }; } diff --git a/include/llvm/Transforms/Scalar/AlignmentFromAssumptions.h b/include/llvm/Transforms/Scalar/AlignmentFromAssumptions.h new file mode 100644 index 000000000000..f75dc4dc331d --- /dev/null +++ b/include/llvm/Transforms/Scalar/AlignmentFromAssumptions.h @@ -0,0 +1,51 @@ +//===---- AlignmentFromAssumptions.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a ScalarEvolution-based transformation to set +// the alignments of load, stores and memory intrinsics based on the truth +// expressions of assume intrinsics. The primary motivation is to handle +// complex alignment assumptions that apply to vector loads and stores that +// appear after vectorization and unrolling. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_ALIGNMENTFROMASSUMPTIONS_H +#define LLVM_TRANSFORMS_SCALAR_ALIGNMENTFROMASSUMPTIONS_H + +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct AlignmentFromAssumptionsPass + : public PassInfoMixin<AlignmentFromAssumptionsPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + // Glue for old PM. + bool runImpl(Function &F, AssumptionCache &AC, ScalarEvolution *SE_, + DominatorTree *DT_); + + // For memory transfers, we need a common alignment for both the source and + // destination. If we have a new alignment for only one operand of a transfer + // instruction, save it in these maps. If we reach the other operand through + // another assumption later, then we may change the alignment at that point. + DenseMap<MemTransferInst *, unsigned> NewDestAlignments, NewSrcAlignments; + + ScalarEvolution *SE = nullptr; + DominatorTree *DT = nullptr; + + bool extractAlignmentInfo(CallInst *I, Value *&AAPtr, const SCEV *&AlignSCEV, + const SCEV *&OffSCEV); + bool processAssumption(CallInst *I); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_ALIGNMENTFROMASSUMPTIONS_H diff --git a/include/llvm/Transforms/Scalar/BDCE.h b/include/llvm/Transforms/Scalar/BDCE.h new file mode 100644 index 000000000000..d7d2730a8033 --- /dev/null +++ b/include/llvm/Transforms/Scalar/BDCE.h @@ -0,0 +1,31 @@ +//===---- BDCE.cpp - Bit-tracking dead code elimination ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Bit-Tracking Dead Code Elimination pass. Some +// instructions (shifts, some ands, ors, etc.) kill some of their input bits. +// We track these dead bits and remove instructions that compute only these +// dead bits. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_BDCE_H +#define LLVM_TRANSFORMS_SCALAR_BDCE_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +// The Bit-Tracking Dead Code Elimination pass. +struct BDCEPass : PassInfoMixin<BDCEPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_BDCE_H diff --git a/include/llvm/Transforms/Scalar/ConstantHoisting.h b/include/llvm/Transforms/Scalar/ConstantHoisting.h new file mode 100644 index 000000000000..3e2b3327a9fe --- /dev/null +++ b/include/llvm/Transforms/Scalar/ConstantHoisting.h @@ -0,0 +1,149 @@ +//===-- ConstantHoisting.h - Prepare code for expensive constants ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass identifies expensive constants to hoist and coalesces them to +// better prepare it for SelectionDAG-based code generation. This works around +// the limitations of the basic-block-at-a-time approach. +// +// First it scans all instructions for integer constants and calculates its +// cost. If the constant can be folded into the instruction (the cost is +// TCC_Free) or the cost is just a simple operation (TCC_BASIC), then we don't +// consider it expensive and leave it alone. This is the default behavior and +// the default implementation of getIntImmCost will always return TCC_Free. +// +// If the cost is more than TCC_BASIC, then the integer constant can't be folded +// into the instruction and it might be beneficial to hoist the constant. +// Similar constants are coalesced to reduce register pressure and +// materialization code. +// +// When a constant is hoisted, it is also hidden behind a bitcast to force it to +// be live-out of the basic block. Otherwise the constant would be just +// duplicated and each basic block would have its own copy in the SelectionDAG. +// The SelectionDAG recognizes such constants as opaque and doesn't perform +// certain transformations on them, which would create a new expensive constant. +// +// This optimization is only applied to integer constants in instructions and +// simple (this means not nested) constant cast expressions. For example: +// %0 = load i64* inttoptr (i64 big_constant to i64*) +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H +#define LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H + +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A private "module" namespace for types and utilities used by +/// ConstantHoisting. These are implementation details and should not be used by +/// clients. +namespace consthoist { +/// \brief Keeps track of the user of a constant and the operand index where the +/// constant is used. +struct ConstantUser { + Instruction *Inst; + unsigned OpndIdx; + + ConstantUser(Instruction *Inst, unsigned Idx) : Inst(Inst), OpndIdx(Idx) { } +}; + +typedef SmallVector<ConstantUser, 8> ConstantUseListType; + +/// \brief Keeps track of a constant candidate and its uses. +struct ConstantCandidate { + ConstantUseListType Uses; + ConstantInt *ConstInt; + unsigned CumulativeCost; + + ConstantCandidate(ConstantInt *ConstInt) + : ConstInt(ConstInt), CumulativeCost(0) { } + + /// \brief Add the user to the use list and update the cost. + void addUser(Instruction *Inst, unsigned Idx, unsigned Cost) { + CumulativeCost += Cost; + Uses.push_back(ConstantUser(Inst, Idx)); + } +}; + +/// \brief This represents a constant that has been rebased with respect to a +/// base constant. The difference to the base constant is recorded in Offset. +struct RebasedConstantInfo { + ConstantUseListType Uses; + Constant *Offset; + + RebasedConstantInfo(ConstantUseListType &&Uses, Constant *Offset) + : Uses(std::move(Uses)), Offset(Offset) { } +}; + +typedef SmallVector<RebasedConstantInfo, 4> RebasedConstantListType; + +/// \brief A base constant and all its rebased constants. +struct ConstantInfo { + ConstantInt *BaseConstant; + RebasedConstantListType RebasedConstants; +}; +} + +class ConstantHoistingPass : public PassInfoMixin<ConstantHoistingPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + // Glue for old PM. + bool runImpl(Function &F, TargetTransformInfo &TTI, DominatorTree &DT, + BasicBlock &Entry); + + void releaseMemory() { + ConstantVec.clear(); + ClonedCastMap.clear(); + ConstCandVec.clear(); + } + +private: + typedef DenseMap<ConstantInt *, unsigned> ConstCandMapType; + typedef std::vector<consthoist::ConstantCandidate> ConstCandVecType; + + const TargetTransformInfo *TTI; + DominatorTree *DT; + BasicBlock *Entry; + + /// Keeps track of constant candidates found in the function. + ConstCandVecType ConstCandVec; + + /// Keep track of cast instructions we already cloned. + SmallDenseMap<Instruction *, Instruction *> ClonedCastMap; + + /// These are the final constants we decided to hoist. + SmallVector<consthoist::ConstantInfo, 8> ConstantVec; + + Instruction *findMatInsertPt(Instruction *Inst, unsigned Idx = ~0U) const; + Instruction *findConstantInsertionPoint( + const consthoist::ConstantInfo &ConstInfo) const; + void collectConstantCandidates(ConstCandMapType &ConstCandMap, + Instruction *Inst, unsigned Idx, + ConstantInt *ConstInt); + void collectConstantCandidates(ConstCandMapType &ConstCandMap, + Instruction *Inst); + void collectConstantCandidates(Function &Fn); + void findAndMakeBaseConstant(ConstCandVecType::iterator S, + ConstCandVecType::iterator E); + unsigned maximizeConstantsInRange(ConstCandVecType::iterator S, + ConstCandVecType::iterator E, + ConstCandVecType::iterator &MaxCostItr); + void findBaseConstants(); + void emitBaseConstants(Instruction *Base, Constant *Offset, + const consthoist::ConstantUser &ConstUser); + bool emitBaseConstants(); + void deleteDeadCastInst() const; + bool optimizeConstants(Function &Fn); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H diff --git a/include/llvm/Transforms/Scalar/CorrelatedValuePropagation.h b/include/llvm/Transforms/Scalar/CorrelatedValuePropagation.h new file mode 100644 index 000000000000..38816bbed068 --- /dev/null +++ b/include/llvm/Transforms/Scalar/CorrelatedValuePropagation.h @@ -0,0 +1,24 @@ +//===---- CorrelatedValuePropagation.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_CORRELATEDVALUEPROPAGATION_H +#define LLVM_TRANSFORMS_SCALAR_CORRELATEDVALUEPROPAGATION_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct CorrelatedValuePropagationPass + : PassInfoMixin<CorrelatedValuePropagationPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_CORRELATEDVALUEPROPAGATION_H diff --git a/include/llvm/Transforms/Scalar/DCE.h b/include/llvm/Transforms/Scalar/DCE.h new file mode 100644 index 000000000000..d9f921e1e7c1 --- /dev/null +++ b/include/llvm/Transforms/Scalar/DCE.h @@ -0,0 +1,29 @@ +//===- DCE.h - Dead code elimination ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Dead Code Elimination pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_DCE_H +#define LLVM_TRANSFORMS_SCALAR_DCE_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Basic Dead Code Elimination pass. +class DCEPass : public PassInfoMixin<DCEPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_DCE_H diff --git a/include/llvm/Transforms/Scalar/DeadStoreElimination.h b/include/llvm/Transforms/Scalar/DeadStoreElimination.h new file mode 100644 index 000000000000..7826e29f178e --- /dev/null +++ b/include/llvm/Transforms/Scalar/DeadStoreElimination.h @@ -0,0 +1,34 @@ +//===- DeadStoreElimination.h - Fast Dead Store Elimination -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a trivial dead store elimination that only considers +// basic-block local redundant stores. +// +// FIXME: This should eventually be extended to be a post-dominator tree +// traversal. Doing so would be pretty trivial. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_DSE_H +#define LLVM_TRANSFORMS_SCALAR_DSE_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// This class implements a trivial dead store elimination. We consider +/// only the redundant stores that are local to a single Basic Block. +class DSEPass : public PassInfoMixin<DSEPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &FAM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_DSE_H diff --git a/include/llvm/Transforms/Scalar/EarlyCSE.h b/include/llvm/Transforms/Scalar/EarlyCSE.h index e3dd3c050df6..80e3c602a2b8 100644 --- a/include/llvm/Transforms/Scalar/EarlyCSE.h +++ b/include/llvm/Transforms/Scalar/EarlyCSE.h @@ -26,12 +26,9 @@ namespace llvm { /// canonicalize things as it goes. It is intended to be fast and catch obvious /// cases so that instcombine and other passes are more effective. It is /// expected that a later pass of GVN will catch the interesting/hard cases. -class EarlyCSEPass { -public: - static StringRef name() { return "EarlyCSEPass"; } - +struct EarlyCSEPass : PassInfoMixin<EarlyCSEPass> { /// \brief Run the pass over the function. - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; } diff --git a/include/llvm/Transforms/Scalar/Float2Int.h b/include/llvm/Transforms/Scalar/Float2Int.h new file mode 100644 index 000000000000..a8042399fb08 --- /dev/null +++ b/include/llvm/Transforms/Scalar/Float2Int.h @@ -0,0 +1,51 @@ +//===-- Float2Int.h - Demote floating point ops to work on integers -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Float2Int pass, which aims to demote floating +// point operations to work on integers, where that is losslessly possible. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_FLOAT2INT_H +#define LLVM_TRANSFORMS_SCALAR_FLOAT2INT_H + +#include "llvm/ADT/EquivalenceClasses.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/IR/ConstantRange.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class Float2IntPass : public PassInfoMixin<Float2IntPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + // Glue for old PM. + bool runImpl(Function &F); + +private: + void findRoots(Function &F, SmallPtrSet<Instruction *, 8> &Roots); + ConstantRange seen(Instruction *I, ConstantRange R); + ConstantRange badRange(); + ConstantRange unknownRange(); + ConstantRange validateRange(ConstantRange R); + void walkBackwards(const SmallPtrSetImpl<Instruction *> &Roots); + void walkForwards(); + bool validateAndTransform(); + Value *convert(Instruction *I, Type *ToTy); + void cleanup(); + + MapVector<Instruction *, ConstantRange> SeenInsts; + SmallPtrSet<Instruction *, 8> Roots; + EquivalenceClasses<Instruction *> ECs; + MapVector<Instruction *, Value *> ConvertedInsts; + LLVMContext *Ctx; +}; +} +#endif // LLVM_TRANSFORMS_SCALAR_FLOAT2INT_H diff --git a/include/llvm/Transforms/Scalar/GVN.h b/include/llvm/Transforms/Scalar/GVN.h new file mode 100644 index 000000000000..3bb5ec392272 --- /dev/null +++ b/include/llvm/Transforms/Scalar/GVN.h @@ -0,0 +1,240 @@ +//===- GVN.h - Eliminate redundant values and loads -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides the interface for LLVM's Global Value Numbering pass +/// which eliminates fully redundant instructions. It also does somewhat Ad-Hoc +/// PRE and dead load elimination. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_GVN_H +#define LLVM_TRANSFORMS_SCALAR_GVN_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A private "module" namespace for types and utilities used by GVN. These +/// are implementation details and should not be used by clients. +namespace gvn LLVM_LIBRARY_VISIBILITY { +struct AvailableValue; +struct AvailableValueInBlock; +class GVNLegacyPass; +} + +/// The core GVN pass object. +/// +/// FIXME: We should have a good summary of the GVN algorithm implemented by +/// this particular pass here. +class GVN : public PassInfoMixin<GVN> { +public: + + /// \brief Run the pass over the function. + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); + + /// This removes the specified instruction from + /// our various maps and marks it for deletion. + void markInstructionForDeletion(Instruction *I) { + VN.erase(I); + InstrsToErase.push_back(I); + } + + DominatorTree &getDominatorTree() const { return *DT; } + AliasAnalysis *getAliasAnalysis() const { return VN.getAliasAnalysis(); } + MemoryDependenceResults &getMemDep() const { return *MD; } + + struct Expression; + + /// This class holds the mapping between values and value numbers. It is used + /// as an efficient mechanism to determine the expression-wise equivalence of + /// two values. + class ValueTable { + DenseMap<Value *, uint32_t> valueNumbering; + DenseMap<Expression, uint32_t> expressionNumbering; + AliasAnalysis *AA; + MemoryDependenceResults *MD; + DominatorTree *DT; + + uint32_t nextValueNumber; + + Expression createExpr(Instruction *I); + Expression createCmpExpr(unsigned Opcode, CmpInst::Predicate Predicate, + Value *LHS, Value *RHS); + Expression createExtractvalueExpr(ExtractValueInst *EI); + uint32_t lookupOrAddCall(CallInst *C); + + public: + ValueTable(); + ValueTable(const ValueTable &Arg); + ValueTable(ValueTable &&Arg); + ~ValueTable(); + + uint32_t lookupOrAdd(Value *V); + uint32_t lookup(Value *V) const; + uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred, + Value *LHS, Value *RHS); + bool exists(Value *V) const; + void add(Value *V, uint32_t num); + void clear(); + void erase(Value *v); + void setAliasAnalysis(AliasAnalysis *A) { AA = A; } + AliasAnalysis *getAliasAnalysis() const { return AA; } + void setMemDep(MemoryDependenceResults *M) { MD = M; } + void setDomTree(DominatorTree *D) { DT = D; } + uint32_t getNextUnusedValueNumber() { return nextValueNumber; } + void verifyRemoved(const Value *) const; + }; + +private: + friend class gvn::GVNLegacyPass; + friend struct DenseMapInfo<Expression>; + + MemoryDependenceResults *MD; + DominatorTree *DT; + const TargetLibraryInfo *TLI; + AssumptionCache *AC; + SetVector<BasicBlock *> DeadBlocks; + + ValueTable VN; + + /// A mapping from value numbers to lists of Value*'s that + /// have that value number. Use findLeader to query it. + struct LeaderTableEntry { + Value *Val; + const BasicBlock *BB; + LeaderTableEntry *Next; + }; + DenseMap<uint32_t, LeaderTableEntry> LeaderTable; + BumpPtrAllocator TableAllocator; + + // Block-local map of equivalent values to their leader, does not + // propagate to any successors. Entries added mid-block are applied + // to the remaining instructions in the block. + SmallMapVector<llvm::Value *, llvm::Constant *, 4> ReplaceWithConstMap; + SmallVector<Instruction *, 8> InstrsToErase; + + typedef SmallVector<NonLocalDepResult, 64> LoadDepVect; + typedef SmallVector<gvn::AvailableValueInBlock, 64> AvailValInBlkVect; + typedef SmallVector<BasicBlock *, 64> UnavailBlkVect; + + bool runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, + const TargetLibraryInfo &RunTLI, AAResults &RunAA, + MemoryDependenceResults *RunMD); + + /// Push a new Value to the LeaderTable onto the list for its value number. + void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) { + LeaderTableEntry &Curr = LeaderTable[N]; + if (!Curr.Val) { + Curr.Val = V; + Curr.BB = BB; + return; + } + + LeaderTableEntry *Node = TableAllocator.Allocate<LeaderTableEntry>(); + Node->Val = V; + Node->BB = BB; + Node->Next = Curr.Next; + Curr.Next = Node; + } + + /// Scan the list of values corresponding to a given + /// value number, and remove the given instruction if encountered. + void removeFromLeaderTable(uint32_t N, Instruction *I, BasicBlock *BB) { + LeaderTableEntry *Prev = nullptr; + LeaderTableEntry *Curr = &LeaderTable[N]; + + while (Curr && (Curr->Val != I || Curr->BB != BB)) { + Prev = Curr; + Curr = Curr->Next; + } + + if (!Curr) + return; + + if (Prev) { + Prev->Next = Curr->Next; + } else { + if (!Curr->Next) { + Curr->Val = nullptr; + Curr->BB = nullptr; + } else { + LeaderTableEntry *Next = Curr->Next; + Curr->Val = Next->Val; + Curr->BB = Next->BB; + Curr->Next = Next->Next; + } + } + } + + // List of critical edges to be split between iterations. + SmallVector<std::pair<TerminatorInst *, unsigned>, 4> toSplit; + + // Helper functions of redundant load elimination + bool processLoad(LoadInst *L); + bool processNonLocalLoad(LoadInst *L); + bool processAssumeIntrinsic(IntrinsicInst *II); + /// Given a local dependency (Def or Clobber) determine if a value is + /// available for the load. Returns true if an value is known to be + /// available and populates Res. Returns false otherwise. + bool AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + Value *Address, gvn::AvailableValue &Res); + /// Given a list of non-local dependencies, determine if a value is + /// available for the load in each specified block. If it is, add it to + /// ValuesPerBlock. If not, add it to UnavailableBlocks. + void AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps, + AvailValInBlkVect &ValuesPerBlock, + UnavailBlkVect &UnavailableBlocks); + bool PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, + UnavailBlkVect &UnavailableBlocks); + + // Other helper routines + bool processInstruction(Instruction *I); + bool processBlock(BasicBlock *BB); + void dump(DenseMap<uint32_t, Value *> &d); + bool iterateOnFunction(Function &F); + bool performPRE(Function &F); + bool performScalarPRE(Instruction *I); + bool performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred, + unsigned int ValNo); + Value *findLeader(const BasicBlock *BB, uint32_t num); + void cleanupGlobalSets(); + void verifyRemoved(const Instruction *I) const; + bool splitCriticalEdges(); + BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ); + bool replaceOperandsWithConsts(Instruction *I) const; + bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root, + bool DominatesByEdge); + bool processFoldableCondBr(BranchInst *BI); + void addDeadBlock(BasicBlock *BB); + void assignValNumForDeadCode(); +}; + +/// Create a legacy GVN pass. This also allows parameterizing whether or not +/// loads are eliminated by the pass. +FunctionPass *createGVNPass(bool NoLoads = false); + +/// \brief A simple and fast domtree-based GVN pass to hoist common expressions +/// from sibling branches. +struct GVNHoistPass : PassInfoMixin<GVNHoistPass> { + /// \brief Run the pass over the function. + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +} + +#endif diff --git a/include/llvm/Transforms/Scalar/GuardWidening.h b/include/llvm/Transforms/Scalar/GuardWidening.h new file mode 100644 index 000000000000..201065cbdfb5 --- /dev/null +++ b/include/llvm/Transforms/Scalar/GuardWidening.h @@ -0,0 +1,32 @@ +//===- GuardWidening.h - ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Guard widening is an optimization over the @llvm.experimental.guard intrinsic +// that (optimistically) combines multiple guards into one to have fewer checks +// at runtime. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_TRANSFORMS_SCALAR_GUARD_WIDENING_H +#define LLVM_TRANSFORMS_SCALAR_GUARD_WIDENING_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class Function; + +struct GuardWideningPass : public PassInfoMixin<GuardWideningPass> { + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + + +#endif // LLVM_TRANSFORMS_SCALAR_GUARD_WIDENING_H diff --git a/include/llvm/Transforms/Scalar/IndVarSimplify.h b/include/llvm/Transforms/Scalar/IndVarSimplify.h new file mode 100644 index 000000000000..325bcc7bed8f --- /dev/null +++ b/include/llvm/Transforms/Scalar/IndVarSimplify.h @@ -0,0 +1,29 @@ +//===- IndVarSimplify.h - Induction Variable Simplification -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Induction Variable +// Simplification pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_INDVARSIMPLIFY_H +#define LLVM_TRANSFORMS_SCALAR_INDVARSIMPLIFY_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class IndVarSimplifyPass : public PassInfoMixin<IndVarSimplifyPass> { +public: + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_INDVARSIMPLIFY_H diff --git a/include/llvm/Transforms/Scalar/JumpThreading.h b/include/llvm/Transforms/Scalar/JumpThreading.h new file mode 100644 index 000000000000..e38bdd03ac06 --- /dev/null +++ b/include/llvm/Transforms/Scalar/JumpThreading.h @@ -0,0 +1,141 @@ +//===- JumpThreading.h - thread control through conditional BBs -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// See the comments on JumpThreadingPass. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_JUMPTHREADING_H +#define LLVM_TRANSFORMS_SCALAR_JUMPTHREADING_H + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BlockFrequencyInfoImpl.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/LazyValueInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/ValueHandle.h" + +namespace llvm { + +/// A private "module" namespace for types and utilities used by +/// JumpThreading. +/// These are implementation details and should not be used by clients. +namespace jumpthreading { +// These are at global scope so static functions can use them too. +typedef SmallVectorImpl<std::pair<Constant *, BasicBlock *>> PredValueInfo; +typedef SmallVector<std::pair<Constant *, BasicBlock *>, 8> PredValueInfoTy; + +// This is used to keep track of what kind of constant we're currently hoping +// to find. +enum ConstantPreference { WantInteger, WantBlockAddress }; +} + +/// This pass performs 'jump threading', which looks at blocks that have +/// multiple predecessors and multiple successors. If one or more of the +/// predecessors of the block can be proven to always jump to one of the +/// successors, we forward the edge from the predecessor to the successor by +/// duplicating the contents of this block. +/// +/// An example of when this can occur is code like this: +/// +/// if () { ... +/// X = 4; +/// } +/// if (X < 3) { +/// +/// In this case, the unconditional branch at the end of the first if can be +/// revectored to the false side of the second if. +/// +class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> { + TargetLibraryInfo *TLI; + LazyValueInfo *LVI; + std::unique_ptr<BlockFrequencyInfo> BFI; + std::unique_ptr<BranchProbabilityInfo> BPI; + bool HasProfileData = false; +#ifdef NDEBUG + SmallPtrSet<const BasicBlock *, 16> LoopHeaders; +#else + SmallSet<AssertingVH<const BasicBlock>, 16> LoopHeaders; +#endif + DenseSet<std::pair<Value *, BasicBlock *>> RecursionSet; + + unsigned BBDupThreshold; + + // RAII helper for updating the recursion stack. + struct RecursionSetRemover { + DenseSet<std::pair<Value *, BasicBlock *>> &TheSet; + std::pair<Value *, BasicBlock *> ThePair; + + RecursionSetRemover(DenseSet<std::pair<Value *, BasicBlock *>> &S, + std::pair<Value *, BasicBlock *> P) + : TheSet(S), ThePair(P) {} + + ~RecursionSetRemover() { TheSet.erase(ThePair); } + }; + +public: + JumpThreadingPass(int T = -1); + // Hack for MSVC 2013 which seems like it can't synthesize this. + JumpThreadingPass(JumpThreadingPass &&Other) + : TLI(Other.TLI), LVI(Other.LVI), BFI(std::move(Other.BFI)), + BPI(std::move(Other.BPI)), HasProfileData(Other.HasProfileData), + LoopHeaders(std::move(Other.LoopHeaders)), + RecursionSet(std::move(Other.RecursionSet)), + BBDupThreshold(Other.BBDupThreshold) {} + + // Glue for old PM. + bool runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_, + bool HasProfileData_, std::unique_ptr<BlockFrequencyInfo> BFI_, + std::unique_ptr<BranchProbabilityInfo> BPI_); + + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); + + void releaseMemory() { + BFI.reset(); + BPI.reset(); + } + + void FindLoopHeaders(Function &F); + bool ProcessBlock(BasicBlock *BB); + bool ThreadEdge(BasicBlock *BB, const SmallVectorImpl<BasicBlock *> &PredBBs, + BasicBlock *SuccBB); + bool DuplicateCondBranchOnPHIIntoPred( + BasicBlock *BB, const SmallVectorImpl<BasicBlock *> &PredBBs); + + bool + ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB, + jumpthreading::PredValueInfo &Result, + jumpthreading::ConstantPreference Preference, + Instruction *CxtI = nullptr); + bool ProcessThreadableEdges(Value *Cond, BasicBlock *BB, + jumpthreading::ConstantPreference Preference, + Instruction *CxtI = nullptr); + + bool ProcessBranchOnPHI(PHINode *PN); + bool ProcessBranchOnXOR(BinaryOperator *BO); + bool ProcessImpliedCondition(BasicBlock *BB); + + bool SimplifyPartiallyRedundantLoad(LoadInst *LI); + bool TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB); + bool TryToUnfoldSelectInCurrBB(BasicBlock *BB); + +private: + BasicBlock *SplitBlockPreds(BasicBlock *BB, ArrayRef<BasicBlock *> Preds, + const char *Suffix); + void UpdateBlockFreqAndEdgeWeight(BasicBlock *PredBB, BasicBlock *BB, + BasicBlock *NewBB, BasicBlock *SuccBB); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Transforms/Scalar/LICM.h b/include/llvm/Transforms/Scalar/LICM.h new file mode 100644 index 000000000000..a050a43d6179 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LICM.h @@ -0,0 +1,48 @@ +//===- LICM.h - Loop Invariant Code Motion Pass -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass performs loop invariant code motion, attempting to remove as much +// code from the body of a loop as possible. It does this by either hoisting +// code into the preheader block, or by sinking code to the exit blocks if it is +// safe. This pass also promotes must-aliased memory locations in the loop to +// live in registers, thus hoisting and sinking "invariant" loads and stores. +// +// This pass uses alias analysis for two purposes: +// +// 1. Moving loop invariant loads and calls out of loops. If we can determine +// that a load or call inside of a loop never aliases anything stored to, +// we can hoist it or sink it like any other instruction. +// 2. Scalar Promotion of Memory - If there is a store instruction inside of +// the loop, we try to move the store to happen AFTER the loop instead of +// inside of the loop. This can only happen if a few conditions are true: +// A. The pointer stored through is loop invariant +// B. There are no stores or loads in the loop which _may_ alias the +// pointer. There are no calls in the loop which mod/ref the pointer. +// If these conditions are true, we can promote the loads and stores in the +// loop of the pointer to use a temporary alloca'd variable. We then use +// the SSAUpdater to construct the appropriate SSA form for the value. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LICM_H +#define LLVM_TRANSFORMS_SCALAR_LICM_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Performs Loop Invariant Code Motion Pass. +class LICMPass : public PassInfoMixin<LICMPass> { +public: + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LICM_H diff --git a/include/llvm/Transforms/Scalar/LoopDeletion.h b/include/llvm/Transforms/Scalar/LoopDeletion.h new file mode 100644 index 000000000000..ed5a9833e572 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopDeletion.h @@ -0,0 +1,38 @@ +//===- LoopDeletion.h - Loop Deletion -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Loop Deletion Pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H +#define LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class LoopDeletionPass : public PassInfoMixin<LoopDeletionPass> { +public: + LoopDeletionPass() {} + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); + bool runImpl(Loop *L, DominatorTree &DT, ScalarEvolution &SE, + LoopInfo &loopInfo); + +private: + bool isLoopDead(Loop *L, ScalarEvolution &SE, + SmallVectorImpl<BasicBlock *> &exitingBlocks, + SmallVectorImpl<BasicBlock *> &exitBlocks, bool &Changed, + BasicBlock *Preheader); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H diff --git a/include/llvm/Transforms/Scalar/LoopDistribute.h b/include/llvm/Transforms/Scalar/LoopDistribute.h new file mode 100644 index 000000000000..ddde5954c218 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopDistribute.h @@ -0,0 +1,30 @@ +//===- LoopDistribute.cpp - Loop Distribution Pass --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Loop Distribution Pass. Its main focus is to +// distribute loops that cannot be vectorized due to dependence cycles. It +// tries to isolate the offending dependences into a new loop allowing +// vectorization of the remaining parts. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPDISTRIBUTE_H +#define LLVM_TRANSFORMS_SCALAR_LOOPDISTRIBUTE_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class LoopDistributePass : public PassInfoMixin<LoopDistributePass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPDISTRIBUTE_H diff --git a/include/llvm/Transforms/Scalar/LoopIdiomRecognize.h b/include/llvm/Transforms/Scalar/LoopIdiomRecognize.h new file mode 100644 index 000000000000..cc66156fba8a --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopIdiomRecognize.h @@ -0,0 +1,31 @@ +//===- LoopIdiomRecognize.h - Loop Idiom Recognize Pass -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass implements an idiom recognizer that transforms simple loops into a +// non-loop form. In cases that this kicks in, it can be a significant +// performance win. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPIDIOMRECOGNIZE_H +#define LLVM_TRANSFORMS_SCALAR_LOOPIDIOMRECOGNIZE_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Performs Loop Idiom Recognize Pass. +class LoopIdiomRecognizePass : public PassInfoMixin<LoopIdiomRecognizePass> { +public: + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPIDIOMRECOGNIZE_H diff --git a/include/llvm/Transforms/Scalar/LoopInstSimplify.h b/include/llvm/Transforms/Scalar/LoopInstSimplify.h new file mode 100644 index 000000000000..f67343f40a7c --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopInstSimplify.h @@ -0,0 +1,29 @@ +//===- LoopInstSimplify.h - Loop Inst Simplify Pass -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass performs lightweight instruction simplification on loop bodies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPINSTSIMPLIFY_H +#define LLVM_TRANSFORMS_SCALAR_LOOPINSTSIMPLIFY_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Performs Loop Inst Simplify Pass. +class LoopInstSimplifyPass : public PassInfoMixin<LoopInstSimplifyPass> { +public: + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPINSTSIMPLIFY_H diff --git a/include/llvm/Transforms/Scalar/LoopRotation.h b/include/llvm/Transforms/Scalar/LoopRotation.h new file mode 100644 index 000000000000..b21c7313dc4b --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopRotation.h @@ -0,0 +1,30 @@ +//===- LoopRotation.h - Loop Rotation -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Loop Rotation pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPROTATION_H +#define LLVM_TRANSFORMS_SCALAR_LOOPROTATION_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A simple loop rotation transformation. +class LoopRotatePass : public PassInfoMixin<LoopRotatePass> { +public: + LoopRotatePass(); + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPROTATION_H diff --git a/include/llvm/Transforms/Scalar/LoopSimplifyCFG.h b/include/llvm/Transforms/Scalar/LoopSimplifyCFG.h new file mode 100644 index 000000000000..7609bb26a1a0 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopSimplifyCFG.h @@ -0,0 +1,32 @@ +//===- LoopSimplifyCFG.cpp - Loop CFG Simplification Pass -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Loop SimplifyCFG Pass. This pass is responsible for +// basic loop CFG cleanup, primarily to assist other loop passes. If you +// encounter a noncanonical CFG construct that causes another loop pass to +// perform suboptimally, this is the place to fix it up. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPSIMPLIFYCFG_H +#define LLVM_TRANSFORMS_SCALAR_LOOPSIMPLIFYCFG_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Performs basic CFG simplifications to assist other loop passes. +class LoopSimplifyCFGPass : public PassInfoMixin<LoopSimplifyCFGPass> { +public: + PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPSIMPLIFYCFG_H diff --git a/include/llvm/Transforms/Scalar/LowerAtomic.h b/include/llvm/Transforms/Scalar/LowerAtomic.h new file mode 100644 index 000000000000..a4a2e7aafe44 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LowerAtomic.h @@ -0,0 +1,29 @@ +//===- LowerAtomic.cpp - Lower atomic intrinsics ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +// This pass lowers atomic intrinsics to non-atomic form for use in a known +// non-preemptible environment. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOWERATOMIC_H +#define LLVM_TRANSFORMS_SCALAR_LOWERATOMIC_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A pass that lowers atomic intrinsic into non-atomic intrinsics. +class LowerAtomicPass : public PassInfoMixin<LowerAtomicPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOWERATOMIC_H diff --git a/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h b/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h index 40283203f3a3..f688e7f19986 100644 --- a/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h +++ b/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h @@ -21,10 +21,7 @@ namespace llvm { -class LowerExpectIntrinsicPass { -public: - static StringRef name() { return "LowerExpectIntrinsicPass"; } - +struct LowerExpectIntrinsicPass : PassInfoMixin<LowerExpectIntrinsicPass> { /// \brief Run the pass over the function. /// /// This will lower all of th expect intrinsic calls in this function into @@ -32,7 +29,7 @@ public: /// of the probabilities and frequencies of the CFG. After running this pass, /// no more expect intrinsics remain, allowing the rest of the optimizer to /// ignore them. - PreservedAnalyses run(Function &F); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); }; } diff --git a/include/llvm/Transforms/Scalar/MemCpyOptimizer.h b/include/llvm/Transforms/Scalar/MemCpyOptimizer.h new file mode 100644 index 000000000000..4308e44e7c4b --- /dev/null +++ b/include/llvm/Transforms/Scalar/MemCpyOptimizer.h @@ -0,0 +1,68 @@ +//===---- MemCpyOptimizer.h - memcpy optimization ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass performs various transformations related to eliminating memcpy +// calls, or transforming sets of stores into memset's. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_MEMCPYOPTIMIZER_H +#define LLVM_TRANSFORMS_SCALAR_MEMCPYOPTIMIZER_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class MemCpyOptPass : public PassInfoMixin<MemCpyOptPass> { + MemoryDependenceResults *MD = nullptr; + TargetLibraryInfo *TLI = nullptr; + std::function<AliasAnalysis &()> LookupAliasAnalysis; + std::function<AssumptionCache &()> LookupAssumptionCache; + std::function<DominatorTree &()> LookupDomTree; + +public: + MemCpyOptPass() {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + // Glue for the old PM. + bool runImpl(Function &F, MemoryDependenceResults *MD_, + TargetLibraryInfo *TLI_, + std::function<AliasAnalysis &()> LookupAliasAnalysis_, + std::function<AssumptionCache &()> LookupAssumptionCache_, + std::function<DominatorTree &()> LookupDomTree_); + +private: + // Helper functions + bool processStore(StoreInst *SI, BasicBlock::iterator &BBI); + bool processMemSet(MemSetInst *SI, BasicBlock::iterator &BBI); + bool processMemCpy(MemCpyInst *M); + bool processMemMove(MemMoveInst *M); + bool performCallSlotOptzn(Instruction *cpy, Value *cpyDst, Value *cpySrc, + uint64_t cpyLen, unsigned cpyAlign, CallInst *C); + bool processMemCpyMemCpyDependence(MemCpyInst *M, MemCpyInst *MDep); + bool processMemSetMemCpyDependence(MemCpyInst *M, MemSetInst *MDep); + bool performMemCpyToMemSetOptzn(MemCpyInst *M, MemSetInst *MDep); + bool processByValArgument(CallSite CS, unsigned ArgNo); + Instruction *tryMergingIntoMemset(Instruction *I, Value *StartPtr, + Value *ByteVal); + + bool iterateOnFunction(Function &F); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_MEMCPYOPTIMIZER_H diff --git a/include/llvm/Transforms/Scalar/MergedLoadStoreMotion.h b/include/llvm/Transforms/Scalar/MergedLoadStoreMotion.h new file mode 100644 index 000000000000..47cfea489243 --- /dev/null +++ b/include/llvm/Transforms/Scalar/MergedLoadStoreMotion.h @@ -0,0 +1,39 @@ +//===- MergedLoadStoreMotion.h - merge and hoist/sink load/stores ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//! \file +//! \brief This pass performs merges of loads and stores on both sides of a +// diamond (hammock). It hoists the loads and sinks the stores. +// +// The algorithm iteratively hoists two loads to the same address out of a +// diamond (hammock) and merges them into a single load in the header. Similar +// it sinks and merges two stores to the tail block (footer). The algorithm +// iterates over the instructions of one side of the diamond and attempts to +// find a matching load/store on the other side. It hoists / sinks when it +// thinks it safe to do so. This optimization helps with eg. hiding load +// latencies, triggering if-conversion, and reducing static code size. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_MERGEDLOADSTOREMOTION_H +#define LLVM_TRANSFORMS_SCALAR_MERGEDLOADSTOREMOTION_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class MergedLoadStoreMotionPass + : public PassInfoMixin<MergedLoadStoreMotionPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +} + +#endif // LLVM_TRANSFORMS_SCALAR_MERGEDLOADSTOREMOTION_H diff --git a/include/llvm/Transforms/Scalar/PartiallyInlineLibCalls.h b/include/llvm/Transforms/Scalar/PartiallyInlineLibCalls.h new file mode 100644 index 000000000000..385bbb40db3f --- /dev/null +++ b/include/llvm/Transforms/Scalar/PartiallyInlineLibCalls.h @@ -0,0 +1,30 @@ +//===--- PartiallyInlineLibCalls.h - Partially inline libcalls --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass tries to partially inline the fast path of well-known library +// functions, such as using square-root instructions for cases where sqrt() +// does not need to set errno. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_PARTIALLYINLINELIBCALLS_H +#define LLVM_TRANSFORMS_SCALAR_PARTIALLYINLINELIBCALLS_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class PartiallyInlineLibCallsPass + : public PassInfoMixin<PartiallyInlineLibCallsPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_PARTIALLYINLINELIBCALLS_H diff --git a/include/llvm/Transforms/Scalar/Reassociate.h b/include/llvm/Transforms/Scalar/Reassociate.h new file mode 100644 index 000000000000..7b68b4489306 --- /dev/null +++ b/include/llvm/Transforms/Scalar/Reassociate.h @@ -0,0 +1,100 @@ +//===- Reassociate.h - Reassociate binary expressions -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass reassociates commutative expressions in an order that is designed +// to promote better constant propagation, GCSE, LICM, PRE, etc. +// +// For example: 4 + (x + 5) -> x + (4 + 5) +// +// In the implementation of this algorithm, constants are assigned rank = 0, +// function arguments are rank = 1, and other values are assigned ranks +// corresponding to the reverse post order traversal of current function +// (starting at 2), which effectively gives values in deep loops higher rank +// than values not in loops. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_REASSOCIATE_H +#define LLVM_TRANSFORMS_SCALAR_REASSOCIATE_H + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A private "module" namespace for types and utilities used by Reassociate. +/// These are implementation details and should not be used by clients. +namespace reassociate { +struct ValueEntry { + unsigned Rank; + Value *Op; + ValueEntry(unsigned R, Value *O) : Rank(R), Op(O) {} +}; +inline bool operator<(const ValueEntry &LHS, const ValueEntry &RHS) { + return LHS.Rank > RHS.Rank; // Sort so that highest rank goes to start. +} + +/// \brief Utility class representing a base and exponent pair which form one +/// factor of some product. +struct Factor { + Value *Base; + unsigned Power; + Factor(Value *Base, unsigned Power) : Base(Base), Power(Power) {} +}; + +class XorOpnd; +} + +/// Reassociate commutative expressions. +class ReassociatePass : public PassInfoMixin<ReassociatePass> { + DenseMap<BasicBlock *, unsigned> RankMap; + DenseMap<AssertingVH<Value>, unsigned> ValueRankMap; + SetVector<AssertingVH<Instruction>> RedoInsts; + bool MadeChange; + +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); + +private: + void BuildRankMap(Function &F, ReversePostOrderTraversal<Function *> &RPOT); + unsigned getRank(Value *V); + void canonicalizeOperands(Instruction *I); + void ReassociateExpression(BinaryOperator *I); + void RewriteExprTree(BinaryOperator *I, + SmallVectorImpl<reassociate::ValueEntry> &Ops); + Value *OptimizeExpression(BinaryOperator *I, + SmallVectorImpl<reassociate::ValueEntry> &Ops); + Value *OptimizeAdd(Instruction *I, + SmallVectorImpl<reassociate::ValueEntry> &Ops); + Value *OptimizeXor(Instruction *I, + SmallVectorImpl<reassociate::ValueEntry> &Ops); + bool CombineXorOpnd(Instruction *I, reassociate::XorOpnd *Opnd1, + APInt &ConstOpnd, Value *&Res); + bool CombineXorOpnd(Instruction *I, reassociate::XorOpnd *Opnd1, + reassociate::XorOpnd *Opnd2, APInt &ConstOpnd, + Value *&Res); + bool collectMultiplyFactors(SmallVectorImpl<reassociate::ValueEntry> &Ops, + SmallVectorImpl<reassociate::Factor> &Factors); + Value *buildMinimalMultiplyDAG(IRBuilder<> &Builder, + SmallVectorImpl<reassociate::Factor> &Factors); + Value *OptimizeMul(BinaryOperator *I, + SmallVectorImpl<reassociate::ValueEntry> &Ops); + Value *RemoveFactorFromExpression(Value *V, Value *Factor); + void EraseInst(Instruction *I); + void RecursivelyEraseDeadInsts(Instruction *I, + SetVector<AssertingVH<Instruction>> &Insts); + void OptimizeInst(Instruction *I); + Instruction *canonicalizeNegConstExpr(Instruction *I); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_REASSOCIATE_H diff --git a/include/llvm/Transforms/Scalar/SCCP.h b/include/llvm/Transforms/Scalar/SCCP.h new file mode 100644 index 000000000000..0dd90ecbedec --- /dev/null +++ b/include/llvm/Transforms/Scalar/SCCP.h @@ -0,0 +1,36 @@ +//===- SCCP.cpp - Sparse Conditional Constant Propagation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +// This file implements sparse conditional constant propagation and merging: +// +// Specifically, this: +// * Assumes values are constant unless proven otherwise +// * Assumes BasicBlocks are dead unless proven otherwise +// * Proves values to be constant, and replaces them with constants +// * Proves conditional branches to be unconditional +// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_SCCP_H +#define LLVM_TRANSFORMS_SCALAR_SCCP_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// This pass performs function-level constant propagation and merging. +class SCCPPass : public PassInfoMixin<SCCPPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H diff --git a/include/llvm/Transforms/Scalar/SROA.h b/include/llvm/Transforms/Scalar/SROA.h index f90cc7b686ba..72e7d63d4df6 100644 --- a/include/llvm/Transforms/Scalar/SROA.h +++ b/include/llvm/Transforms/Scalar/SROA.h @@ -26,7 +26,7 @@ namespace llvm { /// A private "module" namespace for types and utilities used by SROA. These /// are implementation details and should not be used by clients. -namespace sroa { +namespace sroa LLVM_LIBRARY_VISIBILITY { class AllocaSliceRewriter; class AllocaSlices; class Partition; @@ -51,7 +51,7 @@ class SROALegacyPass; /// onto insert and extract operations on a vector value, and convert them to /// this form. By doing so, it will enable promotion of vector aggregates to /// SSA vector values. -class SROA { +class SROA : public PassInfoMixin<SROA> { LLVMContext *C; DominatorTree *DT; AssumptionCache *AC; @@ -101,10 +101,8 @@ class SROA { public: SROA() : C(nullptr), DT(nullptr), AC(nullptr) {} - static StringRef name() { return "SROA"; } - /// \brief Run the pass over the function. - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); private: friend class sroa::AllocaSliceRewriter; diff --git a/include/llvm/Transforms/Scalar/SimplifyCFG.h b/include/llvm/Transforms/Scalar/SimplifyCFG.h index ef28e0f78a4c..53f427a7d19a 100644 --- a/include/llvm/Transforms/Scalar/SimplifyCFG.h +++ b/include/llvm/Transforms/Scalar/SimplifyCFG.h @@ -25,12 +25,10 @@ namespace llvm { /// This pass iteratively simplifies the entire CFG of a function, removing /// unnecessary control flows and bringing it into the canonical form expected /// by the rest of the mid-level optimizer. -class SimplifyCFGPass { +class SimplifyCFGPass : public PassInfoMixin<SimplifyCFGPass> { int BonusInstThreshold; public: - static StringRef name() { return "SimplifyCFGPass"; } - /// \brief Construct a pass with the default thresholds. SimplifyCFGPass(); @@ -38,7 +36,7 @@ public: SimplifyCFGPass(int BonusInstThreshold); /// \brief Run the pass over the function. - PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; } diff --git a/include/llvm/Transforms/Scalar/Sink.h b/include/llvm/Transforms/Scalar/Sink.h new file mode 100644 index 000000000000..1144c62fb20c --- /dev/null +++ b/include/llvm/Transforms/Scalar/Sink.h @@ -0,0 +1,30 @@ +//===-- Sink.h - Code Sinking -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass moves instructions into successor blocks, when possible, so that +// they aren't executed on paths where their results aren't needed. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_SINK_H +#define LLVM_TRANSFORMS_SCALAR_SINK_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Move instructions into successor blocks when possible. +class SinkingPass : public PassInfoMixin<SinkingPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_SINK_H diff --git a/include/llvm/Transforms/Scalar/TailRecursionElimination.h b/include/llvm/Transforms/Scalar/TailRecursionElimination.h new file mode 100644 index 000000000000..793f9bc152ed --- /dev/null +++ b/include/llvm/Transforms/Scalar/TailRecursionElimination.h @@ -0,0 +1,66 @@ +//===---- TailRecursionElimination.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file transforms calls of the current function (self recursion) followed +// by a return instruction with a branch to the entry of the function, creating +// a loop. This pass also implements the following extensions to the basic +// algorithm: +// +// 1. Trivial instructions between the call and return do not prevent the +// transformation from taking place, though currently the analysis cannot +// support moving any really useful instructions (only dead ones). +// 2. This pass transforms functions that are prevented from being tail +// recursive by an associative and commutative expression to use an +// accumulator variable, thus compiling the typical naive factorial or +// 'fib' implementation into efficient code. +// 3. TRE is performed if the function returns void, if the return +// returns the result returned by the call, or if the function returns a +// run-time constant on all exits from the function. It is possible, though +// unlikely, that the return returns something else (like constant 0), and +// can still be TRE'd. It can be TRE'd if ALL OTHER return instructions in +// the function return the exact same value. +// 4. If it can prove that callees do not access their caller stack frame, +// they are marked as eligible for tail call elimination (by the code +// generator). +// +// There are several improvements that could be made: +// +// 1. If the function has any alloca instructions, these instructions will be +// moved out of the entry block of the function, causing them to be +// evaluated each time through the tail recursion. Safely keeping allocas +// in the entry block requires analysis to proves that the tail-called +// function does not read or write the stack object. +// 2. Tail recursion is only performed if the call immediately precedes the +// return instruction. It's possible that there could be a jump between +// the call and the return. +// 3. There can be intervening operations between the call and the return that +// prevent the TRE from occurring. For example, there could be GEP's and +// stores to memory that will not be read or written by the call. This +// requires some substantial analysis (such as with DSA) to prove safe to +// move ahead of the call, but doing so could allow many more TREs to be +// performed, for example in TreeAdd/TreeAlloc from the treeadd benchmark. +// 4. The algorithm we use to detect if callees access their caller stack +// frames is very primitive. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H +#define LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct TailCallElimPass : PassInfoMixin<TailCallElimPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_TAILRECURSIONELIMINATION_H diff --git a/include/llvm/Transforms/Utils/AddDiscriminators.h b/include/llvm/Transforms/Utils/AddDiscriminators.h new file mode 100644 index 000000000000..0b3a8add6278 --- /dev/null +++ b/include/llvm/Transforms/Utils/AddDiscriminators.h @@ -0,0 +1,29 @@ +//===- AddDiscriminators.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass adds DWARF discriminators to the IR. Path discriminators are used +// to decide what CFG path was taken inside sub-graphs whose instructions share +// the same line and column number information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_ADDDISCRIMINATORS_H +#define LLVM_TRANSFORMS_UTILS_ADDDISCRIMINATORS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class AddDiscriminatorsPass : public PassInfoMixin<AddDiscriminatorsPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_ADDDISCRIMINATORS_H diff --git a/include/llvm/Transforms/Utils/BasicBlockUtils.h b/include/llvm/Transforms/Utils/BasicBlockUtils.h index 13c856dfdc9a..37fd20925cba 100644 --- a/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -22,7 +22,7 @@ namespace llvm { -class MemoryDependenceAnalysis; +class MemoryDependenceResults; class DominatorTree; class LoopInfo; class Instruction; @@ -31,51 +31,45 @@ class ReturnInst; class TargetLibraryInfo; class TerminatorInst; -/// DeleteDeadBlock - Delete the specified block, which must have no -/// predecessors. +/// Delete the specified block, which must have no predecessors. void DeleteDeadBlock(BasicBlock *BB); -/// FoldSingleEntryPHINodes - We know that BB has one predecessor. If there are -/// any single-entry PHI nodes in it, fold them away. This handles the case -/// when all entries to the PHI nodes in a block are guaranteed equal, such as -/// when the block has exactly one predecessor. +/// We know that BB has one predecessor. If there are any single-entry PHI nodes +/// in it, fold them away. This handles the case when all entries to the PHI +/// nodes in a block are guaranteed equal, such as when the block has exactly +/// one predecessor. void FoldSingleEntryPHINodes(BasicBlock *BB, - MemoryDependenceAnalysis *MemDep = nullptr); + MemoryDependenceResults *MemDep = nullptr); -/// DeleteDeadPHIs - Examine each PHI in the given block and delete it if it -/// is dead. Also recursively delete any operands that become dead as -/// a result. This includes tracing the def-use list from the PHI to see if -/// it is ultimately unused or if it reaches an unused cycle. Return true -/// if any PHIs were deleted. +/// Examine each PHI in the given block and delete it if it is dead. Also +/// recursively delete any operands that become dead as a result. This includes +/// tracing the def-use list from the PHI to see if it is ultimately unused or +/// if it reaches an unused cycle. Return true if any PHIs were deleted. bool DeleteDeadPHIs(BasicBlock *BB, const TargetLibraryInfo *TLI = nullptr); -/// MergeBlockIntoPredecessor - Attempts to merge a block into its predecessor, -/// if possible. The return value indicates success or failure. +/// Attempts to merge a block into its predecessor, if possible. The return +/// value indicates success or failure. bool MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT = nullptr, LoopInfo *LI = nullptr, - MemoryDependenceAnalysis *MemDep = nullptr); + MemoryDependenceResults *MemDep = nullptr); -// ReplaceInstWithValue - Replace all uses of an instruction (specified by BI) -// with a value, then remove and delete the original instruction. -// +/// Replace all uses of an instruction (specified by BI) with a value, then +/// remove and delete the original instruction. void ReplaceInstWithValue(BasicBlock::InstListType &BIL, BasicBlock::iterator &BI, Value *V); -// ReplaceInstWithInst - Replace the instruction specified by BI with the -// instruction specified by I. Copies DebugLoc from BI to I, if I doesn't -// already have a DebugLoc. The original instruction is deleted and BI is -// updated to point to the new instruction. -// +/// Replace the instruction specified by BI with the instruction specified by I. +/// Copies DebugLoc from BI to I, if I doesn't already have a DebugLoc. The +/// original instruction is deleted and BI is updated to point to the new +/// instruction. void ReplaceInstWithInst(BasicBlock::InstListType &BIL, BasicBlock::iterator &BI, Instruction *I); -// ReplaceInstWithInst - Replace the instruction specified by From with the -// instruction specified by To. Copies DebugLoc from BI to I, if I doesn't -// already have a DebugLoc. -// +/// Replace the instruction specified by From with the instruction specified by +/// To. Copies DebugLoc from BI to I, if I doesn't already have a DebugLoc. void ReplaceInstWithInst(Instruction *From, Instruction *To); -/// \brief Option class for critical edge splitting. +/// Option class for critical edge splitting. /// /// This provides a builder interface for overriding the default options used /// during critical edge splitting. @@ -107,10 +101,9 @@ struct CriticalEdgeSplittingOptions { } }; -/// SplitCriticalEdge - If this edge is a critical edge, insert a new node to -/// split the critical edge. This will update the analyses passed in through -/// the option struct. This returns the new block if the edge was split, null -/// otherwise. +/// If this edge is a critical edge, insert a new node to split the critical +/// edge. This will update the analyses passed in through the option struct. +/// This returns the new block if the edge was split, null otherwise. /// /// If MergeIdenticalEdges in the options struct is true (not the default), /// *all* edges from TI to the specified successor will be merged into the same @@ -137,11 +130,10 @@ SplitCriticalEdge(BasicBlock *BB, succ_iterator SI, Options); } -/// SplitCriticalEdge - If the edge from *PI to BB is not critical, return -/// false. Otherwise, split all edges between the two blocks and return true. -/// This updates all of the same analyses as the other SplitCriticalEdge -/// function. If P is specified, it updates the analyses -/// described above. +/// If the edge from *PI to BB is not critical, return false. Otherwise, split +/// all edges between the two blocks and return true. This updates all of the +/// same analyses as the other SplitCriticalEdge function. If P is specified, it +/// updates the analyses described above. inline bool SplitCriticalEdge(BasicBlock *Succ, pred_iterator PI, const CriticalEdgeSplittingOptions &Options = CriticalEdgeSplittingOptions()) { @@ -153,10 +145,9 @@ inline bool SplitCriticalEdge(BasicBlock *Succ, pred_iterator PI, return MadeChange; } -/// SplitCriticalEdge - If an edge from Src to Dst is critical, split the edge -/// and return true, otherwise return false. This method requires that there be -/// an edge between the two blocks. It updates the analyses -/// passed in the options struct +/// If an edge from Src to Dst is critical, split the edge and return true, +/// otherwise return false. This method requires that there be an edge between +/// the two blocks. It updates the analyses passed in the options struct inline BasicBlock * SplitCriticalEdge(BasicBlock *Src, BasicBlock *Dst, const CriticalEdgeSplittingOptions &Options = @@ -171,30 +162,28 @@ SplitCriticalEdge(BasicBlock *Src, BasicBlock *Dst, } } -// SplitAllCriticalEdges - Loop over all of the edges in the CFG, -// breaking critical edges as they are found. -// Returns the number of broken edges. +/// Loop over all of the edges in the CFG, breaking critical edges as they are +/// found. Returns the number of broken edges. unsigned SplitAllCriticalEdges(Function &F, const CriticalEdgeSplittingOptions &Options = CriticalEdgeSplittingOptions()); -/// SplitEdge - Split the edge connecting specified block. +/// Split the edge connecting specified block. BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To, DominatorTree *DT = nullptr, LoopInfo *LI = nullptr); -/// SplitBlock - Split the specified block at the specified instruction - every -/// thing before SplitPt stays in Old and everything starting with SplitPt moves -/// to a new block. The two blocks are joined by an unconditional branch and -/// the loop info is updated. -/// +/// Split the specified block at the specified instruction - everything before +/// SplitPt stays in Old and everything starting with SplitPt moves to a new +/// block. The two blocks are joined by an unconditional branch and the loop +/// info is updated. BasicBlock *SplitBlock(BasicBlock *Old, Instruction *SplitPt, DominatorTree *DT = nullptr, LoopInfo *LI = nullptr); -/// SplitBlockPredecessors - This method introduces at least one new basic block -/// into the function and moves some of the predecessors of BB to be -/// predecessors of the new block. The new predecessors are indicated by the -/// Preds array. The new block is given a suffix of 'Suffix'. Returns new basic -/// block to which predecessors from Preds are now pointing. +/// This method introduces at least one new basic block into the function and +/// moves some of the predecessors of BB to be predecessors of the new block. +/// The new predecessors are indicated by the Preds array. The new block is +/// given a suffix of 'Suffix'. Returns new basic block to which predecessors +/// from Preds are now pointing. /// /// If BB is a landingpad block then additional basicblock might be introduced. /// It will have Suffix+".split_lp". See SplitLandingPadPredecessors for more @@ -211,12 +200,12 @@ BasicBlock *SplitBlockPredecessors(BasicBlock *BB, ArrayRef<BasicBlock *> Preds, LoopInfo *LI = nullptr, bool PreserveLCSSA = false); -/// SplitLandingPadPredecessors - This method transforms the landing pad, -/// OrigBB, by introducing two new basic blocks into the function. One of those -/// new basic blocks gets the predecessors listed in Preds. The other basic -/// block gets the remaining predecessors of OrigBB. The landingpad instruction -/// OrigBB is clone into both of the new basic blocks. The new blocks are given -/// the suffixes 'Suffix1' and 'Suffix2', and are returned in the NewBBs vector. +/// This method transforms the landing pad, OrigBB, by introducing two new basic +/// blocks into the function. One of those new basic blocks gets the +/// predecessors listed in Preds. The other basic block gets the remaining +/// predecessors of OrigBB. The landingpad instruction OrigBB is clone into both +/// of the new basic blocks. The new blocks are given the suffixes 'Suffix1' and +/// 'Suffix2', and are returned in the NewBBs vector. /// /// This currently updates the LLVM IR, DominatorTree, LoopInfo, and LCCSA but /// no other analyses. In particular, it does not preserve LoopSimplify @@ -231,19 +220,17 @@ void SplitLandingPadPredecessors(BasicBlock *OrigBB, LoopInfo *LI = nullptr, bool PreserveLCSSA = false); -/// FoldReturnIntoUncondBranch - This method duplicates the specified return -/// instruction into a predecessor which ends in an unconditional branch. If -/// the return instruction returns a value defined by a PHI, propagate the -/// right value into the return. It returns the new return instruction in the -/// predecessor. +/// This method duplicates the specified return instruction into a predecessor +/// which ends in an unconditional branch. If the return instruction returns a +/// value defined by a PHI, propagate the right value into the return. It +/// returns the new return instruction in the predecessor. ReturnInst *FoldReturnIntoUncondBranch(ReturnInst *RI, BasicBlock *BB, BasicBlock *Pred); -/// SplitBlockAndInsertIfThen - Split the containing block at the -/// specified instruction - everything before and including SplitBefore stays -/// in the old basic block, and everything after SplitBefore is moved to a -/// new block. The two blocks are connected by a conditional branch -/// (with value of Cmp being the condition). +/// Split the containing block at the specified instruction - everything before +/// and including SplitBefore stays in the old basic block, and everything after +/// SplitBefore is moved to a new block. The two blocks are connected by a +/// conditional branch (with value of Cmp being the condition). /// Before: /// Head /// SplitBefore @@ -259,11 +246,12 @@ ReturnInst *FoldReturnIntoUncondBranch(ReturnInst *RI, BasicBlock *BB, /// UnreachableInst, otherwise it branches to Tail. /// Returns the NewBasicBlock's terminator. /// -/// Updates DT if given. +/// Updates DT and LI if given. TerminatorInst *SplitBlockAndInsertIfThen(Value *Cond, Instruction *SplitBefore, bool Unreachable, MDNode *BranchWeights = nullptr, - DominatorTree *DT = nullptr); + DominatorTree *DT = nullptr, + LoopInfo *LI = nullptr); /// SplitBlockAndInsertIfThenElse is similar to SplitBlockAndInsertIfThen, /// but also creates the ElseBlock. @@ -284,12 +272,14 @@ void SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore, TerminatorInst **ElseTerm, MDNode *BranchWeights = nullptr); -/// -/// GetIfCondition - Check whether BB is the merge point of a if-region. +/// Check whether BB is the merge point of a if-region. /// If so, return the boolean condition that determines which entry into /// BB will be taken. Also, return by references the block that will be /// entered from if the condition is true, and the block that will be /// entered if the condition is false. +/// +/// This does no checking to see if the true/false blocks have large or unsavory +/// instructions in them. Value *GetIfCondition(BasicBlock *BB, BasicBlock *&IfTrue, BasicBlock *&IfFalse); } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index 879f295caf0c..2d2a85905d0e 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -22,94 +22,96 @@ namespace llvm { class DataLayout; class TargetLibraryInfo; - /// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*. - Value *CastToCStr(Value *V, IRBuilder<> &B); - - /// EmitStrLen - Emit a call to the strlen function to the builder, for the - /// specified pointer. Ptr is required to be some pointer type, and the - /// return value has 'intptr_t' type. - Value *EmitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, + /// Analyze the name and prototype of the given function and set any + /// applicable attributes. + /// If the library function is unavailable, this doesn't modify it. + /// + /// Returns true if any attributes were set and false otherwise. + bool inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI); + + /// Return V if it is an i8*, otherwise cast it to i8*. + Value *castToCStr(Value *V, IRBuilder<> &B); + + /// Emit a call to the strlen function to the builder, for the specified + /// pointer. Ptr is required to be some pointer type, and the return value has + /// 'intptr_t' type. + Value *emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitStrNLen - Emit a call to the strnlen function to the builder, for the - /// specified pointer. Ptr is required to be some pointer type, MaxLen must - /// be of size_t type, and the return value has 'intptr_t' type. - Value *EmitStrNLen(Value *Ptr, Value *MaxLen, IRBuilder<> &B, + /// Emit a call to the strnlen function to the builder, for the specified + /// pointer. Ptr is required to be some pointer type, MaxLen must be of size_t + /// type, and the return value has 'intptr_t' type. + Value *emitStrNLen(Value *Ptr, Value *MaxLen, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitStrChr - Emit a call to the strchr function to the builder, for the - /// specified pointer and character. Ptr is required to be some pointer type, - /// and the return value has 'i8*' type. - Value *EmitStrChr(Value *Ptr, char C, IRBuilder<> &B, + /// Emit a call to the strchr function to the builder, for the specified + /// pointer and character. Ptr is required to be some pointer type, and the + /// return value has 'i8*' type. + Value *emitStrChr(Value *Ptr, char C, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// EmitStrNCmp - Emit a call to the strncmp function to the builder. - Value *EmitStrNCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, + /// Emit a call to the strncmp function to the builder. + Value *emitStrNCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitStrCpy - Emit a call to the strcpy function to the builder, for the - /// specified pointer arguments. - Value *EmitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, + /// Emit a call to the strcpy function to the builder, for the specified + /// pointer arguments. + Value *emitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, const TargetLibraryInfo *TLI, StringRef Name = "strcpy"); - /// EmitStrNCpy - Emit a call to the strncpy function to the builder, for the - /// specified pointer arguments and length. - Value *EmitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, + /// Emit a call to the strncpy function to the builder, for the specified + /// pointer arguments and length. + Value *emitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, const TargetLibraryInfo *TLI, StringRef Name = "strncpy"); - /// EmitMemCpyChk - Emit a call to the __memcpy_chk function to the builder. - /// This expects that the Len and ObjSize have type 'intptr_t' and Dst/Src - /// are pointers. - Value *EmitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, + /// Emit a call to the __memcpy_chk function to the builder. This expects that + /// the Len and ObjSize have type 'intptr_t' and Dst/Src are pointers. + Value *emitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is - /// a pointer, Val is an i32 value, and Len is an 'intptr_t' value. - Value *EmitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B, + /// Emit a call to the memchr function. This assumes that Ptr is a pointer, + /// Val is an i32 value, and Len is an 'intptr_t' value. + Value *emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitMemCmp - Emit a call to the memcmp function. - Value *EmitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, + /// Emit a call to the memcmp function. + Value *emitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); - /// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' - /// (e.g. 'floor'). This function is known to take a single of type matching - /// 'Op' and returns one value with the same type. If 'Op' is a long double, - /// 'l' is added as the suffix of name, if 'Op' is a float, we add a 'f' - /// suffix. - Value *EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, + /// Emit a call to the unary function named 'Name' (e.g. 'floor'). This + /// function is known to take a single of type matching 'Op' and returns one + /// value with the same type. If 'Op' is a long double, 'l' is added as the + /// suffix of name, if 'Op' is a float, we add a 'f' suffix. + Value *emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, const AttributeSet &Attrs); - /// EmitUnaryFloatFnCall - Emit a call to the binary function named 'Name' - /// (e.g. 'fmin'). This function is known to take type matching 'Op1' and - /// 'Op2' and return one value with the same type. If 'Op1/Op2' are long - /// double, 'l' is added as the suffix of name, if 'Op1/Op2' are float, we - /// add a 'f' suffix. - Value *EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, + /// Emit a call to the binary function named 'Name' (e.g. 'fmin'). This + /// function is known to take type matching 'Op1' and 'Op2' and return one + /// value with the same type. If 'Op1/Op2' are long double, 'l' is added as + /// the suffix of name, if 'Op1/Op2' are float, we add a 'f' suffix. + Value *emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, IRBuilder<> &B, const AttributeSet &Attrs); - /// EmitPutChar - Emit a call to the putchar function. This assumes that Char - /// is an integer. - Value *EmitPutChar(Value *Char, IRBuilder<> &B, const TargetLibraryInfo *TLI); + /// Emit a call to the putchar function. This assumes that Char is an integer. + Value *emitPutChar(Value *Char, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// EmitPutS - Emit a call to the puts function. This assumes that Str is - /// some pointer. - Value *EmitPutS(Value *Str, IRBuilder<> &B, const TargetLibraryInfo *TLI); + /// Emit a call to the puts function. This assumes that Str is some pointer. + Value *emitPutS(Value *Str, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// EmitFPutC - Emit a call to the fputc function. This assumes that Char is - /// an i32, and File is a pointer to FILE. - Value *EmitFPutC(Value *Char, Value *File, IRBuilder<> &B, + /// Emit a call to the fputc function. This assumes that Char is an i32, and + /// File is a pointer to FILE. + Value *emitFPutC(Value *Char, Value *File, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// EmitFPutS - Emit a call to the puts function. Str is required to be a - /// pointer and File is a pointer to FILE. - Value *EmitFPutS(Value *Str, Value *File, IRBuilder<> &B, + /// Emit a call to the puts function. Str is required to be a pointer and + /// File is a pointer to FILE. + Value *emitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is - /// a pointer, Size is an 'intptr_t', and File is a pointer to FILE. - Value *EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, + /// Emit a call to the fwrite function. This assumes that Ptr is a pointer, + /// Size is an 'intptr_t', and File is a pointer to FILE. + Value *emitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); } diff --git a/include/llvm/Transforms/Utils/Cloning.h b/include/llvm/Transforms/Utils/Cloning.h index 4f006f2adeef..c5fb37007090 100644 --- a/include/llvm/Transforms/Utils/Cloning.h +++ b/include/llvm/Transforms/Utils/Cloning.h @@ -59,7 +59,7 @@ std::unique_ptr<Module> CloneModule(const Module *M, ValueToValueMapTy &VMap); /// in place of the global definition. std::unique_ptr<Module> CloneModule(const Module *M, ValueToValueMapTy &VMap, - std::function<bool(const GlobalValue *)> ShouldCloneDefinition); + function_ref<bool(const GlobalValue *)> ShouldCloneDefinition); /// ClonedCodeInfo - This struct can be used to capture information about code /// being cloned, while it is being cloned. @@ -114,20 +114,19 @@ BasicBlock *CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap, const Twine &NameSuffix = "", Function *F = nullptr, ClonedCodeInfo *CodeInfo = nullptr); -/// CloneFunction - Return a copy of the specified function, but without -/// embedding the function into another module. Also, any references specified -/// in the VMap are changed to refer to their mapped value instead of the -/// original one. If any of the arguments to the function are in the VMap, -/// the arguments are deleted from the resultant function. The VMap is -/// updated to include mappings from all of the instructions and basicblocks in -/// the function from their old to new values. The final argument captures -/// information about the cloned code if non-null. +/// CloneFunction - Return a copy of the specified function and add it to that +/// function's module. Also, any references specified in the VMap are changed +/// to refer to their mapped value instead of the original one. If any of the +/// arguments to the function are in the VMap, the arguments are deleted from +/// the resultant function. The VMap is updated to include mappings from all of +/// the instructions and basicblocks in the function from their old to new +/// values. The final argument captures information about the cloned code if +/// non-null. /// -/// If ModuleLevelChanges is false, VMap contains no non-identity GlobalValue -/// mappings, and debug info metadata will not be cloned. +/// VMap contains no non-identity GlobalValue mappings and debug info metadata +/// will not be cloned. /// -Function *CloneFunction(const Function *F, ValueToValueMapTy &VMap, - bool ModuleLevelChanges, +Function *CloneFunction(Function *F, ValueToValueMapTy &VMap, ClonedCodeInfo *CodeInfo = nullptr); /// Clone OldFunc into NewFunc, transforming the old arguments into references @@ -221,6 +220,7 @@ bool InlineFunction(CallSite CS, InlineFunctionInfo &IFI, /// /// Updates LoopInfo and DominatorTree assuming the loop is dominated by block /// \p LoopDomBB. Insert the new blocks before block specified in \p Before. +/// Note: Only innermost loops are supported. Loop *cloneLoopWithPreheader(BasicBlock *Before, BasicBlock *LoopDomBB, Loop *OrigLoop, ValueToValueMapTy &VMap, const Twine &NameSuffix, LoopInfo *LI, diff --git a/include/llvm/Transforms/Utils/CodeExtractor.h b/include/llvm/Transforms/Utils/CodeExtractor.h index 3a96d955cac2..30dafd045f23 100644 --- a/include/llvm/Transforms/Utils/CodeExtractor.h +++ b/include/llvm/Transforms/Utils/CodeExtractor.h @@ -15,10 +15,10 @@ #ifndef LLVM_TRANSFORMS_UTILS_CODEEXTRACTOR_H #define LLVM_TRANSFORMS_UTILS_CODEEXTRACTOR_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SetVector.h" namespace llvm { +template <typename T> class ArrayRef; class BasicBlock; class DominatorTree; class Function; diff --git a/include/llvm/Transforms/Utils/Evaluator.h b/include/llvm/Transforms/Utils/Evaluator.h new file mode 100644 index 000000000000..07f12f41b3bc --- /dev/null +++ b/include/llvm/Transforms/Utils/Evaluator.h @@ -0,0 +1,119 @@ +//===-- Evaluator.h - LLVM IR evaluator -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Function evaluator for LLVM IR. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_EVALUATOR_H +#define LLVM_TRANSFORMS_UTILS_EVALUATOR_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/GlobalVariable.h" + +#include <deque> +#include <memory> + +namespace llvm { + +class DataLayout; +class Function; +class TargetLibraryInfo; + +/// This class evaluates LLVM IR, producing the Constant representing each SSA +/// instruction. Changes to global variables are stored in a mapping that can +/// be iterated over after the evaluation is complete. Once an evaluation call +/// fails, the evaluation object should not be reused. +class Evaluator { +public: + Evaluator(const DataLayout &DL, const TargetLibraryInfo *TLI) + : DL(DL), TLI(TLI) { + ValueStack.emplace_back(); + } + + ~Evaluator() { + for (auto &Tmp : AllocaTmps) + // If there are still users of the alloca, the program is doing something + // silly, e.g. storing the address of the alloca somewhere and using it + // later. Since this is undefined, we'll just make it be null. + if (!Tmp->use_empty()) + Tmp->replaceAllUsesWith(Constant::getNullValue(Tmp->getType())); + } + + /// Evaluate a call to function F, returning true if successful, false if we + /// can't evaluate it. ActualArgs contains the formal arguments for the + /// function. + bool EvaluateFunction(Function *F, Constant *&RetVal, + const SmallVectorImpl<Constant*> &ActualArgs); + + /// Evaluate all instructions in block BB, returning true if successful, false + /// if we can't evaluate it. NewBB returns the next BB that control flows + /// into, or null upon return. + bool EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB); + + Constant *getVal(Value *V) { + if (Constant *CV = dyn_cast<Constant>(V)) return CV; + Constant *R = ValueStack.back().lookup(V); + assert(R && "Reference to an uncomputed value!"); + return R; + } + + void setVal(Value *V, Constant *C) { + ValueStack.back()[V] = C; + } + + const DenseMap<Constant*, Constant*> &getMutatedMemory() const { + return MutatedMemory; + } + + const SmallPtrSetImpl<GlobalVariable*> &getInvariants() const { + return Invariants; + } + +private: + Constant *ComputeLoadResult(Constant *P); + + /// As we compute SSA register values, we store their contents here. The back + /// of the deque contains the current function and the stack contains the + /// values in the calling frames. + std::deque<DenseMap<Value*, Constant*>> ValueStack; + + /// This is used to detect recursion. In pathological situations we could hit + /// exponential behavior, but at least there is nothing unbounded. + SmallVector<Function*, 4> CallStack; + + /// For each store we execute, we update this map. Loads check this to get + /// the most up-to-date value. If evaluation is successful, this state is + /// committed to the process. + DenseMap<Constant*, Constant*> MutatedMemory; + + /// To 'execute' an alloca, we create a temporary global variable to represent + /// its body. This vector is needed so we can delete the temporary globals + /// when we are done. + SmallVector<std::unique_ptr<GlobalVariable>, 32> AllocaTmps; + + /// These global variables have been marked invariant by the static + /// constructor. + SmallPtrSet<GlobalVariable*, 8> Invariants; + + /// These are constants we have checked and know to be simple enough to live + /// in a static initializer of a global. + SmallPtrSet<Constant*, 8> SimpleConstants; + + const DataLayout &DL; + const TargetLibraryInfo *TLI; +}; + +} + +#endif diff --git a/include/llvm/Transforms/Utils/FunctionImportUtils.h b/include/llvm/Transforms/Utils/FunctionImportUtils.h new file mode 100644 index 000000000000..3b94ef60be5d --- /dev/null +++ b/include/llvm/Transforms/Utils/FunctionImportUtils.h @@ -0,0 +1,100 @@ +//===- FunctionImportUtils.h - Importing support utilities -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FunctionImportGlobalProcessing class which is used +// to perform the necessary global value handling for function importing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_FUNCTIONIMPORTUTILS_H +#define LLVM_TRANSFORMS_UTILS_FUNCTIONIMPORTUTILS_H + +#include "llvm/ADT/SetVector.h" +#include "llvm/IR/ModuleSummaryIndex.h" + +namespace llvm { +class Module; + +/// Class to handle necessary GlobalValue changes required by ThinLTO +/// function importing, including linkage changes and any necessary renaming. +class FunctionImportGlobalProcessing { + /// The Module which we are exporting or importing functions from. + Module &M; + + /// Module summary index passed in for function importing/exporting handling. + const ModuleSummaryIndex &ImportIndex; + + /// Globals to import from this module, all other functions will be + /// imported as declarations instead of definitions. + DenseSet<const GlobalValue *> *GlobalsToImport; + + /// Set to true if the given ModuleSummaryIndex contains any functions + /// from this source module, in which case we must conservatively assume + /// that any of its functions may be imported into another module + /// as part of a different backend compilation process. + bool HasExportedFunctions = false; + + /// Check if we should promote the given local value to global scope. + bool doPromoteLocalToGlobal(const GlobalValue *SGV); + + /// Helper methods to check if we are importing from or potentially + /// exporting from the current source module. + bool isPerformingImport() const { return GlobalsToImport != nullptr; } + bool isModuleExporting() const { return HasExportedFunctions; } + + /// If we are importing from the source module, checks if we should + /// import SGV as a definition, otherwise import as a declaration. + bool doImportAsDefinition(const GlobalValue *SGV); + + /// Get the name for SGV that should be used in the linked destination + /// module. Specifically, this handles the case where we need to rename + /// a local that is being promoted to global scope. + std::string getName(const GlobalValue *SGV); + + /// Process globals so that they can be used in ThinLTO. This includes + /// promoting local variables so that they can be reference externally by + /// thin lto imported globals and converting strong external globals to + /// available_externally. + void processGlobalsForThinLTO(); + void processGlobalForThinLTO(GlobalValue &GV); + + /// Get the new linkage for SGV that should be used in the linked destination + /// module. Specifically, for ThinLTO importing or exporting it may need + /// to be adjusted. + GlobalValue::LinkageTypes getLinkage(const GlobalValue *SGV); + +public: + FunctionImportGlobalProcessing( + Module &M, const ModuleSummaryIndex &Index, + DenseSet<const GlobalValue *> *GlobalsToImport = nullptr) + : M(M), ImportIndex(Index), GlobalsToImport(GlobalsToImport) { + // If we have a ModuleSummaryIndex but no function to import, + // then this is the primary module being compiled in a ThinLTO + // backend compilation, and we need to see if it has functions that + // may be exported to another backend compilation. + if (!GlobalsToImport) + HasExportedFunctions = ImportIndex.hasExportedFunctions(M); + } + + bool run(); + + static bool + doImportAsDefinition(const GlobalValue *SGV, + DenseSet<const GlobalValue *> *GlobalsToImport); +}; + +/// Perform in-place global value handling on the given Module for +/// exported local functions renamed and promoted for ThinLTO. +bool renameModuleForThinLTO( + Module &M, const ModuleSummaryIndex &Index, + DenseSet<const GlobalValue *> *GlobalsToImport = nullptr); + +} // End llvm namespace + +#endif diff --git a/include/llvm/Transforms/Utils/LCSSA.h b/include/llvm/Transforms/Utils/LCSSA.h new file mode 100644 index 000000000000..f0277d021541 --- /dev/null +++ b/include/llvm/Transforms/Utils/LCSSA.h @@ -0,0 +1,44 @@ +//===- LCSSA.h - Loop-closed SSA transform Pass -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass transforms loops by placing phi nodes at the end of the loops for +// all values that are live across the loop boundary. For example, it turns +// the left into the right code: +// +// for (...) for (...) +// if (c) if (c) +// X1 = ... X1 = ... +// else else +// X2 = ... X2 = ... +// X3 = phi(X1, X2) X3 = phi(X1, X2) +// ... = X3 + 4 X4 = phi(X3) +// ... = X4 + 4 +// +// This is still valid LLVM; the extra phi nodes are purely redundant, and will +// be trivially eliminated by InstCombine. The major benefit of this +// transformation is that it makes many other loop optimizations, such as +// LoopUnswitching, simpler. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_LCSSA_H +#define LLVM_TRANSFORMS_UTILS_LCSSA_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Converts loops into loop-closed SSA form. +class LCSSAPass : public PassInfoMixin<LCSSAPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_LCSSA_H diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index 3ae01657a2ec..43b376cf8068 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -21,6 +21,7 @@ #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Operator.h" +#include "llvm/ADT/SmallPtrSet.h" namespace llvm { @@ -29,6 +30,7 @@ class BasicBlock; class Function; class BranchInst; class Instruction; +class CallInst; class DbgDeclareInst; class StoreInst; class LoadInst; @@ -50,10 +52,10 @@ template<typename T> class SmallVectorImpl; // Local constant propagation. // -/// ConstantFoldTerminator - If a terminator instruction is predicated on a -/// constant value, convert it into an unconditional branch to the constant -/// destination. This is a nontrivial operation because the successors of this -/// basic block must have their PHI nodes updated. +/// If a terminator instruction is predicated on a constant value, convert it +/// into an unconditional branch to the constant destination. +/// This is a nontrivial operation because the successors of this basic block +/// must have their PHI nodes updated. /// Also calls RecursivelyDeleteTriviallyDeadInstructions() on any branch/switch /// conditions and indirectbr addresses this might make dead if /// DeleteDeadConditions is true. @@ -64,29 +66,27 @@ bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false, // Local dead code elimination. // -/// isInstructionTriviallyDead - Return true if the result produced by the -/// instruction is not used, and the instruction has no side effects. -/// +/// Return true if the result produced by the instruction is not used, and the +/// instruction has no side effects. bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI = nullptr); -/// RecursivelyDeleteTriviallyDeadInstructions - If the specified value is a -/// trivially dead instruction, delete it. If that makes any of its operands -/// trivially dead, delete them too, recursively. Return true if any -/// instructions were deleted. +/// If the specified value is a trivially dead instruction, delete it. +/// If that makes any of its operands trivially dead, delete them too, +/// recursively. Return true if any instructions were deleted. bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI = nullptr); -/// RecursivelyDeleteDeadPHINode - If the specified value is an effectively -/// dead PHI node, due to being a def-use chain of single-use nodes that -/// either forms a cycle or is terminated by a trivially dead instruction, -/// delete it. If that makes any of its operands trivially dead, delete them -/// too, recursively. Return true if a change was made. +/// If the specified value is an effectively dead PHI node, due to being a +/// def-use chain of single-use nodes that either forms a cycle or is terminated +/// by a trivially dead instruction, delete it. If that makes any of its +/// operands trivially dead, delete them too, recursively. Return true if a +/// change was made. bool RecursivelyDeleteDeadPHINode(PHINode *PN, const TargetLibraryInfo *TLI = nullptr); -/// SimplifyInstructionsInBlock - Scan the specified basic block and try to -/// simplify any instructions in it and recursively delete dead instructions. +/// Scan the specified basic block and try to simplify any instructions in it +/// and recursively delete dead instructions. /// /// This returns true if it changed the code, note that it can delete /// instructions in other blocks as well in this block. @@ -97,9 +97,9 @@ bool SimplifyInstructionsInBlock(BasicBlock *BB, // Control Flow Graph Restructuring. // -/// RemovePredecessorAndSimplify - Like BasicBlock::removePredecessor, this -/// method is called when we're about to delete Pred as a predecessor of BB. If -/// BB contains any PHI nodes, this drops the entries in the PHI nodes for Pred. +/// Like BasicBlock::removePredecessor, this method is called when we're about +/// to delete Pred as a predecessor of BB. If BB contains any PHI nodes, this +/// drops the entries in the PHI nodes for Pred. /// /// Unlike the removePredecessor method, this attempts to simplify uses of PHI /// nodes that collapse into identity values. For example, if we have: @@ -110,74 +110,68 @@ bool SimplifyInstructionsInBlock(BasicBlock *BB, /// recursively fold the 'and' to 0. void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred); -/// MergeBasicBlockIntoOnlyPred - BB is a block with one predecessor and its -/// predecessor is known to have one successor (BB!). Eliminate the edge -/// between them, moving the instructions in the predecessor into BB. This -/// deletes the predecessor block. -/// +/// BB is a block with one predecessor and its predecessor is known to have one +/// successor (BB!). Eliminate the edge between them, moving the instructions in +/// the predecessor into BB. This deletes the predecessor block. void MergeBasicBlockIntoOnlyPred(BasicBlock *BB, DominatorTree *DT = nullptr); -/// TryToSimplifyUncondBranchFromEmptyBlock - BB is known to contain an -/// unconditional branch, and contains no instructions other than PHI nodes, -/// potential debug intrinsics and the branch. If possible, eliminate BB by -/// rewriting all the predecessors to branch to the successor block and return -/// true. If we can't transform, return false. +/// BB is known to contain an unconditional branch, and contains no instructions +/// other than PHI nodes, potential debug intrinsics and the branch. If +/// possible, eliminate BB by rewriting all the predecessors to branch to the +/// successor block and return true. If we can't transform, return false. bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB); -/// EliminateDuplicatePHINodes - Check for and eliminate duplicate PHI -/// nodes in this block. This doesn't try to be clever about PHI nodes -/// which differ only in the order of the incoming values, but instcombine -/// orders them so it usually won't matter. -/// +/// Check for and eliminate duplicate PHI nodes in this block. This doesn't try +/// to be clever about PHI nodes which differ only in the order of the incoming +/// values, but instcombine orders them so it usually won't matter. bool EliminateDuplicatePHINodes(BasicBlock *BB); -/// SimplifyCFG - This function is used to do simplification of a CFG. For +/// This function is used to do simplification of a CFG. For /// example, it adjusts branches to branches to eliminate the extra hop, it /// eliminates unreachable basic blocks, and does other "peephole" optimization /// of the CFG. It returns true if a modification was made, possibly deleting -/// the basic block that was pointed to. -/// +/// the basic block that was pointed to. LoopHeaders is an optional input +/// parameter, providing the set of loop header that SimplifyCFG should not +/// eliminate. bool SimplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, - unsigned BonusInstThreshold, AssumptionCache *AC = nullptr); + unsigned BonusInstThreshold, AssumptionCache *AC = nullptr, + SmallPtrSetImpl<BasicBlock *> *LoopHeaders = nullptr); -/// FlatternCFG - This function is used to flatten a CFG. For -/// example, it uses parallel-and and parallel-or mode to collapse -// if-conditions and merge if-regions with identical statements. -/// +/// This function is used to flatten a CFG. For example, it uses parallel-and +/// and parallel-or mode to collapse if-conditions and merge if-regions with +/// identical statements. bool FlattenCFG(BasicBlock *BB, AliasAnalysis *AA = nullptr); -/// FoldBranchToCommonDest - If this basic block is ONLY a setcc and a branch, -/// and if a predecessor branches to us and one of our successors, fold the -/// setcc into the predecessor and use logical operations to pick the right -/// destination. +/// If this basic block is ONLY a setcc and a branch, and if a predecessor +/// branches to us and one of our successors, fold the setcc into the +/// predecessor and use logical operations to pick the right destination. bool FoldBranchToCommonDest(BranchInst *BI, unsigned BonusInstThreshold = 1); -/// DemoteRegToStack - This function takes a virtual register computed by an -/// Instruction and replaces it with a slot in the stack frame, allocated via -/// alloca. This allows the CFG to be changed around without fear of -/// invalidating the SSA information for the value. It returns the pointer to -/// the alloca inserted to create a stack slot for X. -/// +/// This function takes a virtual register computed by an Instruction and +/// replaces it with a slot in the stack frame, allocated via alloca. +/// This allows the CFG to be changed around without fear of invalidating the +/// SSA information for the value. It returns the pointer to the alloca inserted +/// to create a stack slot for X. AllocaInst *DemoteRegToStack(Instruction &X, bool VolatileLoads = false, Instruction *AllocaPoint = nullptr); -/// DemotePHIToStack - This function takes a virtual register computed by a phi -/// node and replaces it with a slot in the stack frame, allocated via alloca. -/// The phi node is deleted and it returns the pointer to the alloca inserted. +/// This function takes a virtual register computed by a phi node and replaces +/// it with a slot in the stack frame, allocated via alloca. The phi node is +/// deleted and it returns the pointer to the alloca inserted. AllocaInst *DemotePHIToStack(PHINode *P, Instruction *AllocaPoint = nullptr); -/// getOrEnforceKnownAlignment - If the specified pointer has an alignment that -/// we can determine, return it, otherwise return 0. If PrefAlign is specified, -/// and it is more than the alignment of the ultimate object, see if we can -/// increase the alignment of the ultimate object, making this check succeed. +/// If the specified pointer has an alignment that we can determine, return it, +/// otherwise return 0. If PrefAlign is specified, and it is more than the +/// alignment of the ultimate object, see if we can increase the alignment of +/// the ultimate object, making this check succeed. unsigned getOrEnforceKnownAlignment(Value *V, unsigned PrefAlign, const DataLayout &DL, const Instruction *CxtI = nullptr, AssumptionCache *AC = nullptr, const DominatorTree *DT = nullptr); -/// getKnownAlignment - Try to infer an alignment for the specified pointer. +/// Try to infer an alignment for the specified pointer. static inline unsigned getKnownAlignment(Value *V, const DataLayout &DL, const Instruction *CxtI = nullptr, AssumptionCache *AC = nullptr, @@ -185,9 +179,9 @@ static inline unsigned getKnownAlignment(Value *V, const DataLayout &DL, return getOrEnforceKnownAlignment(V, 0, DL, CxtI, AC, DT); } -/// EmitGEPOffset - Given a getelementptr instruction/constantexpr, emit the -/// code necessary to compute the offset from the base pointer (without adding -/// in the base pointer). Return the result as a signed integer of intptr size. +/// Given a getelementptr instruction/constantexpr, emit the code necessary to +/// compute the offset from the base pointer (without adding in the base +/// pointer). Return the result as a signed integer of intptr size. /// When NoAssumptions is true, no assumptions about index computation not /// overflowing is made. template <typename IRBuilderTy> @@ -264,15 +258,14 @@ bool ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, bool ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, LoadInst *LI, DIBuilder &Builder); -/// LowerDbgDeclare - Lowers llvm.dbg.declare intrinsics into appropriate set -/// of llvm.dbg.value intrinsics. +/// Lowers llvm.dbg.declare intrinsics into appropriate set of +/// llvm.dbg.value intrinsics. bool LowerDbgDeclare(Function &F); -/// FindAllocaDbgDeclare - Finds the llvm.dbg.declare intrinsic corresponding to -/// an alloca, if any. +/// Finds the llvm.dbg.declare intrinsic corresponding to an alloca, if any. DbgDeclareInst *FindAllocaDbgDeclare(Value *V); -/// \brief Replaces llvm.dbg.declare instruction when the address it describes +/// Replaces llvm.dbg.declare instruction when the address it describes /// is replaced with a new value. If Deref is true, an additional DW_OP_deref is /// prepended to the expression. If Offset is non-zero, a constant displacement /// is added to the expression (after the optional Deref). Offset can be @@ -281,7 +274,7 @@ bool replaceDbgDeclare(Value *Address, Value *NewAddress, Instruction *InsertBefore, DIBuilder &Builder, bool Deref, int Offset); -/// \brief Replaces llvm.dbg.declare instruction when the alloca it describes +/// Replaces llvm.dbg.declare instruction when the alloca it describes /// is replaced with a new value. If Deref is true, an additional DW_OP_deref is /// prepended to the expression. If Offset is non-zero, a constant displacement /// is added to the expression (after the optional Deref). Offset can be @@ -289,39 +282,51 @@ bool replaceDbgDeclare(Value *Address, Value *NewAddress, bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, bool Deref, int Offset = 0); -/// \brief Insert an unreachable instruction before the specified +/// Replaces multiple llvm.dbg.value instructions when the alloca it describes +/// is replaced with a new value. If Offset is non-zero, a constant displacement +/// is added to the expression (after the mandatory Deref). Offset can be +/// negative. New llvm.dbg.value instructions are inserted at the locations of +/// the instructions they replace. +void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, + DIBuilder &Builder, int Offset = 0); + +/// Remove all instructions from a basic block other than it's terminator +/// and any present EH pad instructions. +unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB); + +/// Insert an unreachable instruction before the specified /// instruction, making it and the rest of the code in the block dead. -void changeToUnreachable(Instruction *I, bool UseLLVMTrap); +unsigned changeToUnreachable(Instruction *I, bool UseLLVMTrap); /// Replace 'BB's terminator with one that does not have an unwind successor -/// block. Rewrites `invoke` to `call`, etc. Updates any PHIs in unwind +/// block. Rewrites `invoke` to `call`, etc. Updates any PHIs in unwind /// successor. /// /// \param BB Block whose terminator will be replaced. Its terminator must /// have an unwind successor. void removeUnwindEdge(BasicBlock *BB); -/// \brief Remove all blocks that can not be reached from the function's entry. +/// Remove all blocks that can not be reached from the function's entry. /// /// Returns true if any basic block was removed. bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr); -/// \brief Combine the metadata of two instructions so that K can replace J +/// Combine the metadata of two instructions so that K can replace J /// /// Metadata not listed as known via KnownIDs is removed void combineMetadata(Instruction *K, const Instruction *J, ArrayRef<unsigned> KnownIDs); -/// \brief Replace each use of 'From' with 'To' if that use is dominated by +/// Replace each use of 'From' with 'To' if that use is dominated by /// the given edge. Returns the number of replacements made. unsigned replaceDominatedUsesWith(Value *From, Value *To, DominatorTree &DT, const BasicBlockEdge &Edge); -/// \brief Replace each use of 'From' with 'To' if that use is dominated by -/// the given BasicBlock. Returns the number of replacements made. +/// Replace each use of 'From' with 'To' if that use is dominated by +/// the end of the given BasicBlock. Returns the number of replacements made. unsigned replaceDominatedUsesWith(Value *From, Value *To, DominatorTree &DT, const BasicBlock *BB); -/// \brief Return true if the CallSite CS calls a gc leaf function. +/// Return true if the CallSite CS calls a gc leaf function. /// /// A leaf function is a function that does not safepoint the thread during its /// execution. During a call or invoke to such a function, the callers stack @@ -335,7 +340,7 @@ bool callsGCLeafFunction(ImmutableCallSite CS); // Intrinsic pattern matching // -/// Try and match a bitreverse or bswap idiom. +/// Try and match a bswap or bitreverse idiom. /// /// If an idiom is matched, an intrinsic call is inserted before \c I. Any added /// instructions are returned in \c InsertedInsts. They will all have been added @@ -346,10 +351,21 @@ bool callsGCLeafFunction(ImmutableCallSite CS); /// to BW / 4 nodes to be searched, so is significantly faster. /// /// This function returns true on a successful match or false otherwise. -bool recognizeBitReverseOrBSwapIdiom( +bool recognizeBSwapOrBitReverseIdiom( Instruction *I, bool MatchBSwaps, bool MatchBitReversals, SmallVectorImpl<Instruction *> &InsertedInsts); +//===----------------------------------------------------------------------===// +// Sanitizer utilities +// + +/// Given a CallInst, check if it calls a string function known to CodeGen, +/// and mark it with NoBuiltin if so. To be used by sanitizers that intend +/// to intercept string functions and want to avoid converting them to target +/// specific instructions. +void maybeMarkSanitizerLibraryCallNoBuiltin(CallInst *CI, + const TargetLibraryInfo *TLI); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Utils/LoopSimplify.h b/include/llvm/Transforms/Utils/LoopSimplify.h new file mode 100644 index 000000000000..7cf89eaeb939 --- /dev/null +++ b/include/llvm/Transforms/Utils/LoopSimplify.h @@ -0,0 +1,65 @@ +//===- LoopSimplify.h - Loop Canonicalization Pass --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass performs several transformations to transform natural loops into a +// simpler form, which makes subsequent analyses and transformations simpler and +// more effective. +// +// Loop pre-header insertion guarantees that there is a single, non-critical +// entry edge from outside of the loop to the loop header. This simplifies a +// number of analyses and transformations, such as LICM. +// +// Loop exit-block insertion guarantees that all exit blocks from the loop +// (blocks which are outside of the loop that have predecessors inside of the +// loop) only have predecessors from inside of the loop (and are thus dominated +// by the loop header). This simplifies transformations such as store-sinking +// that are built into LICM. +// +// This pass also guarantees that loops will have exactly one backedge. +// +// Indirectbr instructions introduce several complications. If the loop +// contains or is entered by an indirectbr instruction, it may not be possible +// to transform the loop and make these guarantees. Client code should check +// that these conditions are true before relying on them. +// +// Note that the simplifycfg pass will clean up blocks which are split out but +// end up being unnecessary, so usage of this pass should not pessimize +// generated code. +// +// This pass obviously modifies the CFG, but updates loop information and +// dominator information. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TRANSFORMS_UTILS_LOOPSIMPLIFY_H +#define LLVM_TRANSFORMS_UTILS_LOOPSIMPLIFY_H + +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// This pass is responsible for loop canonicalization. +class LoopSimplifyPass : public PassInfoMixin<LoopSimplifyPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Simplify each loop in a loop nest recursively. +/// +/// This takes a potentially un-simplified loop L (and its children) and turns +/// it into a simplified loop nest with preheaders and single backedges. It will +/// update \c AliasAnalysis and \c ScalarEvolution analyses if they're non-null. +bool simplifyLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, bool PreserveLCSSA); + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_LOOPSIMPLIFY_H diff --git a/include/llvm/Transforms/Utils/LoopUtils.h b/include/llvm/Transforms/Utils/LoopUtils.h index 2cfacb650ff5..89fea10f818a 100644 --- a/include/llvm/Transforms/Utils/LoopUtils.h +++ b/include/llvm/Transforms/Utils/LoopUtils.h @@ -30,20 +30,21 @@ class DominatorTree; class Loop; class LoopInfo; class Pass; +class PredicatedScalarEvolution; class PredIteratorCache; class ScalarEvolution; +class SCEV; class TargetLibraryInfo; /// \brief Captures loop safety information. /// It keep information for loop & its header may throw exception. -struct LICMSafetyInfo { - bool MayThrow; // The current loop contains an instruction which - // may throw. - bool HeaderMayThrow; // Same as previous, but specific to loop header +struct LoopSafetyInfo { + bool MayThrow; // The current loop contains an instruction which + // may throw. + bool HeaderMayThrow; // Same as previous, but specific to loop header // Used to update funclet bundle operands. DenseMap<BasicBlock *, ColorVector> BlockColors; - LICMSafetyInfo() : MayThrow(false), HeaderMayThrow(false) - {} + LoopSafetyInfo() : MayThrow(false), HeaderMayThrow(false) {} }; /// The RecurrenceDescriptor is used to identify recurrences variables in a @@ -175,6 +176,13 @@ public: static bool isReductionPHI(PHINode *Phi, Loop *TheLoop, RecurrenceDescriptor &RedDes); + /// Returns true if Phi is a first-order recurrence. A first-order recurrence + /// is a non-reduction recurrence relation in which the value of the + /// recurrence in the current loop iteration equals a value defined in the + /// previous iteration. + static bool isFirstOrderRecurrence(PHINode *Phi, Loop *TheLoop, + DominatorTree *DT); + RecurrenceKind getRecurrenceKind() { return Kind; } MinMaxRecurrenceKind getMinMaxRecurrenceKind() { return MinMaxKind; } @@ -261,7 +269,7 @@ public: public: /// Default constructor - creates an invalid induction. InductionDescriptor() - : StartValue(nullptr), IK(IK_NoInduction), StepValue(nullptr) {} + : StartValue(nullptr), IK(IK_NoInduction), Step(nullptr) {} /// Get the consecutive direction. Returns: /// 0 - unknown or non-consecutive. @@ -275,37 +283,59 @@ public: /// For pointer induction, returns StartValue[Index * StepValue]. /// FIXME: The newly created binary instructions should contain nsw/nuw /// flags, which can be found from the original scalar operations. - Value *transform(IRBuilder<> &B, Value *Index) const; + Value *transform(IRBuilder<> &B, Value *Index, ScalarEvolution *SE, + const DataLayout& DL) const; Value *getStartValue() const { return StartValue; } InductionKind getKind() const { return IK; } - ConstantInt *getStepValue() const { return StepValue; } - + const SCEV *getStep() const { return Step; } + ConstantInt *getConstIntStepValue() const; + + /// Returns true if \p Phi is an induction. If \p Phi is an induction, + /// the induction descriptor \p D will contain the data describing this + /// induction. If by some other means the caller has a better SCEV + /// expression for \p Phi than the one returned by the ScalarEvolution + /// analysis, it can be passed through \p Expr. static bool isInductionPHI(PHINode *Phi, ScalarEvolution *SE, - InductionDescriptor &D); + InductionDescriptor &D, + const SCEV *Expr = nullptr); + + /// Returns true if \p Phi is an induction, in the context associated with + /// the run-time predicate of PSE. If \p Assume is true, this can add further + /// SCEV predicates to \p PSE in order to prove that \p Phi is an induction. + /// If \p Phi is an induction, \p D will contain the data describing this + /// induction. + static bool isInductionPHI(PHINode *Phi, PredicatedScalarEvolution &PSE, + InductionDescriptor &D, bool Assume = false); private: /// Private constructor - used by \c isInductionPHI. - InductionDescriptor(Value *Start, InductionKind K, ConstantInt *Step); + InductionDescriptor(Value *Start, InductionKind K, const SCEV *Step); /// Start value. TrackingVH<Value> StartValue; /// Induction kind. InductionKind IK; /// Step value. - ConstantInt *StepValue; + const SCEV *Step; }; BasicBlock *InsertPreheaderForLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, bool PreserveLCSSA); -/// \brief Simplify each loop in a loop nest recursively. +/// Ensures LCSSA form for every instruction from the Worklist in the scope of +/// innermost containing loop. +/// +/// For the given instruction which have uses outside of the loop, an LCSSA PHI +/// node is inserted and the uses outside the loop are rewritten to use this +/// node. +/// +/// LoopInfo and DominatorTree are required and, since the routine makes no +/// changes to CFG, preserved. /// -/// This takes a potentially un-simplified loop L (and its children) and turns -/// it into a simplified loop nest with preheaders and single backedges. It will -/// update \c AliasAnalysis and \c ScalarEvolution analyses if they're non-null. -bool simplifyLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, - AssumptionCache *AC, bool PreserveLCSSA); +/// Returns true if any modifications are made. +bool formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist, + DominatorTree &DT, LoopInfo &LI); /// \brief Put loop into LCSSA form. /// @@ -318,8 +348,7 @@ bool simplifyLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, /// If ScalarEvolution is passed in, it will be preserved. /// /// Returns true if any modifications are made to the loop. -bool formLCSSA(Loop &L, DominatorTree &DT, LoopInfo *LI, - ScalarEvolution *SE); +bool formLCSSA(Loop &L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution *SE); /// \brief Put a loop nest into LCSSA form. /// @@ -343,7 +372,7 @@ bool formLCSSARecursively(Loop &L, DominatorTree &DT, LoopInfo *LI, /// It returns changed status. bool sinkRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *, TargetLibraryInfo *, Loop *, AliasSetTracker *, - LICMSafetyInfo *); + LoopSafetyInfo *); /// \brief Walk the specified region of the CFG (defined by all blocks /// dominated by the specified block, and that are in the current loop) in depth @@ -354,7 +383,7 @@ bool sinkRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *, /// loop and loop safety information as arguments. It returns changed status. bool hoistRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *, TargetLibraryInfo *, Loop *, AliasSetTracker *, - LICMSafetyInfo *); + LoopSafetyInfo *); /// \brief Try to promote memory values to scalars by sinking stores out of /// the loop and moving loads to before the loop. We do this by looping over @@ -363,20 +392,45 @@ bool hoistRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *, /// insertion point vector, PredIteratorCache, LoopInfo, DominatorTree, Loop, /// AliasSet information for all instructions of the loop and loop safety /// information as arguments. It returns changed status. -bool promoteLoopAccessesToScalars(AliasSet &, SmallVectorImpl<BasicBlock*> &, - SmallVectorImpl<Instruction*> &, +bool promoteLoopAccessesToScalars(AliasSet &, SmallVectorImpl<BasicBlock *> &, + SmallVectorImpl<Instruction *> &, PredIteratorCache &, LoopInfo *, - DominatorTree *, Loop *, AliasSetTracker *, - LICMSafetyInfo *); + DominatorTree *, const TargetLibraryInfo *, + Loop *, AliasSetTracker *, LoopSafetyInfo *); /// \brief Computes safety information for a loop /// checks loop body & header for the possibility of may throw -/// exception, it takes LICMSafetyInfo and loop as argument. -/// Updates safety information in LICMSafetyInfo argument. -void computeLICMSafetyInfo(LICMSafetyInfo *, Loop *); +/// exception, it takes LoopSafetyInfo and loop as argument. +/// Updates safety information in LoopSafetyInfo argument. +void computeLoopSafetyInfo(LoopSafetyInfo *, Loop *); + +/// Returns true if the instruction in a loop is guaranteed to execute at least +/// once. +bool isGuaranteedToExecute(const Instruction &Inst, const DominatorTree *DT, + const Loop *CurLoop, + const LoopSafetyInfo *SafetyInfo); /// \brief Returns the instructions that use values defined in the loop. SmallVector<Instruction *, 8> findDefsUsedOutsideOfLoop(Loop *L); + +/// \brief Find string metadata for loop +/// +/// If it has a value (e.g. {"llvm.distribute", 1} return the value as an +/// operand or null otherwise. If the string metadata is not found return +/// Optional's not-a-value. +Optional<const MDOperand *> findStringMetadataForLoop(Loop *TheLoop, + StringRef Name); + +/// \brief Set input string into loop metadata by keeping other values intact. +void addStringMetadataToLoop(Loop *TheLoop, const char *MDString, + unsigned V = 0); + +/// Helper to consistently add the set of standard passes to a loop pass's \c +/// AnalysisUsage. +/// +/// All loop passes should call this as part of implementing their \c +/// getAnalysisUsage. +void getLoopAnalysisUsage(AnalysisUsage &AU); } #endif diff --git a/include/llvm/Transforms/Utils/LoopVersioning.h b/include/llvm/Transforms/Utils/LoopVersioning.h index 3b70594e0b63..0d345a972e10 100644 --- a/include/llvm/Transforms/Utils/LoopVersioning.h +++ b/include/llvm/Transforms/Utils/LoopVersioning.h @@ -73,11 +73,30 @@ public: /// \brief Sets the runtime alias checks for versioning the loop. void setAliasChecks( - const SmallVector<RuntimePointerChecking::PointerCheck, 4> Checks); + SmallVector<RuntimePointerChecking::PointerCheck, 4> Checks); /// \brief Sets the runtime SCEV checks for versioning the loop. void setSCEVChecks(SCEVUnionPredicate Check); + /// \brief Annotate memory instructions in the versioned loop with no-alias + /// metadata based on the memchecks issued. + /// + /// This is just wrapper that calls prepareNoAliasMetadata and + /// annotateInstWithNoAlias on the instructions of the versioned loop. + void annotateLoopWithNoAlias(); + + /// \brief Set up the aliasing scopes based on the memchecks. This needs to + /// be called before the first call to annotateInstWithNoAlias. + void prepareNoAliasMetadata(); + + /// \brief Add the noalias annotations to \p VersionedInst. + /// + /// \p OrigInst is the instruction corresponding to \p VersionedInst in the + /// original loop. Initialize the aliasing scopes with + /// prepareNoAliasMetadata once before this can be called. + void annotateInstWithNoAlias(Instruction *VersionedInst, + const Instruction *OrigInst); + private: /// \brief Adds the necessary PHI nodes for the versioned loops based on the /// loop-defined values used outside of the loop. @@ -86,6 +105,12 @@ private: /// that are used outside the loop. void addPHINodes(const SmallVectorImpl<Instruction *> &DefsUsedOutside); + /// \brief Add the noalias annotations to \p I. Initialize the aliasing + /// scopes with prepareNoAliasMetadata once before this can be called. + void annotateInstWithNoAlias(Instruction *I) { + annotateInstWithNoAlias(I, I); + } + /// \brief The original loop. This becomes the "versioned" one. I.e., /// control flows here if pointers in the loop don't alias. Loop *VersionedLoop; @@ -103,6 +128,19 @@ private: /// \brief The set of SCEV checks that we are versioning for. SCEVUnionPredicate Preds; + /// \brief Maps a pointer to the pointer checking group that the pointer + /// belongs to. + DenseMap<const Value *, const RuntimePointerChecking::CheckingPtrGroup *> + PtrToGroup; + + /// \brief The alias scope corresponding to a pointer checking group. + DenseMap<const RuntimePointerChecking::CheckingPtrGroup *, MDNode *> + GroupToScope; + + /// \brief The list of alias scopes that a pointer checking group can't alias. + DenseMap<const RuntimePointerChecking::CheckingPtrGroup *, MDNode *> + GroupToNonAliasingScopeList; + /// \brief Analyses used. const LoopAccessInfo &LAI; LoopInfo *LI; diff --git a/include/llvm/Transforms/Utils/Mem2Reg.h b/include/llvm/Transforms/Utils/Mem2Reg.h new file mode 100644 index 000000000000..f3c80edf544d --- /dev/null +++ b/include/llvm/Transforms/Utils/Mem2Reg.h @@ -0,0 +1,28 @@ +//===- Mem2Reg.h - The -mem2reg pass, a wrapper around the Utils lib ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass is a simple pass wrapper around the PromoteMemToReg function call +// exposed by the Utils library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_MEM2REG_H +#define LLVM_TRANSFORMS_UTILS_MEM2REG_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class PromotePass : public PassInfoMixin<PromotePass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} + +#endif // LLVM_TRANSFORMS_UTILS_MEM2REG_H
\ No newline at end of file diff --git a/include/llvm/Transforms/Utils/MemorySSA.h b/include/llvm/Transforms/Utils/MemorySSA.h new file mode 100644 index 000000000000..befc34cb80fc --- /dev/null +++ b/include/llvm/Transforms/Utils/MemorySSA.h @@ -0,0 +1,949 @@ +//===- MemorySSA.h - Build Memory SSA ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// \file +// \brief This file exposes an interface to building/using memory SSA to +// walk memory instructions using a use/def graph. +// +// Memory SSA class builds an SSA form that links together memory access +// instructions such as loads, stores, atomics, and calls. Additionally, it does +// a trivial form of "heap versioning" Every time the memory state changes in +// the program, we generate a new heap version. It generates MemoryDef/Uses/Phis +// that are overlayed on top of the existing instructions. +// +// As a trivial example, +// define i32 @main() #0 { +// entry: +// %call = call noalias i8* @_Znwm(i64 4) #2 +// %0 = bitcast i8* %call to i32* +// %call1 = call noalias i8* @_Znwm(i64 4) #2 +// %1 = bitcast i8* %call1 to i32* +// store i32 5, i32* %0, align 4 +// store i32 7, i32* %1, align 4 +// %2 = load i32* %0, align 4 +// %3 = load i32* %1, align 4 +// %add = add nsw i32 %2, %3 +// ret i32 %add +// } +// +// Will become +// define i32 @main() #0 { +// entry: +// ; 1 = MemoryDef(0) +// %call = call noalias i8* @_Znwm(i64 4) #3 +// %2 = bitcast i8* %call to i32* +// ; 2 = MemoryDef(1) +// %call1 = call noalias i8* @_Znwm(i64 4) #3 +// %4 = bitcast i8* %call1 to i32* +// ; 3 = MemoryDef(2) +// store i32 5, i32* %2, align 4 +// ; 4 = MemoryDef(3) +// store i32 7, i32* %4, align 4 +// ; MemoryUse(3) +// %7 = load i32* %2, align 4 +// ; MemoryUse(4) +// %8 = load i32* %4, align 4 +// %add = add nsw i32 %7, %8 +// ret i32 %add +// } +// +// Given this form, all the stores that could ever effect the load at %8 can be +// gotten by using the MemoryUse associated with it, and walking from use to def +// until you hit the top of the function. +// +// Each def also has a list of users associated with it, so you can walk from +// both def to users, and users to defs. Note that we disambiguate MemoryUses, +// but not the RHS of MemoryDefs. You can see this above at %7, which would +// otherwise be a MemoryUse(4). Being disambiguated means that for a given +// store, all the MemoryUses on its use lists are may-aliases of that store (but +// the MemoryDefs on its use list may not be). +// +// MemoryDefs are not disambiguated because it would require multiple reaching +// definitions, which would require multiple phis, and multiple memoryaccesses +// per instruction. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_MEMORYSSA_H +#define LLVM_TRANSFORMS_UTILS_MEMORYSSA_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/PHITransAddr.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Use.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/PassAnalysisSupport.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <memory> +#include <utility> + +namespace llvm { + +class DominatorTree; +class Function; +class Instruction; +class MemoryAccess; +class LLVMContext; +class raw_ostream; + +template <class T> class memoryaccess_def_iterator_base; +using memoryaccess_def_iterator = memoryaccess_def_iterator_base<MemoryAccess>; +using const_memoryaccess_def_iterator = + memoryaccess_def_iterator_base<const MemoryAccess>; + +// \brief The base for all memory accesses. All memory accesses in a block are +// linked together using an intrusive list. +class MemoryAccess : public User, public ilist_node<MemoryAccess> { + void *operator new(size_t, unsigned) = delete; + void *operator new(size_t) = delete; + +public: + // Methods for support type inquiry through isa, cast, and + // dyn_cast + static inline bool classof(const MemoryAccess *) { return true; } + static inline bool classof(const Value *V) { + unsigned ID = V->getValueID(); + return ID == MemoryUseVal || ID == MemoryPhiVal || ID == MemoryDefVal; + } + + ~MemoryAccess() override; + + BasicBlock *getBlock() const { return Block; } + + virtual void print(raw_ostream &OS) const = 0; + virtual void dump() const; + + /// \brief The user iterators for a memory access + typedef user_iterator iterator; + typedef const_user_iterator const_iterator; + + /// \brief This iterator walks over all of the defs in a given + /// MemoryAccess. For MemoryPhi nodes, this walks arguments. For + /// MemoryUse/MemoryDef, this walks the defining access. + memoryaccess_def_iterator defs_begin(); + const_memoryaccess_def_iterator defs_begin() const; + memoryaccess_def_iterator defs_end(); + const_memoryaccess_def_iterator defs_end() const; + +protected: + friend class MemorySSA; + friend class MemoryUseOrDef; + friend class MemoryUse; + friend class MemoryDef; + friend class MemoryPhi; + + /// \brief Used internally to give IDs to MemoryAccesses for printing + virtual unsigned getID() const = 0; + + MemoryAccess(LLVMContext &C, unsigned Vty, BasicBlock *BB, + unsigned NumOperands) + : User(Type::getVoidTy(C), Vty, nullptr, NumOperands), Block(BB) {} + +private: + MemoryAccess(const MemoryAccess &); + void operator=(const MemoryAccess &); + BasicBlock *Block; +}; + +template <> +struct ilist_traits<MemoryAccess> : public ilist_default_traits<MemoryAccess> { + /// See details of the instruction class for why this trick works + // FIXME: This downcast is UB. See llvm.org/PR26753. + LLVM_NO_SANITIZE("object-size") + MemoryAccess *createSentinel() const { + return static_cast<MemoryAccess *>(&Sentinel); + } + + static void destroySentinel(MemoryAccess *) {} + + MemoryAccess *provideInitialHead() const { return createSentinel(); } + MemoryAccess *ensureHead(MemoryAccess *) const { return createSentinel(); } + static void noteHead(MemoryAccess *, MemoryAccess *) {} + +private: + mutable ilist_half_node<MemoryAccess> Sentinel; +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const MemoryAccess &MA) { + MA.print(OS); + return OS; +} + +/// \brief Class that has the common methods + fields of memory uses/defs. It's +/// a little awkward to have, but there are many cases where we want either a +/// use or def, and there are many cases where uses are needed (defs aren't +/// acceptable), and vice-versa. +/// +/// This class should never be instantiated directly; make a MemoryUse or +/// MemoryDef instead. +class MemoryUseOrDef : public MemoryAccess { + void *operator new(size_t, unsigned) = delete; + void *operator new(size_t) = delete; + +public: + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess); + + /// \brief Get the instruction that this MemoryUse represents. + Instruction *getMemoryInst() const { return MemoryInst; } + + /// \brief Get the access that produces the memory state used by this Use. + MemoryAccess *getDefiningAccess() const { return getOperand(0); } + + static inline bool classof(const MemoryUseOrDef *) { return true; } + static inline bool classof(const Value *MA) { + return MA->getValueID() == MemoryUseVal || MA->getValueID() == MemoryDefVal; + } + +protected: + friend class MemorySSA; + + MemoryUseOrDef(LLVMContext &C, MemoryAccess *DMA, unsigned Vty, + Instruction *MI, BasicBlock *BB) + : MemoryAccess(C, Vty, BB, 1), MemoryInst(MI) { + setDefiningAccess(DMA); + } + + void setDefiningAccess(MemoryAccess *DMA) { setOperand(0, DMA); } + +private: + Instruction *MemoryInst; +}; + +template <> +struct OperandTraits<MemoryUseOrDef> + : public FixedNumOperandTraits<MemoryUseOrDef, 1> {}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUseOrDef, MemoryAccess) + +/// \brief Represents read-only accesses to memory +/// +/// In particular, the set of Instructions that will be represented by +/// MemoryUse's is exactly the set of Instructions for which +/// AliasAnalysis::getModRefInfo returns "Ref". +class MemoryUse final : public MemoryUseOrDef { + void *operator new(size_t, unsigned) = delete; + +public: + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess); + + // allocate space for exactly one operand + void *operator new(size_t s) { return User::operator new(s, 1); } + + MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB) + : MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB) {} + + static inline bool classof(const MemoryUse *) { return true; } + static inline bool classof(const Value *MA) { + return MA->getValueID() == MemoryUseVal; + } + + void print(raw_ostream &OS) const override; + +protected: + friend class MemorySSA; + + unsigned getID() const override { + llvm_unreachable("MemoryUses do not have IDs"); + } +}; + +template <> +struct OperandTraits<MemoryUse> : public FixedNumOperandTraits<MemoryUse, 1> {}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUse, MemoryAccess) + +/// \brief Represents a read-write access to memory, whether it is a must-alias, +/// or a may-alias. +/// +/// In particular, the set of Instructions that will be represented by +/// MemoryDef's is exactly the set of Instructions for which +/// AliasAnalysis::getModRefInfo returns "Mod" or "ModRef". +/// Note that, in order to provide def-def chains, all defs also have a use +/// associated with them. This use points to the nearest reaching +/// MemoryDef/MemoryPhi. +class MemoryDef final : public MemoryUseOrDef { + void *operator new(size_t, unsigned) = delete; + +public: + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess); + + // allocate space for exactly one operand + void *operator new(size_t s) { return User::operator new(s, 1); } + + MemoryDef(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB, + unsigned Ver) + : MemoryUseOrDef(C, DMA, MemoryDefVal, MI, BB), ID(Ver) {} + + static inline bool classof(const MemoryDef *) { return true; } + static inline bool classof(const Value *MA) { + return MA->getValueID() == MemoryDefVal; + } + + void print(raw_ostream &OS) const override; + +protected: + friend class MemorySSA; + + // For debugging only. This gets used to give memory accesses pretty numbers + // when printing them out + unsigned getID() const override { return ID; } + +private: + const unsigned ID; +}; + +template <> +struct OperandTraits<MemoryDef> : public FixedNumOperandTraits<MemoryDef, 1> {}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryDef, MemoryAccess) + +/// \brief Represents phi nodes for memory accesses. +/// +/// These have the same semantic as regular phi nodes, with the exception that +/// only one phi will ever exist in a given basic block. +/// Guaranteeing one phi per block means guaranteeing there is only ever one +/// valid reaching MemoryDef/MemoryPHI along each path to the phi node. +/// This is ensured by not allowing disambiguation of the RHS of a MemoryDef or +/// a MemoryPhi's operands. +/// That is, given +/// if (a) { +/// store %a +/// store %b +/// } +/// it *must* be transformed into +/// if (a) { +/// 1 = MemoryDef(liveOnEntry) +/// store %a +/// 2 = MemoryDef(1) +/// store %b +/// } +/// and *not* +/// if (a) { +/// 1 = MemoryDef(liveOnEntry) +/// store %a +/// 2 = MemoryDef(liveOnEntry) +/// store %b +/// } +/// even if the two stores do not conflict. Otherwise, both 1 and 2 reach the +/// end of the branch, and if there are not two phi nodes, one will be +/// disconnected completely from the SSA graph below that point. +/// Because MemoryUse's do not generate new definitions, they do not have this +/// issue. +class MemoryPhi final : public MemoryAccess { + void *operator new(size_t, unsigned) = delete; + // allocate space for exactly zero operands + void *operator new(size_t s) { return User::operator new(s); } + +public: + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess); + + MemoryPhi(LLVMContext &C, BasicBlock *BB, unsigned Ver, unsigned NumPreds = 0) + : MemoryAccess(C, MemoryPhiVal, BB, 0), ID(Ver), ReservedSpace(NumPreds) { + allocHungoffUses(ReservedSpace); + } + + // Block iterator interface. This provides access to the list of incoming + // basic blocks, which parallels the list of incoming values. + typedef BasicBlock **block_iterator; + typedef BasicBlock *const *const_block_iterator; + + block_iterator block_begin() { + auto *Ref = reinterpret_cast<Use::UserRef *>(op_begin() + ReservedSpace); + return reinterpret_cast<block_iterator>(Ref + 1); + } + + const_block_iterator block_begin() const { + const auto *Ref = + reinterpret_cast<const Use::UserRef *>(op_begin() + ReservedSpace); + return reinterpret_cast<const_block_iterator>(Ref + 1); + } + + block_iterator block_end() { return block_begin() + getNumOperands(); } + + const_block_iterator block_end() const { + return block_begin() + getNumOperands(); + } + + op_range incoming_values() { return operands(); } + + const_op_range incoming_values() const { return operands(); } + + /// \brief Return the number of incoming edges + unsigned getNumIncomingValues() const { return getNumOperands(); } + + /// \brief Return incoming value number x + MemoryAccess *getIncomingValue(unsigned I) const { return getOperand(I); } + void setIncomingValue(unsigned I, MemoryAccess *V) { + assert(V && "PHI node got a null value!"); + setOperand(I, V); + } + static unsigned getOperandNumForIncomingValue(unsigned I) { return I; } + static unsigned getIncomingValueNumForOperand(unsigned I) { return I; } + + /// \brief Return incoming basic block number @p i. + BasicBlock *getIncomingBlock(unsigned I) const { return block_begin()[I]; } + + /// \brief Return incoming basic block corresponding + /// to an operand of the PHI. + BasicBlock *getIncomingBlock(const Use &U) const { + assert(this == U.getUser() && "Iterator doesn't point to PHI's Uses?"); + return getIncomingBlock(unsigned(&U - op_begin())); + } + + /// \brief Return incoming basic block corresponding + /// to value use iterator. + BasicBlock *getIncomingBlock(MemoryAccess::const_user_iterator I) const { + return getIncomingBlock(I.getUse()); + } + + void setIncomingBlock(unsigned I, BasicBlock *BB) { + assert(BB && "PHI node got a null basic block!"); + block_begin()[I] = BB; + } + + /// \brief Add an incoming value to the end of the PHI list + void addIncoming(MemoryAccess *V, BasicBlock *BB) { + if (getNumOperands() == ReservedSpace) + growOperands(); // Get more space! + // Initialize some new operands. + setNumHungOffUseOperands(getNumOperands() + 1); + setIncomingValue(getNumOperands() - 1, V); + setIncomingBlock(getNumOperands() - 1, BB); + } + + /// \brief Return the first index of the specified basic + /// block in the value list for this PHI. Returns -1 if no instance. + int getBasicBlockIndex(const BasicBlock *BB) const { + for (unsigned I = 0, E = getNumOperands(); I != E; ++I) + if (block_begin()[I] == BB) + return I; + return -1; + } + + Value *getIncomingValueForBlock(const BasicBlock *BB) const { + int Idx = getBasicBlockIndex(BB); + assert(Idx >= 0 && "Invalid basic block argument!"); + return getIncomingValue(Idx); + } + + static inline bool classof(const MemoryPhi *) { return true; } + static inline bool classof(const Value *V) { + return V->getValueID() == MemoryPhiVal; + } + + void print(raw_ostream &OS) const override; + +protected: + friend class MemorySSA; + /// \brief this is more complicated than the generic + /// User::allocHungoffUses, because we have to allocate Uses for the incoming + /// values and pointers to the incoming blocks, all in one allocation. + void allocHungoffUses(unsigned N) { + User::allocHungoffUses(N, /* IsPhi */ true); + } + + /// For debugging only. This gets used to give memory accesses pretty numbers + /// when printing them out + unsigned getID() const final { return ID; } + +private: + // For debugging only + const unsigned ID; + unsigned ReservedSpace; + + /// \brief This grows the operand list in response to a push_back style of + /// operation. This grows the number of ops by 1.5 times. + void growOperands() { + unsigned E = getNumOperands(); + // 2 op PHI nodes are VERY common, so reserve at least enough for that. + ReservedSpace = std::max(E + E / 2, 2u); + growHungoffUses(ReservedSpace, /* IsPhi */ true); + } +}; + +template <> struct OperandTraits<MemoryPhi> : public HungoffOperandTraits<2> {}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryPhi, MemoryAccess) + +class MemorySSAWalker; + +/// \brief Encapsulates MemorySSA, including all data associated with memory +/// accesses. +class MemorySSA { +public: + MemorySSA(Function &, AliasAnalysis *, DominatorTree *); + MemorySSA(MemorySSA &&); + ~MemorySSA(); + + MemorySSAWalker *getWalker(); + + /// \brief Given a memory Mod/Ref'ing instruction, get the MemorySSA + /// access associated with it. If passed a basic block gets the memory phi + /// node that exists for that block, if there is one. Otherwise, this will get + /// a MemoryUseOrDef. + MemoryAccess *getMemoryAccess(const Value *) const; + MemoryPhi *getMemoryAccess(const BasicBlock *BB) const; + + void dump() const; + void print(raw_ostream &) const; + + /// \brief Return true if \p MA represents the live on entry value + /// + /// Loads and stores from pointer arguments and other global values may be + /// defined by memory operations that do not occur in the current function, so + /// they may be live on entry to the function. MemorySSA represents such + /// memory state by the live on entry definition, which is guaranteed to occur + /// before any other memory access in the function. + inline bool isLiveOnEntryDef(const MemoryAccess *MA) const { + return MA == LiveOnEntryDef.get(); + } + + inline MemoryAccess *getLiveOnEntryDef() const { + return LiveOnEntryDef.get(); + } + + using AccessList = iplist<MemoryAccess>; + + /// \brief Return the list of MemoryAccess's for a given basic block. + /// + /// This list is not modifiable by the user. + const AccessList *getBlockAccesses(const BasicBlock *BB) const { + auto It = PerBlockAccesses.find(BB); + return It == PerBlockAccesses.end() ? nullptr : It->second.get(); + } + + /// \brief Create an empty MemoryPhi in MemorySSA + MemoryPhi *createMemoryPhi(BasicBlock *BB); + + enum InsertionPlace { Beginning, End }; + + /// \brief Create a MemoryAccess in MemorySSA at a specified point in a block, + /// with a specified clobbering definition. + /// + /// Returns the new MemoryAccess. + /// This should be called when a memory instruction is created that is being + /// used to replace an existing memory instruction. It will *not* create PHI + /// nodes, or verify the clobbering definition. The insertion place is used + /// solely to determine where in the memoryssa access lists the instruction + /// will be placed. The caller is expected to keep ordering the same as + /// instructions. + /// It will return the new MemoryAccess. + MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition, + const BasicBlock *BB, + InsertionPlace Point); + /// \brief Create a MemoryAccess in MemorySSA before or after an existing + /// MemoryAccess. + /// + /// Returns the new MemoryAccess. + /// This should be called when a memory instruction is created that is being + /// used to replace an existing memory instruction. It will *not* create PHI + /// nodes, or verify the clobbering definition. The clobbering definition + /// must be non-null. + MemoryAccess *createMemoryAccessBefore(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt); + MemoryAccess *createMemoryAccessAfter(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt); + + /// \brief Remove a MemoryAccess from MemorySSA, including updating all + /// definitions and uses. + /// This should be called when a memory instruction that has a MemoryAccess + /// associated with it is erased from the program. For example, if a store or + /// load is simply erased (not replaced), removeMemoryAccess should be called + /// on the MemoryAccess for that store/load. + void removeMemoryAccess(MemoryAccess *); + + /// \brief Given two memory accesses in the same basic block, determine + /// whether MemoryAccess \p A dominates MemoryAccess \p B. + bool locallyDominates(const MemoryAccess *A, const MemoryAccess *B) const; + + /// \brief Verify that MemorySSA is self consistent (IE definitions dominate + /// all uses, uses appear in the right places). This is used by unit tests. + void verifyMemorySSA() const; + +protected: + // Used by Memory SSA annotater, dumpers, and wrapper pass + friend class MemorySSAAnnotatedWriter; + friend class MemorySSAPrinterLegacyPass; + void verifyDefUses(Function &F) const; + void verifyDomination(Function &F) const; + void verifyOrdering(Function &F) const; + +private: + class CachingWalker; + void buildMemorySSA(); + void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const; + using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>; + + void + determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks); + void computeDomLevels(DenseMap<DomTreeNode *, unsigned> &DomLevels); + void markUnreachableAsLiveOnEntry(BasicBlock *BB); + bool dominatesUse(const MemoryAccess *, const MemoryAccess *) const; + MemoryUseOrDef *createNewAccess(Instruction *); + MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *); + MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace); + void removeFromLookups(MemoryAccess *); + + MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *); + void renamePass(DomTreeNode *, MemoryAccess *IncomingVal, + SmallPtrSet<BasicBlock *, 16> &Visited); + AccessList *getOrCreateAccessList(const BasicBlock *); + AliasAnalysis *AA; + DominatorTree *DT; + Function &F; + + // Memory SSA mappings + DenseMap<const Value *, MemoryAccess *> ValueToMemoryAccess; + AccessMap PerBlockAccesses; + std::unique_ptr<MemoryAccess> LiveOnEntryDef; + + // Memory SSA building info + std::unique_ptr<CachingWalker> Walker; + unsigned NextID; +}; + +// This pass does eager building and then printing of MemorySSA. It is used by +// the tests to be able to build, dump, and verify Memory SSA. +class MemorySSAPrinterLegacyPass : public FunctionPass { +public: + MemorySSAPrinterLegacyPass(); + + static char ID; + bool runOnFunction(Function &) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +/// An analysis that produces \c MemorySSA for a function. +/// +class MemorySSAAnalysis : public AnalysisInfoMixin<MemorySSAAnalysis> { + friend AnalysisInfoMixin<MemorySSAAnalysis>; + static char PassID; + +public: + typedef MemorySSA Result; + + MemorySSA run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Printer pass for \c MemorySSA. +class MemorySSAPrinterPass : public PassInfoMixin<MemorySSAPrinterPass> { + raw_ostream &OS; + +public: + explicit MemorySSAPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Verifier pass for \c MemorySSA. +struct MemorySSAVerifierPass : PassInfoMixin<MemorySSAVerifierPass> { + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; + +/// \brief Legacy analysis pass which computes \c MemorySSA. +class MemorySSAWrapperPass : public FunctionPass { +public: + MemorySSAWrapperPass(); + + static char ID; + bool runOnFunction(Function &) override; + void releaseMemory() override; + MemorySSA &getMSSA() { return *MSSA; } + const MemorySSA &getMSSA() const { return *MSSA; } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + void verifyAnalysis() const override; + void print(raw_ostream &OS, const Module *M = nullptr) const override; + +private: + std::unique_ptr<MemorySSA> MSSA; +}; + +/// \brief This is the generic walker interface for walkers of MemorySSA. +/// Walkers are used to be able to further disambiguate the def-use chains +/// MemorySSA gives you, or otherwise produce better info than MemorySSA gives +/// you. +/// In particular, while the def-use chains provide basic information, and are +/// guaranteed to give, for example, the nearest may-aliasing MemoryDef for a +/// MemoryUse as AliasAnalysis considers it, a user mant want better or other +/// information. In particular, they may want to use SCEV info to further +/// disambiguate memory accesses, or they may want the nearest dominating +/// may-aliasing MemoryDef for a call or a store. This API enables a +/// standardized interface to getting and using that info. +class MemorySSAWalker { +public: + MemorySSAWalker(MemorySSA *); + virtual ~MemorySSAWalker() {} + + using MemoryAccessSet = SmallVector<MemoryAccess *, 8>; + + /// \brief Given a memory Mod/Ref/ModRef'ing instruction, calling this + /// will give you the nearest dominating MemoryAccess that Mod's the location + /// the instruction accesses (by skipping any def which AA can prove does not + /// alias the location(s) accessed by the instruction given). + /// + /// Note that this will return a single access, and it must dominate the + /// Instruction, so if an operand of a MemoryPhi node Mod's the instruction, + /// this will return the MemoryPhi, not the operand. This means that + /// given: + /// if (a) { + /// 1 = MemoryDef(liveOnEntry) + /// store %a + /// } else { + /// 2 = MemoryDef(liveOnEntry) + /// store %b + /// } + /// 3 = MemoryPhi(2, 1) + /// MemoryUse(3) + /// load %a + /// + /// calling this API on load(%a) will return the MemoryPhi, not the MemoryDef + /// in the if (a) branch. + virtual MemoryAccess *getClobberingMemoryAccess(const Instruction *) = 0; + + /// \brief Given a potentially clobbering memory access and a new location, + /// calling this will give you the nearest dominating clobbering MemoryAccess + /// (by skipping non-aliasing def links). + /// + /// This version of the function is mainly used to disambiguate phi translated + /// pointers, where the value of a pointer may have changed from the initial + /// memory access. Note that this expects to be handed either a MemoryUse, + /// or an already potentially clobbering access. Unlike the above API, if + /// given a MemoryDef that clobbers the pointer as the starting access, it + /// will return that MemoryDef, whereas the above would return the clobber + /// starting from the use side of the memory def. + virtual MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, + MemoryLocation &) = 0; + + /// \brief Given a memory access, invalidate anything this walker knows about + /// that access. + /// This API is used by walkers that store information to perform basic cache + /// invalidation. This will be called by MemorySSA at appropriate times for + /// the walker it uses or returns. + virtual void invalidateInfo(MemoryAccess *) {} + +protected: + friend class MemorySSA; // For updating MSSA pointer in MemorySSA move + // constructor. + MemorySSA *MSSA; +}; + +/// \brief A MemorySSAWalker that does no alias queries, or anything else. It +/// simply returns the links as they were constructed by the builder. +class DoNothingMemorySSAWalker final : public MemorySSAWalker { +public: + MemoryAccess *getClobberingMemoryAccess(const Instruction *) override; + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, + MemoryLocation &) override; +}; + +using MemoryAccessPair = std::pair<MemoryAccess *, MemoryLocation>; +using ConstMemoryAccessPair = std::pair<const MemoryAccess *, MemoryLocation>; + +/// \brief Iterator base class used to implement const and non-const iterators +/// over the defining accesses of a MemoryAccess. +template <class T> +class memoryaccess_def_iterator_base + : public iterator_facade_base<memoryaccess_def_iterator_base<T>, + std::forward_iterator_tag, T, ptrdiff_t, T *, + T *> { + using BaseT = typename memoryaccess_def_iterator_base::iterator_facade_base; + +public: + memoryaccess_def_iterator_base(T *Start) : Access(Start), ArgNo(0) {} + memoryaccess_def_iterator_base() : Access(nullptr), ArgNo(0) {} + bool operator==(const memoryaccess_def_iterator_base &Other) const { + return Access == Other.Access && (!Access || ArgNo == Other.ArgNo); + } + + // This is a bit ugly, but for MemoryPHI's, unlike PHINodes, you can't get the + // block from the operand in constant time (In a PHINode, the uselist has + // both, so it's just subtraction). We provide it as part of the + // iterator to avoid callers having to linear walk to get the block. + // If the operation becomes constant time on MemoryPHI's, this bit of + // abstraction breaking should be removed. + BasicBlock *getPhiArgBlock() const { + MemoryPhi *MP = dyn_cast<MemoryPhi>(Access); + assert(MP && "Tried to get phi arg block when not iterating over a PHI"); + return MP->getIncomingBlock(ArgNo); + } + typename BaseT::iterator::pointer operator*() const { + assert(Access && "Tried to access past the end of our iterator"); + // Go to the first argument for phis, and the defining access for everything + // else. + if (MemoryPhi *MP = dyn_cast<MemoryPhi>(Access)) + return MP->getIncomingValue(ArgNo); + return cast<MemoryUseOrDef>(Access)->getDefiningAccess(); + } + using BaseT::operator++; + memoryaccess_def_iterator &operator++() { + assert(Access && "Hit end of iterator"); + if (MemoryPhi *MP = dyn_cast<MemoryPhi>(Access)) { + if (++ArgNo >= MP->getNumIncomingValues()) { + ArgNo = 0; + Access = nullptr; + } + } else { + Access = nullptr; + } + return *this; + } + +private: + T *Access; + unsigned ArgNo; +}; + +inline memoryaccess_def_iterator MemoryAccess::defs_begin() { + return memoryaccess_def_iterator(this); +} + +inline const_memoryaccess_def_iterator MemoryAccess::defs_begin() const { + return const_memoryaccess_def_iterator(this); +} + +inline memoryaccess_def_iterator MemoryAccess::defs_end() { + return memoryaccess_def_iterator(); +} + +inline const_memoryaccess_def_iterator MemoryAccess::defs_end() const { + return const_memoryaccess_def_iterator(); +} + +/// \brief GraphTraits for a MemoryAccess, which walks defs in the normal case, +/// and uses in the inverse case. +template <> struct GraphTraits<MemoryAccess *> { + using NodeType = MemoryAccess; + using ChildIteratorType = memoryaccess_def_iterator; + + static NodeType *getEntryNode(NodeType *N) { return N; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->defs_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->defs_end(); + } +}; + +template <> struct GraphTraits<Inverse<MemoryAccess *>> { + using NodeType = MemoryAccess; + using ChildIteratorType = MemoryAccess::iterator; + + static NodeType *getEntryNode(NodeType *N) { return N; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->user_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->user_end(); + } +}; + +/// \brief Provide an iterator that walks defs, giving both the memory access, +/// and the current pointer location, updating the pointer location as it +/// changes due to phi node translation. +/// +/// This iterator, while somewhat specialized, is what most clients actually +/// want when walking upwards through MemorySSA def chains. It takes a pair of +/// <MemoryAccess,MemoryLocation>, and walks defs, properly translating the +/// memory location through phi nodes for the user. +class upward_defs_iterator + : public iterator_facade_base<upward_defs_iterator, + std::forward_iterator_tag, + const MemoryAccessPair> { + using BaseT = upward_defs_iterator::iterator_facade_base; + +public: + upward_defs_iterator(const MemoryAccessPair &Info) + : DefIterator(Info.first), Location(Info.second), + OriginalAccess(Info.first) { + CurrentPair.first = nullptr; + + WalkingPhi = Info.first && isa<MemoryPhi>(Info.first); + fillInCurrentPair(); + } + + upward_defs_iterator() + : DefIterator(), Location(), OriginalAccess(), WalkingPhi(false) { + CurrentPair.first = nullptr; + } + + bool operator==(const upward_defs_iterator &Other) const { + return DefIterator == Other.DefIterator; + } + + BaseT::iterator::reference operator*() const { + assert(DefIterator != OriginalAccess->defs_end() && + "Tried to access past the end of our iterator"); + return CurrentPair; + } + + using BaseT::operator++; + upward_defs_iterator &operator++() { + assert(DefIterator != OriginalAccess->defs_end() && + "Tried to access past the end of the iterator"); + ++DefIterator; + if (DefIterator != OriginalAccess->defs_end()) + fillInCurrentPair(); + return *this; + } + + BasicBlock *getPhiArgBlock() const { return DefIterator.getPhiArgBlock(); } + +private: + void fillInCurrentPair() { + CurrentPair.first = *DefIterator; + if (WalkingPhi && Location.Ptr) { + PHITransAddr Translator( + const_cast<Value *>(Location.Ptr), + OriginalAccess->getBlock()->getModule()->getDataLayout(), nullptr); + if (!Translator.PHITranslateValue(OriginalAccess->getBlock(), + DefIterator.getPhiArgBlock(), nullptr, + false)) + if (Translator.getAddr() != Location.Ptr) { + CurrentPair.second = Location.getWithNewPtr(Translator.getAddr()); + return; + } + } + CurrentPair.second = Location; + } + + MemoryAccessPair CurrentPair; + memoryaccess_def_iterator DefIterator; + MemoryLocation Location; + MemoryAccess *OriginalAccess; + bool WalkingPhi; +}; + +inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) { + return upward_defs_iterator(Pair); +} + +inline upward_defs_iterator upward_defs_end() { return upward_defs_iterator(); } + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_MEMORYSSA_H diff --git a/include/llvm/Transforms/Utils/ModuleUtils.h b/include/llvm/Transforms/Utils/ModuleUtils.h index 0f23d34de5db..2eb2b1363b0b 100644 --- a/include/llvm/Transforms/Utils/ModuleUtils.h +++ b/include/llvm/Transforms/Utils/ModuleUtils.h @@ -14,12 +14,12 @@ #ifndef LLVM_TRANSFORMS_UTILS_MODULEUTILS_H #define LLVM_TRANSFORMS_UTILS_MODULEUTILS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include <utility> // for std::pair namespace llvm { +template <typename T> class ArrayRef; class Module; class Function; class GlobalValue; @@ -28,22 +28,17 @@ class Constant; class StringRef; class Value; class Type; -template <class PtrType> class SmallPtrSetImpl; /// Append F to the list of global ctors of module M with the given Priority. /// This wraps the function in the appropriate structure and stores it along /// side other global constructors. For details see /// http://llvm.org/docs/LangRef.html#intg_global_ctors -void appendToGlobalCtors(Module &M, Function *F, int Priority); +void appendToGlobalCtors(Module &M, Function *F, int Priority, + Constant *Data = nullptr); /// Same as appendToGlobalCtors(), but for global dtors. -void appendToGlobalDtors(Module &M, Function *F, int Priority); - -/// \brief Given "llvm.used" or "llvm.compiler.used" as a global name, collect -/// the initializer elements of that global in Set and return the global itself. -GlobalVariable *collectUsedGlobalVariables(Module &M, - SmallPtrSetImpl<GlobalValue *> &Set, - bool CompilerUsed); +void appendToGlobalDtors(Module &M, Function *F, int Priority, + Constant *Data = nullptr); // Validate the result of Module::getOrInsertFunction called for an interface // function of given sanitizer. If the instrumented module defines a function @@ -59,6 +54,11 @@ std::pair<Function *, Function *> createSanitizerCtorAndInitFunctions( Module &M, StringRef CtorName, StringRef InitName, ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs, StringRef VersionCheckName = StringRef()); + +/// Rename all the anon functions in the module using a hash computed from +/// the list of public globals in the module. +bool nameUnamedFunctions(Module &M); + } // End llvm namespace #endif // LLVM_TRANSFORMS_UTILS_MODULEUTILS_H diff --git a/include/llvm/Transforms/Utils/PromoteMemToReg.h b/include/llvm/Transforms/Utils/PromoteMemToReg.h index d0602bf47c92..b548072c413e 100644 --- a/include/llvm/Transforms/Utils/PromoteMemToReg.h +++ b/include/llvm/Transforms/Utils/PromoteMemToReg.h @@ -15,10 +15,9 @@ #ifndef LLVM_TRANSFORMS_UTILS_PROMOTEMEMTOREG_H #define LLVM_TRANSFORMS_UTILS_PROMOTEMEMTOREG_H -#include "llvm/ADT/ArrayRef.h" - namespace llvm { +template <typename T> class ArrayRef; class AllocaInst; class DominatorTree; class AliasSetTracker; diff --git a/include/llvm/Transforms/Utils/SSAUpdater.h b/include/llvm/Transforms/Utils/SSAUpdater.h index 1c7b2c587a36..9f98bac22dc9 100644 --- a/include/llvm/Transforms/Utils/SSAUpdater.h +++ b/include/llvm/Transforms/Utils/SSAUpdater.h @@ -14,7 +14,6 @@ #ifndef LLVM_TRANSFORMS_UTILS_SSAUPDATER_H #define LLVM_TRANSFORMS_UTILS_SSAUPDATER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" @@ -22,8 +21,9 @@ namespace llvm { class BasicBlock; class Instruction; class LoadInst; - template<typename T> class SmallVectorImpl; - template<typename T> class SSAUpdaterTraits; + template <typename T> class ArrayRef; + template <typename T> class SmallVectorImpl; + template <typename T> class SSAUpdaterTraits; class PHINode; class Type; class Use; diff --git a/include/llvm/Transforms/Utils/SSAUpdaterImpl.h b/include/llvm/Transforms/Utils/SSAUpdaterImpl.h index 425ecd3cfb5e..b5f4ac82b605 100644 --- a/include/llvm/Transforms/Utils/SSAUpdaterImpl.h +++ b/include/llvm/Transforms/Utils/SSAUpdaterImpl.h @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" diff --git a/include/llvm/Transforms/Utils/SanitizerStats.h b/include/llvm/Transforms/Utils/SanitizerStats.h new file mode 100644 index 000000000000..d36e34258a3f --- /dev/null +++ b/include/llvm/Transforms/Utils/SanitizerStats.h @@ -0,0 +1,56 @@ +//===- SanitizerStats.h - Sanitizer statistics gathering -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Declares functions and data structures for sanitizer statistics gathering. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H +#define LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H + +#include "llvm/IR/IRBuilder.h" + +namespace llvm { + +// Number of bits in data that are used for the sanitizer kind. Needs to match +// __sanitizer::kKindBits in compiler-rt/lib/stats/stats.h +enum { kSanitizerStatKindBits = 3 }; + +enum SanitizerStatKind { + SanStat_CFI_VCall, + SanStat_CFI_NVCall, + SanStat_CFI_DerivedCast, + SanStat_CFI_UnrelatedCast, + SanStat_CFI_ICall, +}; + +struct SanitizerStatReport { + SanitizerStatReport(Module *M); + + /// Generates code into B that increments a location-specific counter tagged + /// with the given sanitizer kind SK. + void create(IRBuilder<> &B, SanitizerStatKind SK); + + /// Finalize module stats array and add global constructor to register it. + void finish(); + +private: + Module *M; + GlobalVariable *ModuleStatsGV; + ArrayType *StatTy; + StructType *EmptyModuleStatsTy; + + std::vector<Constant *> Inits; + ArrayType *makeModuleStatsArrayTy(); + StructType *makeModuleStatsTy(); +}; + +} + +#endif diff --git a/include/llvm/Transforms/Utils/SimplifyIndVar.h b/include/llvm/Transforms/Utils/SimplifyIndVar.h index 3c55e64537c7..90438ee699fe 100644 --- a/include/llvm/Transforms/Utils/SimplifyIndVar.h +++ b/include/llvm/Transforms/Utils/SimplifyIndVar.h @@ -17,7 +17,6 @@ #define LLVM_TRANSFORMS_UTILS_SIMPLIFYINDVAR_H #include "llvm/IR/ValueHandle.h" -#include "llvm/Support/CommandLine.h" namespace llvm { @@ -34,24 +33,14 @@ class ScalarEvolution; class IVVisitor { protected: const DominatorTree *DT; - bool ShouldSplitOverflowIntrinsics; virtual void anchor(); public: - IVVisitor(): DT(nullptr), ShouldSplitOverflowIntrinsics(false) {} + IVVisitor() : DT(nullptr) {} virtual ~IVVisitor() {} const DominatorTree *getDomTree() const { return DT; } - - bool shouldSplitOverflowInstrinsics() const { - return ShouldSplitOverflowIntrinsics; - } - void setSplitOverflowIntrinsics() { - ShouldSplitOverflowIntrinsics = true; - assert(DT && "Splitting overflow intrinsics requires a DomTree."); - } - virtual void visitCast(CastInst *Cast) = 0; }; diff --git a/include/llvm/Transforms/Utils/SimplifyInstructions.h b/include/llvm/Transforms/Utils/SimplifyInstructions.h new file mode 100644 index 000000000000..ea491dc50587 --- /dev/null +++ b/include/llvm/Transforms/Utils/SimplifyInstructions.h @@ -0,0 +1,31 @@ +//===- SimplifyInstructions.h - Remove redundant instructions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a utility pass used for testing the InstructionSimplify analysis. +// The analysis is applied to every instruction, and if it simplifies then the +// instruction is replaced by the simplification. If you are looking for a pass +// that performs serious instruction folding, use the instcombine pass instead. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_SIMPLIFYINSTRUCTIONS_H +#define LLVM_TRANSFORMS_UTILS_SIMPLIFYINSTRUCTIONS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// This pass removes redundant instructions. +class InstSimplifierPass : public PassInfoMixin<InstSimplifierPass> { +public: + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_SIMPLIFYINSTRUCTIONS_H diff --git a/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/include/llvm/Transforms/Utils/SimplifyLibCalls.h index fc34f49a1255..92ee24633950 100644 --- a/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -16,11 +16,11 @@ #define LLVM_TRANSFORMS_UTILS_SIMPLIFYLIBCALLS_H #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/IRBuilder.h" namespace llvm { +class StringRef; class Value; class CallInst; class DataLayout; @@ -154,7 +154,7 @@ private: // Helper methods Value *emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, IRBuilder<> &B); - void classifyArgUse(Value *Val, BasicBlock *BB, bool IsFloat, + void classifyArgUse(Value *Val, Function *F, bool IsFloat, SmallVectorImpl<CallInst *> &SinCalls, SmallVectorImpl<CallInst *> &CosCalls, SmallVectorImpl<CallInst *> &SinCosCalls); diff --git a/include/llvm/Transforms/Utils/SplitModule.h b/include/llvm/Transforms/Utils/SplitModule.h index 7d896d1993d6..b7a3bcf4f86a 100644 --- a/include/llvm/Transforms/Utils/SplitModule.h +++ b/include/llvm/Transforms/Utils/SplitModule.h @@ -16,7 +16,7 @@ #ifndef LLVM_TRANSFORMS_UTILS_SPLITMODULE_H #define LLVM_TRANSFORMS_UTILS_SPLITMODULE_H -#include <functional> +#include "llvm/ADT/STLExtras.h" #include <memory> namespace llvm { @@ -36,7 +36,8 @@ class StringRef; /// each partition. void SplitModule( std::unique_ptr<Module> M, unsigned N, - std::function<void(std::unique_ptr<Module> MPart)> ModuleCallback); + function_ref<void(std::unique_ptr<Module> MPart)> ModuleCallback, + bool PreserveLocals = false); } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/UnrollLoop.h b/include/llvm/Transforms/Utils/UnrollLoop.h index 710817cddf6a..4d370407591d 100644 --- a/include/llvm/Transforms/Utils/UnrollLoop.h +++ b/include/llvm/Transforms/Utils/UnrollLoop.h @@ -16,10 +16,10 @@ #ifndef LLVM_TRANSFORMS_UTILS_UNROLLLOOP_H #define LLVM_TRANSFORMS_UTILS_UNROLLLOOP_H -#include "llvm/ADT/StringRef.h" namespace llvm { +class StringRef; class AssumptionCache; class DominatorTree; class Loop; @@ -29,15 +29,16 @@ class MDNode; class Pass; class ScalarEvolution; -bool UnrollLoop(Loop *L, unsigned Count, unsigned TripCount, bool AllowRuntime, - bool AllowExpensiveTripCount, unsigned TripMultiple, - LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, - AssumptionCache *AC, bool PreserveLCSSA); +bool UnrollLoop(Loop *L, unsigned Count, unsigned TripCount, bool Force, + bool AllowRuntime, bool AllowExpensiveTripCount, + unsigned TripMultiple, LoopInfo *LI, ScalarEvolution *SE, + DominatorTree *DT, AssumptionCache *AC, bool PreserveLCSSA); -bool UnrollRuntimeLoopProlog(Loop *L, unsigned Count, - bool AllowExpensiveTripCount, LoopInfo *LI, - ScalarEvolution *SE, DominatorTree *DT, - bool PreserveLCSSA); +bool UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, + bool AllowExpensiveTripCount, + bool UseEpilogRemainder, LoopInfo *LI, + ScalarEvolution *SE, DominatorTree *DT, + bool PreserveLCSSA); MDNode *GetUnrollMetadata(MDNode *LoopID, StringRef Name); } diff --git a/include/llvm/Transforms/Utils/ValueMapper.h b/include/llvm/Transforms/Utils/ValueMapper.h index 469022f34c56..de649009612c 100644 --- a/include/llvm/Transforms/Utils/ValueMapper.h +++ b/include/llvm/Transforms/Utils/ValueMapper.h @@ -18,117 +18,255 @@ #include "llvm/IR/ValueMap.h" namespace llvm { - class Value; - class Instruction; - typedef ValueMap<const Value *, WeakVH> ValueToValueMapTy; - - /// ValueMapTypeRemapper - This is a class that can be implemented by clients - /// to remap types when cloning constants and instructions. - class ValueMapTypeRemapper { - virtual void anchor(); // Out of line method. - public: - virtual ~ValueMapTypeRemapper() {} - - /// remapType - The client should implement this method if they want to - /// remap types while mapping values. - virtual Type *remapType(Type *SrcTy) = 0; - }; - - /// ValueMaterializer - This is a class that can be implemented by clients - /// to materialize Values on demand. - class ValueMaterializer { - virtual void anchor(); // Out of line method. - - protected: - ~ValueMaterializer() = default; - ValueMaterializer() = default; - ValueMaterializer(const ValueMaterializer&) = default; - ValueMaterializer &operator=(const ValueMaterializer&) = default; - - public: - /// The client should implement this method if they want to generate a - /// mapped Value on demand. For example, if linking lazily. - virtual Value *materializeDeclFor(Value *V) = 0; - - /// If the data being mapped is recursive, the above function can map - /// just the declaration and this is called to compute the initializer. - /// It is called after the mapping is recorded, so it doesn't need to worry - /// about recursion. - virtual void materializeInitFor(GlobalValue *New, GlobalValue *Old); - - /// If the client needs to handle temporary metadata it must implement - /// these methods. - virtual Metadata *mapTemporaryMetadata(Metadata *MD) { return nullptr; } - virtual void replaceTemporaryMetadata(const Metadata *OrigMD, - Metadata *NewMD) {} - - /// The client should implement this method if some metadata need - /// not be mapped, for example DISubprogram metadata for functions not - /// linked into the destination module. - virtual bool isMetadataNeeded(Metadata *MD) { return true; } - }; - - /// RemapFlags - These are flags that the value mapping APIs allow. - enum RemapFlags { - RF_None = 0, - - /// RF_NoModuleLevelChanges - If this flag is set, the remapper knows that - /// only local values within a function (such as an instruction or argument) - /// are mapped, not global values like functions and global metadata. - RF_NoModuleLevelChanges = 1, - - /// RF_IgnoreMissingEntries - If this flag is set, the remapper ignores - /// entries that are not in the value map. If it is unset, it aborts if an - /// operand is asked to be remapped which doesn't exist in the mapping. - RF_IgnoreMissingEntries = 2, - - /// Instruct the remapper to move distinct metadata instead of duplicating - /// it when there are module-level changes. - RF_MoveDistinctMDs = 4, - - /// Any global values not in value map are mapped to null instead of - /// mapping to self. Illegal if RF_IgnoreMissingEntries is also set. - RF_NullMapMissingGlobalValues = 8, - - /// Set when there is still temporary metadata that must be handled, - /// such as when we are doing function importing and will materialize - /// and link metadata as a postpass. - RF_HaveUnmaterializedMetadata = 16, - }; - - static inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) { - return RemapFlags(unsigned(LHS)|unsigned(RHS)); - } - - Value *MapValue(const Value *V, ValueToValueMapTy &VM, - RemapFlags Flags = RF_None, - ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr); - - Metadata *MapMetadata(const Metadata *MD, ValueToValueMapTy &VM, - RemapFlags Flags = RF_None, - ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr); - - /// MapMetadata - provide versions that preserve type safety for MDNodes. - MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM, - RemapFlags Flags = RF_None, - ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr); - - void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, - RemapFlags Flags = RF_None, - ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr); - - /// MapValue - provide versions that preserve type safety for Constants. - inline Constant *MapValue(const Constant *V, ValueToValueMapTy &VM, - RemapFlags Flags = RF_None, - ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr) { - return cast<Constant>(MapValue((const Value*)V, VM, Flags, TypeMapper, - Materializer)); - } + +class Value; +class Instruction; +typedef ValueMap<const Value *, WeakVH> ValueToValueMapTy; + +/// This is a class that can be implemented by clients to remap types when +/// cloning constants and instructions. +class ValueMapTypeRemapper { + virtual void anchor(); // Out of line method. +public: + virtual ~ValueMapTypeRemapper() {} + + /// The client should implement this method if they want to remap types while + /// mapping values. + virtual Type *remapType(Type *SrcTy) = 0; +}; + +/// This is a class that can be implemented by clients to materialize Values on +/// demand. +class ValueMaterializer { + virtual void anchor(); // Out of line method. + +protected: + ~ValueMaterializer() = default; + ValueMaterializer() = default; + ValueMaterializer(const ValueMaterializer &) = default; + ValueMaterializer &operator=(const ValueMaterializer &) = default; + +public: + /// This method can be implemented to generate a mapped Value on demand. For + /// example, if linking lazily. Returns null if the value is not materialized. + virtual Value *materialize(Value *V) = 0; +}; + +/// These are flags that the value mapping APIs allow. +enum RemapFlags { + RF_None = 0, + + /// If this flag is set, the remapper knows that only local values within a + /// function (such as an instruction or argument) are mapped, not global + /// values like functions and global metadata. + RF_NoModuleLevelChanges = 1, + + /// If this flag is set, the remapper ignores missing function-local entries + /// (Argument, Instruction, BasicBlock) that are not in the value map. If it + /// is unset, it aborts if an operand is asked to be remapped which doesn't + /// exist in the mapping. + /// + /// There are no such assertions in MapValue(), whose results are almost + /// unchanged by this flag. This flag mainly changes the assertion behaviour + /// in RemapInstruction(). + /// + /// Since an Instruction's metadata operands (even that point to SSA values) + /// aren't guaranteed to be dominated by their definitions, MapMetadata will + /// return "!{}" instead of "null" for \a LocalAsMetadata instances whose SSA + /// values are unmapped when this flag is set. Otherwise, \a MapValue() + /// completely ignores this flag. + /// + /// \a MapMetadata() always ignores this flag. + RF_IgnoreMissingLocals = 2, + + /// Instruct the remapper to move distinct metadata instead of duplicating it + /// when there are module-level changes. + RF_MoveDistinctMDs = 4, + + /// Any global values not in value map are mapped to null instead of mapping + /// to self. Illegal if RF_IgnoreMissingLocals is also set. + RF_NullMapMissingGlobalValues = 8, +}; + +static inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) { + return RemapFlags(unsigned(LHS) | unsigned(RHS)); +} + +class ValueMapperImpl; + +/// Context for (re-)mapping values (and metadata). +/// +/// A shared context used for mapping and remapping of Value and Metadata +/// instances using \a ValueToValueMapTy, \a RemapFlags, \a +/// ValueMapTypeRemapper, and \a ValueMaterializer. +/// +/// There are a number of top-level entry points: +/// - \a mapValue() (and \a mapConstant()); +/// - \a mapMetadata() (and \a mapMDNode()); +/// - \a remapInstruction(); and +/// - \a remapFunction(). +/// +/// The \a ValueMaterializer can be used as a callback, but cannot invoke any +/// of these top-level functions recursively. Instead, callbacks should use +/// one of the following to schedule work lazily in the \a ValueMapper +/// instance: +/// - \a scheduleMapGlobalInitializer() +/// - \a scheduleMapAppendingVariable() +/// - \a scheduleMapGlobalAliasee() +/// - \a scheduleRemapFunction() +/// +/// Sometimes a callback needs a diferent mapping context. Such a context can +/// be registered using \a registerAlternateMappingContext(), which takes an +/// alternate \a ValueToValueMapTy and \a ValueMaterializer and returns a ID to +/// pass into the schedule*() functions. +/// +/// TODO: lib/Linker really doesn't need the \a ValueHandle in the \a +/// ValueToValueMapTy. We should template \a ValueMapper (and its +/// implementation classes), and explicitly instantiate on two concrete +/// instances of \a ValueMap (one as \a ValueToValueMap, and one with raw \a +/// Value pointers). It may be viable to do away with \a TrackingMDRef in the +/// \a Metadata side map for the lib/Linker case as well, in which case we'll +/// need a new template parameter on \a ValueMap. +/// +/// TODO: Update callers of \a RemapInstruction() and \a MapValue() (etc.) to +/// use \a ValueMapper directly. +class ValueMapper { + void *pImpl; + + ValueMapper(ValueMapper &&) = delete; + ValueMapper(const ValueMapper &) = delete; + ValueMapper &operator=(ValueMapper &&) = delete; + ValueMapper &operator=(const ValueMapper &) = delete; + +public: + ValueMapper(ValueToValueMapTy &VM, RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr); + ~ValueMapper(); + + /// Register an alternate mapping context. + /// + /// Returns a MappingContextID that can be used with the various schedule*() + /// API to switch in a different value map on-the-fly. + unsigned + registerAlternateMappingContext(ValueToValueMapTy &VM, + ValueMaterializer *Materializer = nullptr); + + /// Add to the current \a RemapFlags. + /// + /// \note Like the top-level mapping functions, \a addFlags() must be called + /// at the top level, not during a callback in a \a ValueMaterializer. + void addFlags(RemapFlags Flags); + + Metadata *mapMetadata(const Metadata &MD); + MDNode *mapMDNode(const MDNode &N); + + Value *mapValue(const Value &V); + Constant *mapConstant(const Constant &C); + + void remapInstruction(Instruction &I); + void remapFunction(Function &F); + + void scheduleMapGlobalInitializer(GlobalVariable &GV, Constant &Init, + unsigned MappingContextID = 0); + void scheduleMapAppendingVariable(GlobalVariable &GV, Constant *InitPrefix, + bool IsOldCtorDtor, + ArrayRef<Constant *> NewMembers, + unsigned MappingContextID = 0); + void scheduleMapGlobalAliasee(GlobalAlias &GA, Constant &Aliasee, + unsigned MappingContextID = 0); + void scheduleRemapFunction(Function &F, unsigned MappingContextID = 0); +}; + +/// Look up or compute a value in the value map. +/// +/// Return a mapped value for a function-local value (Argument, Instruction, +/// BasicBlock), or compute and memoize a value for a Constant. +/// +/// 1. If \c V is in VM, return the result. +/// 2. Else if \c V can be materialized with \c Materializer, do so, memoize +/// it in \c VM, and return it. +/// 3. Else if \c V is a function-local value, return nullptr. +/// 4. Else if \c V is a \a GlobalValue, return \c nullptr or \c V depending +/// on \a RF_NullMapMissingGlobalValues. +/// 5. Else if \c V is a \a MetadataAsValue wrapping a LocalAsMetadata, +/// recurse on the local SSA value, and return nullptr or "metadata !{}" on +/// missing depending on RF_IgnoreMissingValues. +/// 6. Else if \c V is a \a MetadataAsValue, rewrap the return of \a +/// MapMetadata(). +/// 7. Else, compute the equivalent constant, and return it. +inline Value *MapValue(const Value *V, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + return ValueMapper(VM, Flags, TypeMapper, Materializer).mapValue(*V); +} + +/// Lookup or compute a mapping for a piece of metadata. +/// +/// Compute and memoize a mapping for \c MD. +/// +/// 1. If \c MD is mapped, return it. +/// 2. Else if \a RF_NoModuleLevelChanges or \c MD is an \a MDString, return +/// \c MD. +/// 3. Else if \c MD is a \a ConstantAsMetadata, call \a MapValue() and +/// re-wrap its return (returning nullptr on nullptr). +/// 4. Else, \c MD is an \a MDNode. These are remapped, along with their +/// transitive operands. Distinct nodes are duplicated or moved depending +/// on \a RF_MoveDistinctNodes. Uniqued nodes are remapped like constants. +/// +/// \note \a LocalAsMetadata is completely unsupported by \a MapMetadata. +/// Instead, use \a MapValue() with its wrapping \a MetadataAsValue instance. +inline Metadata *MapMetadata(const Metadata *MD, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMetadata(*MD); +} + +/// Version of MapMetadata with type safety for MDNode. +inline MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMDNode(*MD); +} + +/// Convert the instruction operands from referencing the current values into +/// those specified by VM. +/// +/// If \a RF_IgnoreMissingLocals is set and an operand can't be found via \a +/// MapValue(), use the old value. Otherwise assert that this doesn't happen. +/// +/// Note that \a MapValue() only returns \c nullptr for SSA values missing from +/// \c VM. +inline void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + ValueMapper(VM, Flags, TypeMapper, Materializer).remapInstruction(*I); +} + +/// Remap the operands, metadata, arguments, and instructions of a function. +/// +/// Calls \a MapValue() on prefix data, prologue data, and personality +/// function; calls \a MapMetadata() on each attached MDNode; remaps the +/// argument types using the provided \c TypeMapper; and calls \a +/// RemapInstruction() on every instruction. +inline void RemapFunction(Function &F, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + ValueMapper(VM, Flags, TypeMapper, Materializer).remapFunction(F); +} + +/// Version of MapValue with type safety for Constant. +inline Constant *MapValue(const Constant *V, ValueToValueMapTy &VM, + RemapFlags Flags = RF_None, + ValueMapTypeRemapper *TypeMapper = nullptr, + ValueMaterializer *Materializer = nullptr) { + return ValueMapper(VM, Flags, TypeMapper, Materializer).mapConstant(*V); +} } // End llvm namespace diff --git a/include/llvm/Transforms/Vectorize.h b/include/llvm/Transforms/Vectorize.h index aec3993d68fc..f734e299c6e9 100644 --- a/include/llvm/Transforms/Vectorize.h +++ b/include/llvm/Transforms/Vectorize.h @@ -139,6 +139,13 @@ Pass *createSLPVectorizerPass(); bool vectorizeBasicBlock(Pass *P, BasicBlock &BB, const VectorizeConfig &C = VectorizeConfig()); +//===----------------------------------------------------------------------===// +// +// LoadStoreVectorizer - Create vector loads and stores, but leave scalar +// operations. +// +Pass *createLoadStoreVectorizerPass(); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Vectorize/LoopVectorize.h b/include/llvm/Transforms/Vectorize/LoopVectorize.h new file mode 100644 index 000000000000..e6d3e8353307 --- /dev/null +++ b/include/llvm/Transforms/Vectorize/LoopVectorize.h @@ -0,0 +1,103 @@ +//===---- LoopVectorize.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the LLVM loop vectorizer. This pass modifies 'vectorizable' loops +// and generates target-independent LLVM-IR. +// The vectorizer uses the TargetTransformInfo analysis to estimate the costs +// of instructions in order to estimate the profitability of vectorization. +// +// The loop vectorizer combines consecutive loop iterations into a single +// 'wide' iteration. After this transformation the index is incremented +// by the SIMD vector width, and not by one. +// +// This pass has three parts: +// 1. The main loop pass that drives the different parts. +// 2. LoopVectorizationLegality - A unit that checks for the legality +// of the vectorization. +// 3. InnerLoopVectorizer - A unit that performs the actual +// widening of instructions. +// 4. LoopVectorizationCostModel - A unit that checks for the profitability +// of vectorization. It decides on the optimal vector width, which +// can be one, if vectorization is not profitable. +// +//===----------------------------------------------------------------------===// +// +// The reduction-variable vectorization is based on the paper: +// D. Nuzman and R. Henderson. Multi-platform Auto-vectorization. +// +// Variable uniformity checks are inspired by: +// Karrenberg, R. and Hack, S. Whole Function Vectorization. +// +// The interleaved access vectorization is based on the paper: +// Dorit Nuzman, Ira Rosen and Ayal Zaks. Auto-Vectorization of Interleaved +// Data for SIMD +// +// Other ideas/concepts are from: +// A. Zaks and D. Nuzman. Autovectorization in GCC-two years later. +// +// S. Maleki, Y. Gao, M. Garzaran, T. Wong and D. Padua. An Evaluation of +// Vectorizing Compilers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZE_H +#define LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZE_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/DemandedBits.h" +#include "llvm/Analysis/LoopAccessAnalysis.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopPassManager.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" +#include <functional> + +namespace llvm { + +/// The LoopVectorize Pass. +struct LoopVectorizePass : public PassInfoMixin<LoopVectorizePass> { + bool DisableUnrolling = false; + /// If true, consider all loops for vectorization. + /// If false, only loops that explicitly request vectorization are + /// considered. + bool AlwaysVectorize = true; + + ScalarEvolution *SE; + LoopInfo *LI; + TargetTransformInfo *TTI; + DominatorTree *DT; + BlockFrequencyInfo *BFI; + TargetLibraryInfo *TLI; + DemandedBits *DB; + AliasAnalysis *AA; + AssumptionCache *AC; + std::function<const LoopAccessInfo &(Loop &)> *GetLAA; + + BlockFrequency ColdEntryFreq; + + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + // Shim for old PM. + bool runImpl(Function &F, ScalarEvolution &SE_, LoopInfo &LI_, + TargetTransformInfo &TTI_, DominatorTree &DT_, + BlockFrequencyInfo &BFI_, TargetLibraryInfo *TLI_, + DemandedBits &DB_, AliasAnalysis &AA_, AssumptionCache &AC_, + std::function<const LoopAccessInfo &(Loop &)> &GetLAA_); + + bool processLoop(Loop *L); +}; +} + +#endif // LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZE_H diff --git a/include/llvm/Transforms/Vectorize/SLPVectorizer.h b/include/llvm/Transforms/Vectorize/SLPVectorizer.h new file mode 100644 index 000000000000..3a5b42411d35 --- /dev/null +++ b/include/llvm/Transforms/Vectorize/SLPVectorizer.h @@ -0,0 +1,113 @@ +//===---- SLPVectorizer.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This pass implements the Bottom Up SLP vectorizer. It detects consecutive +// stores that can be put together into vector-stores. Next, it attempts to +// construct vectorizable tree using the use-def chains. If a profitable tree +// was found, the SLP vectorizer performs vectorization on the tree. +// +// The pass is inspired by the work described in the paper: +// "Loop-Aware SLP in GCC" by Ira Rosen, Dorit Nuzman, Ayal Zaks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_VECTORIZE_SLPVECTORIZER_H +#define LLVM_TRANSFORMS_VECTORIZE_SLPVECTORIZER_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/DemandedBits.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// A private "module" namespace for types and utilities used by this pass. +/// These are implementation details and should not be used by clients. +namespace slpvectorizer { +class BoUpSLP; +} + +struct SLPVectorizerPass : public PassInfoMixin<SLPVectorizerPass> { + typedef SmallVector<StoreInst *, 8> StoreList; + typedef MapVector<Value *, StoreList> StoreListMap; + typedef SmallVector<WeakVH, 8> WeakVHList; + typedef MapVector<Value *, WeakVHList> WeakVHListMap; + + ScalarEvolution *SE = nullptr; + TargetTransformInfo *TTI = nullptr; + TargetLibraryInfo *TLI = nullptr; + AliasAnalysis *AA = nullptr; + LoopInfo *LI = nullptr; + DominatorTree *DT = nullptr; + AssumptionCache *AC = nullptr; + DemandedBits *DB = nullptr; + const DataLayout *DL = nullptr; + +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + // Glue for old PM. + bool runImpl(Function &F, ScalarEvolution *SE_, TargetTransformInfo *TTI_, + TargetLibraryInfo *TLI_, AliasAnalysis *AA_, LoopInfo *LI_, + DominatorTree *DT_, AssumptionCache *AC_, DemandedBits *DB_); + +private: + /// \brief Collect store and getelementptr instructions and organize them + /// according to the underlying object of their pointer operands. We sort the + /// instructions by their underlying objects to reduce the cost of + /// consecutive access queries. + /// + /// TODO: We can further reduce this cost if we flush the chain creation + /// every time we run into a memory barrier. + void collectSeedInstructions(BasicBlock *BB); + + /// \brief Try to vectorize a chain that starts at two arithmetic instrs. + bool tryToVectorizePair(Value *A, Value *B, slpvectorizer::BoUpSLP &R); + + /// \brief Try to vectorize a list of operands. + /// \@param BuildVector A list of users to ignore for the purpose of + /// scheduling and that don't need extracting. + /// \returns true if a value was vectorized. + bool tryToVectorizeList(ArrayRef<Value *> VL, slpvectorizer::BoUpSLP &R, + ArrayRef<Value *> BuildVector = None, + bool allowReorder = false); + + /// \brief Try to vectorize a chain that may start at the operands of \V; + bool tryToVectorize(BinaryOperator *V, slpvectorizer::BoUpSLP &R); + + /// \brief Vectorize the store instructions collected in Stores. + bool vectorizeStoreChains(slpvectorizer::BoUpSLP &R); + + /// \brief Vectorize the index computations of the getelementptr instructions + /// collected in GEPs. + bool vectorizeGEPIndices(BasicBlock *BB, slpvectorizer::BoUpSLP &R); + + /// \brief Scan the basic block and look for patterns that are likely to start + /// a vectorization chain. + bool vectorizeChainsInBlock(BasicBlock *BB, slpvectorizer::BoUpSLP &R); + + bool vectorizeStoreChain(ArrayRef<Value *> Chain, int CostThreshold, + slpvectorizer::BoUpSLP &R, unsigned VecRegSize); + + bool vectorizeStores(ArrayRef<StoreInst *> Stores, int costThreshold, + slpvectorizer::BoUpSLP &R); + + /// The store instructions in a basic block organized by base pointer. + StoreListMap Stores; + + /// The getelementptr instructions in a basic block organized by base pointer. + WeakVHListMap GEPs; +}; +} + +#endif // LLVM_TRANSFORMS_VECTORIZE_SLPVECTORIZER_H diff --git a/include/llvm/module.modulemap b/include/llvm/module.modulemap index d74ada6faa61..cc1895011dc3 100644 --- a/include/llvm/module.modulemap +++ b/include/llvm/module.modulemap @@ -3,9 +3,6 @@ module LLVM_Analysis { umbrella "Analysis" module * { export * } - // FIXME: Why is this excluded? - exclude header "Analysis/BlockFrequencyInfoImpl.h" - // This is intended for (repeated) textual inclusion. textual header "Analysis/TargetLibraryInfo.def" } @@ -37,12 +34,9 @@ module LLVM_Backend { module Target { umbrella "Target" module * { export * } - } - // FIXME: Where should this go? - module Analysis_BlockFrequencyInfoImpl { - header "Analysis/BlockFrequencyInfoImpl.h" - export * + // This is intended for (repeated) textual inclusion. + textual header "Target/TargetOpcodes.def" } } @@ -90,6 +84,17 @@ module LLVM_DebugInfo_PDB_DIA { module * { export * } } +module LLVM_DebugInfo_CodeView { + requires cplusplus + + umbrella "DebugInfo/CodeView" + module * { export * } + + // These are intended for (repeated) textual inclusion. + textual header "DebugInfo/CodeView/TypeRecords.def" + textual header "DebugInfo/CodeView/CVSymbolTypes.def" +} + module LLVM_ExecutionEngine { requires cplusplus @@ -101,21 +106,64 @@ module LLVM_ExecutionEngine { // Exclude these; they're intended to be included into only a single // translation unit (or none) and aren't part of this module. - exclude header "ExecutionEngine/JIT.h" exclude header "ExecutionEngine/MCJIT.h" exclude header "ExecutionEngine/Interpreter.h" exclude header "ExecutionEngine/OrcMCJITReplacement.h" } -module LLVM_IR { - requires cplusplus +module LLVM_Pass { + module Pass { + // PassSupport.h and PassAnalysisSupport.h are made available only through + // Pass.h. + header "Pass.h" + header "PassSupport.h" + header "PassAnalysisSupport.h" + export * + } - // FIXME: Is this the right place for these? - module Pass { header "Pass.h" export * } - module PassSupport { header "PassSupport.h" export * } - module PassAnalysisSupport { header "PassAnalysisSupport.h" export * } module PassRegistry { header "PassRegistry.h" export * } module InitializePasses { header "InitializePasses.h" export * } +} + +module LLVM_intrinsic_gen { + requires cplusplus + + // Delay building the modules containing dependencies to Attributes.h and + // Intrinsics.h because they need to be generated by tablegen first. + + // Attributes.h + module IR_Argument { header "IR/Argument.h" export * } + module IR_Attributes { header "IR/Attributes.h" export * } + module IR_CallSite { header "IR/CallSite.h" export * } + module IR_ConstantFolder { header "IR/ConstantFolder.h" export * } + module IR_NoFolder { header "IR/NoFolder.h" export * } + module IR_Module { header "IR/Module.h" export * } + module IR_ModuleSummaryIndex { header "IR/ModuleSummaryIndex.h" export * } + module IR_Function { header "IR/Function.h" export * } + module IR_InstrTypes { header "IR/InstrTypes.h" export * } + module IR_Instructions { header "IR/Instructions.h" export * } + + + // Intrinsics.h + module IR_CFG { header "IR/CFG.h" export * } + module IR_ConstantRange { header "IR/ConstantRange.h" export * } + module IR_Dominators { header "IR/Dominators.h" export * } + module IR_IRBuilder { header "IR/IRBuilder.h" export * } + module IR_PassManager { header "IR/PassManager.h" export * } + module IR_PredIteratorCache { header "IR/PredIteratorCache.h" export * } + module IR_Verifier { header "IR/Verifier.h" export * } + module IR_InstIterator { header "IR/InstIterator.h" export * } + module IR_InstVisitor { header "IR/InstVisitor.h" export * } + module IR_Intrinsics { header "IR/Intrinsics.h" export * } + module IR_IntrinsicInst { header "IR/IntrinsicInst.h" export * } + module IR_PatternMatch { header "IR/PatternMatch.h" export * } + module IR_Statepoint { header "IR/Statepoint.h" export * } + + export * +} + +module LLVM_IR { + requires cplusplus umbrella "IR" module * { export * } @@ -154,6 +202,16 @@ module LLVM_Object { } module LLVM_Option { requires cplusplus umbrella "Option" module * { export * } } + +module LLVM_ProfileData { + requires cplusplus + + umbrella "ProfileData" + module * { export * } + + textual header "ProfileData/InstrProfData.inc" +} + module LLVM_TableGen { requires cplusplus umbrella "TableGen" module * { export * } } module LLVM_Transforms { @@ -184,9 +242,6 @@ module LLVM_Utils { // Exclude this; it's only included on Solaris. exclude header "Support/Solaris.h" - // Exclude this; it's only included on AIX and fundamentally non-modular. - exclude header "Support/AIXDataTypesFix.h" - // Exclude this; it's fundamentally non-modular. exclude header "Support/PluginLoader.h" @@ -195,12 +250,17 @@ module LLVM_Utils { // These are intended for textual inclusion. textual header "Support/ARMTargetParser.def" + textual header "Support/AArch64TargetParser.def" textual header "Support/Dwarf.def" + textual header "Support/MachO.def" textual header "Support/ELFRelocs/AArch64.def" + textual header "Support/ELFRelocs/AMDGPU.def" textual header "Support/ELFRelocs/ARM.def" textual header "Support/ELFRelocs/AVR.def" + textual header "Support/ELFRelocs/BPF.def" textual header "Support/ELFRelocs/Hexagon.def" textual header "Support/ELFRelocs/i386.def" + textual header "Support/ELFRelocs/Lanai.def" textual header "Support/ELFRelocs/Mips.def" textual header "Support/ELFRelocs/PowerPC64.def" textual header "Support/ELFRelocs/PowerPC.def" |