diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /include | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) | |
download | src-71d5a2540a98c81f5bcaeb48805e0e2881f530ef.tar.gz src-71d5a2540a98c81f5bcaeb48805e0e2881f530ef.zip |
Vendor import of llvm trunk r300422:vendor/llvm/llvm-trunk-r300422
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=317017
svn path=/vendor/llvm/llvm-trunk-r300422/; revision=317018; tag=vendor/llvm/llvm-trunk-r300422
Diffstat (limited to 'include')
559 files changed, 20790 insertions, 8857 deletions
diff --git a/include/llvm-c/Transforms/Scalar.h b/include/llvm-c/Transforms/Scalar.h index 8991e0904849..b9612b9cec04 100644 --- a/include/llvm-c/Transforms/Scalar.h +++ b/include/llvm-c/Transforms/Scalar.h @@ -44,6 +44,9 @@ void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM); /** See llvm::createCFGSimplificationPass function. */ void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM); +/** See llvm::createLateCFGSimplificationPass function. */ +void LLVMAddLateCFGSimplificationPass(LLVMPassManagerRef PM); + /** See llvm::createDeadStoreEliminationPass function. */ void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM); diff --git a/include/llvm-c/lto.h b/include/llvm-c/lto.h index c3af74cdedab..8d45b7832041 100644 --- a/include/llvm-c/lto.h +++ b/include/llvm-c/lto.h @@ -551,7 +551,7 @@ lto_codegen_set_should_embed_uselists(lto_code_gen_t cg, lto_bool_t ShouldEmbedUselists); /** - * @} + * @} // endgoup LLVMCLTO * @defgroup LLVMCTLTO ThinLTO * @ingroup LLVMC * @@ -669,75 +669,6 @@ extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg, lto_codegen_model); /** - * @} - * @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control - * @ingroup LLVMCTLTO - * - * 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. - * @{ - */ - -/** - * Sets the path to a directory to use as a cache storage for incremental build. - * Setting this activates caching. - * - * \since LTO_API_VERSION=18 - */ -extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg, - const char *cache_dir); - -/** - * Sets the cache pruning interval (in seconds). A negative value disable the - * pruning. An unspecified default value will be applied, and a value of 0 will - * be ignored. - * - * \since LTO_API_VERSION=18 - */ -extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg, - int interval); - -/** - * 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, a value of 0 will - * be ignored. An unspecified default value will be applied. - * - * The formula looks like: - * AvailableSpace = FreeSpace + ExistingCacheSize - * NewCacheSize = AvailableSpace * P/100 - * - * \since LTO_API_VERSION=18 - */ -extern void thinlto_codegen_set_final_cache_size_relative_to_available_space( - thinlto_code_gen_t cg, unsigned percentage); - -/** - * Sets the expiration (in seconds) for an entry in the cache. An unspecified - * default value will be applied. A value of 0 will be ignored. - * - * \since LTO_API_VERSION=18 - */ -extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg, - unsigned expiration); - -/** - * @} - */ - -/** * Sets the path to a directory to use as a storage for temporary bitcode files. * The intention is to make the bitcode files available for debugging at various * stage of the pipeline. @@ -820,12 +751,77 @@ extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg, const char *name, int length); -#ifdef __cplusplus -} -#endif +/** + * @} // endgoup LLVMCTLTO + * @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control + * @ingroup LLVMCTLTO + * + * 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. + * @{ + */ + +/** + * Sets the path to a directory to use as a cache storage for incremental build. + * Setting this activates caching. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg, + const char *cache_dir); + +/** + * Sets the cache pruning interval (in seconds). A negative value disable the + * pruning. An unspecified default value will be applied, and a value of 0 will + * be ignored. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg, + int interval); + +/** + * 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, a value of 0 will + * be ignored. An unspecified default value will be applied. + * + * The formula looks like: + * AvailableSpace = FreeSpace + ExistingCacheSize + * NewCacheSize = AvailableSpace * P/100 + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_final_cache_size_relative_to_available_space( + thinlto_code_gen_t cg, unsigned percentage); /** - * @} + * Sets the expiration (in seconds) for an entry in the cache. An unspecified + * default value will be applied. A value of 0 will be ignored. + * + * \since LTO_API_VERSION=18 */ +extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg, + unsigned expiration); + +/** + * @} // endgroup LLVMCTLTO_CACHING + */ + +#ifdef __cplusplus +} +#endif #endif /* LLVM_C_LTO_H */ diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 00304230a991..e7e5036e6930 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -18,9 +18,19 @@ #define LLVM_ADT_APFLOAT_H #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include <memory> +#define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \ + do { \ + if (usesLayout<IEEEFloat>(getSemantics())) \ + return U.IEEE.METHOD_CALL; \ + if (usesLayout<DoubleAPFloat>(getSemantics())) \ + return U.Double.METHOD_CALL; \ + llvm_unreachable("Unexpected semantics"); \ + } while (false) + namespace llvm { struct fltSemantics; @@ -42,7 +52,7 @@ enum lostFraction { // Example of truncated bits: lfMoreThanHalf // 1xxxxx x's not all zero }; -/// \brief A self-contained host- and target-independent arbitrary-precision +/// A self-contained host- and target-independent arbitrary-precision /// floating-point software implementation. /// /// APFloat uses bignum integer arithmetic as provided by static functions in @@ -130,22 +140,25 @@ enum lostFraction { // Example of truncated bits: // implementation classes. This struct should not define any non-static data // members. struct APFloatBase { + // TODO remove this and use APInt typedef directly. + typedef APInt::WordType integerPart; + /// A signed type to represent a floating point numbers unbiased exponent. typedef signed short ExponentType; /// \name Floating Point Semantics. /// @{ - static const fltSemantics &IEEEhalf(); - static const fltSemantics &IEEEsingle(); - static const fltSemantics &IEEEdouble(); - static const fltSemantics &IEEEquad(); - static const fltSemantics &PPCDoubleDouble(); - static const fltSemantics &x87DoubleExtended(); + static const fltSemantics &IEEEhalf() LLVM_READNONE; + static const fltSemantics &IEEEsingle() LLVM_READNONE; + static const fltSemantics &IEEEdouble() LLVM_READNONE; + static const fltSemantics &IEEEquad() LLVM_READNONE; + static const fltSemantics &PPCDoubleDouble() LLVM_READNONE; + static const fltSemantics &x87DoubleExtended() LLVM_READNONE; /// A Pseudo fltsemantic used to construct APFloats that cannot conflict with /// anything real. - static const fltSemantics &Bogus(); + static const fltSemantics &Bogus() LLVM_READNONE; /// @} @@ -191,7 +204,7 @@ struct APFloatBase { uninitialized }; - /// \brief Enumeration of \c ilogb error results. + /// Enumeration of \c ilogb error results. enum IlogbErrorKinds { IEK_Zero = INT_MIN + 1, IEK_NaN = INT_MIN, @@ -227,7 +240,7 @@ public: /// @} - /// \brief Returns whether this instance allocated memory. + /// Returns whether this instance allocated memory. bool needsCleanup() const { return partCount() > 1; } /// \name Convenience "constructors" @@ -235,10 +248,6 @@ public: /// @} - /// Used to insert APFloat objects, or objects that contain APFloat objects, - /// into FoldingSets. - void Profile(FoldingSetNodeID &NID) const; - /// \name Arithmetic /// @{ @@ -255,53 +264,12 @@ public: /// IEEE-754R 5.3.1: nextUp/nextDown. opStatus next(bool nextDown); - /// \brief Operator+ overload which provides the default - /// \c nmNearestTiesToEven rounding mode and *no* error checking. - IEEEFloat operator+(const IEEEFloat &RHS) const { - IEEEFloat Result = *this; - Result.add(RHS, rmNearestTiesToEven); - return Result; - } - - /// \brief Operator- overload which provides the default - /// \c nmNearestTiesToEven rounding mode and *no* error checking. - IEEEFloat operator-(const IEEEFloat &RHS) const { - IEEEFloat Result = *this; - Result.subtract(RHS, rmNearestTiesToEven); - return Result; - } - - /// \brief Operator* overload which provides the default - /// \c nmNearestTiesToEven rounding mode and *no* error checking. - IEEEFloat operator*(const IEEEFloat &RHS) const { - IEEEFloat Result = *this; - Result.multiply(RHS, rmNearestTiesToEven); - return Result; - } - - /// \brief Operator/ overload which provides the default - /// \c nmNearestTiesToEven rounding mode and *no* error checking. - IEEEFloat operator/(const IEEEFloat &RHS) const { - IEEEFloat Result = *this; - Result.divide(RHS, rmNearestTiesToEven); - return Result; - } - /// @} /// \name Sign operations. /// @{ void changeSign(); - void clearSign(); - void copySign(const IEEEFloat &); - - /// \brief A static helper to produce a copy of an APFloat value with its sign - /// copied from some other APFloat. - static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) { - Value.copySign(Sign); - return Value; - } /// @} @@ -309,9 +277,8 @@ public: /// @{ opStatus convert(const fltSemantics &, roundingMode, bool *); - opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode, - bool *) const; - opStatus convertToInteger(APSInt &, roundingMode, bool *) const; + opStatus convertToInteger(MutableArrayRef<integerPart>, unsigned int, bool, + roundingMode, bool *) const; opStatus convertFromAPInt(const APInt &, bool, roundingMode); opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int, bool, roundingMode); @@ -398,7 +365,7 @@ public: /// Returns true if and only if the number has the largest possible finite /// magnitude in the current semantics. bool isLargest() const; - + /// Returns true if and only if the number is an exact integer. bool isInteger() const; @@ -407,7 +374,7 @@ public: IEEEFloat &operator=(const IEEEFloat &); IEEEFloat &operator=(IEEEFloat &&); - /// \brief Overload to compute a hash code for an APFloat value. + /// Overload to compute a hash code for an APFloat value. /// /// Note that the use of hash codes for floating point values is in general /// frought with peril. Equality is hard to define for these values. For @@ -443,9 +410,9 @@ public: /// If this value has an exact multiplicative inverse, store it in inv and /// return true. - bool getExactInverse(IEEEFloat *inv) const; + bool getExactInverse(APFloat *inv) const; - /// \brief Returns the exponent of the internal representation of the APFloat. + /// Returns the exponent of the internal representation of the APFloat. /// /// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)). /// For special APFloat values, this returns special error codes: @@ -456,7 +423,7 @@ public: /// friend int ilogb(const IEEEFloat &Arg); - /// \brief Returns: X * 2^Exp for integral exponents. + /// Returns: X * 2^Exp for integral exponents. friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode); friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode); @@ -532,8 +499,9 @@ private: opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract); opStatus handleOverflow(roundingMode); bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const; - opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool, - roundingMode, bool *) const; + opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart>, + unsigned int, bool, roundingMode, + bool *) const; opStatus convertFromUnsignedParts(const integerPart *, unsigned int, roundingMode); opStatus convertFromHexadecimalString(StringRef, roundingMode); @@ -636,6 +604,13 @@ public: opStatus add(const DoubleAPFloat &RHS, roundingMode RM); opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM); + opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM); + opStatus divide(const DoubleAPFloat &RHS, roundingMode RM); + opStatus remainder(const DoubleAPFloat &RHS); + opStatus mod(const DoubleAPFloat &RHS); + opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand, + const DoubleAPFloat &Addend, roundingMode RM); + opStatus roundToIntegral(roundingMode RM); void changeSign(); cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const; @@ -643,9 +618,49 @@ public: bool isNegative() const; void makeInf(bool Neg); + void makeZero(bool Neg); + void makeLargest(bool Neg); + void makeSmallest(bool Neg); + void makeSmallestNormalized(bool Neg); void makeNaN(bool SNaN, bool Neg, const APInt *fill); + + cmpResult compare(const DoubleAPFloat &RHS) const; + bool bitwiseIsEqual(const DoubleAPFloat &RHS) const; + APInt bitcastToAPInt() const; + opStatus convertFromString(StringRef, roundingMode); + opStatus next(bool nextDown); + + opStatus convertToInteger(MutableArrayRef<integerPart> Input, + unsigned int Width, bool IsSigned, roundingMode RM, + bool *IsExact) const; + opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM); + opStatus convertFromSignExtendedInteger(const integerPart *Input, + unsigned int InputSize, bool IsSigned, + roundingMode RM); + opStatus convertFromZeroExtendedInteger(const integerPart *Input, + unsigned int InputSize, bool IsSigned, + roundingMode RM); + unsigned int convertToHexString(char *DST, unsigned int HexDigits, + bool UpperCase, roundingMode RM) const; + + bool isDenormal() const; + bool isSmallest() const; + bool isLargest() const; + bool isInteger() const; + + void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, + unsigned FormatMaxPadding) const; + + bool getExactInverse(APFloat *inv) const; + + friend int ilogb(const DoubleAPFloat &Arg); + friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode); + friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode); + friend hash_code hash_value(const DoubleAPFloat &Arg); }; +hash_code hash_value(const DoubleAPFloat &Arg); + } // End detail namespace // This is a interface class that is currently forwarding functionalities from @@ -770,26 +785,24 @@ class APFloat : public APFloatBase { llvm_unreachable("Unexpected semantics"); } - void makeZero(bool Neg) { getIEEE().makeZero(Neg); } + void makeZero(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeZero(Neg)); } - void makeInf(bool Neg) { - if (usesLayout<IEEEFloat>(*U.semantics)) - return U.IEEE.makeInf(Neg); - if (usesLayout<DoubleAPFloat>(*U.semantics)) - return U.Double.makeInf(Neg); - llvm_unreachable("Unexpected semantics"); - } + void makeInf(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeInf(Neg)); } void makeNaN(bool SNaN, bool Neg, const APInt *fill) { - getIEEE().makeNaN(SNaN, Neg, fill); + APFLOAT_DISPATCH_ON_SEMANTICS(makeNaN(SNaN, Neg, fill)); } - void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); } + void makeLargest(bool Neg) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeLargest(Neg)); + } - void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); } + void makeSmallest(bool Neg) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallest(Neg)); + } void makeSmallestNormalized(bool Neg) { - getIEEE().makeSmallestNormalized(Neg); + APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallestNormalized(Neg)); } // FIXME: This is due to clang 3.3 (or older version) always checks for the @@ -804,7 +817,8 @@ class APFloat : public APFloatBase { : U(std::move(F), S) {} cmpResult compareAbsoluteValue(const APFloat &RHS) const { - assert(&getSemantics() == &RHS.getSemantics()); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only compare APFloats with the same semantics"); if (usesLayout<IEEEFloat>(getSemantics())) return U.IEEE.compareAbsoluteValue(RHS.U.IEEE); if (usesLayout<DoubleAPFloat>(getSemantics())) @@ -827,13 +841,7 @@ public: ~APFloat() = default; - bool needsCleanup() const { - if (usesLayout<IEEEFloat>(getSemantics())) - return U.IEEE.needsCleanup(); - if (usesLayout<DoubleAPFloat>(getSemantics())) - return U.Double.needsCleanup(); - llvm_unreachable("Unexpected semantics"); - } + bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); } /// Factory for Positive and Negative Zero. /// @@ -920,9 +928,13 @@ public: /// \param isIEEE - If 128 bit number, select between PPC and IEEE static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false); - void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); } + /// Used to insert APFloat objects, or objects that contain APFloat objects, + /// into FoldingSets. + void Profile(FoldingSetNodeID &NID) const; opStatus add(const APFloat &RHS, roundingMode RM) { + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); if (usesLayout<IEEEFloat>(getSemantics())) return U.IEEE.add(RHS.U.IEEE, RM); if (usesLayout<DoubleAPFloat>(getSemantics())) @@ -930,6 +942,8 @@ public: llvm_unreachable("Unexpected semantics"); } opStatus subtract(const APFloat &RHS, roundingMode RM) { + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); if (usesLayout<IEEEFloat>(getSemantics())) return U.IEEE.subtract(RHS.U.IEEE, RM); if (usesLayout<DoubleAPFloat>(getSemantics())) @@ -937,95 +951,172 @@ public: llvm_unreachable("Unexpected semantics"); } opStatus multiply(const APFloat &RHS, roundingMode RM) { - return getIEEE().multiply(RHS.getIEEE(), RM); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.multiply(RHS.U.IEEE, RM); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.multiply(RHS.U.Double, RM); + llvm_unreachable("Unexpected semantics"); } opStatus divide(const APFloat &RHS, roundingMode RM) { - return getIEEE().divide(RHS.getIEEE(), RM); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.divide(RHS.U.IEEE, RM); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.divide(RHS.U.Double, RM); + llvm_unreachable("Unexpected semantics"); } opStatus remainder(const APFloat &RHS) { - return getIEEE().remainder(RHS.getIEEE()); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.remainder(RHS.U.IEEE); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.remainder(RHS.U.Double); + llvm_unreachable("Unexpected semantics"); + } + opStatus mod(const APFloat &RHS) { + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.mod(RHS.U.IEEE); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.mod(RHS.U.Double); + llvm_unreachable("Unexpected semantics"); } - opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); } opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM) { - return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(), - RM); + assert(&getSemantics() == &Multiplicand.getSemantics() && + "Should only call on APFloats with the same semantics"); + assert(&getSemantics() == &Addend.getSemantics() && + "Should only call on APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double, + RM); + llvm_unreachable("Unexpected semantics"); } opStatus roundToIntegral(roundingMode RM) { - return getIEEE().roundToIntegral(RM); + APFLOAT_DISPATCH_ON_SEMANTICS(roundToIntegral(RM)); + } + + // TODO: bool parameters are not readable and a source of bugs. + // Do something. + opStatus next(bool nextDown) { + APFLOAT_DISPATCH_ON_SEMANTICS(next(nextDown)); } - opStatus next(bool nextDown) { return getIEEE().next(nextDown); } + /// Add two APFloats, rounding ties to the nearest even. + /// No error checking. APFloat operator+(const APFloat &RHS) const { - return APFloat(getIEEE() + RHS.getIEEE(), getSemantics()); + APFloat Result(*this); + (void)Result.add(RHS, rmNearestTiesToEven); + return Result; } + /// Subtract two APFloats, rounding ties to the nearest even. + /// No error checking. APFloat operator-(const APFloat &RHS) const { - return APFloat(getIEEE() - RHS.getIEEE(), getSemantics()); + APFloat Result(*this); + (void)Result.subtract(RHS, rmNearestTiesToEven); + return Result; } + /// Multiply two APFloats, rounding ties to the nearest even. + /// No error checking. APFloat operator*(const APFloat &RHS) const { - return APFloat(getIEEE() * RHS.getIEEE(), getSemantics()); + APFloat Result(*this); + (void)Result.multiply(RHS, rmNearestTiesToEven); + return Result; } + /// Divide the first APFloat by the second, rounding ties to the nearest even. + /// No error checking. APFloat operator/(const APFloat &RHS) const { - return APFloat(getIEEE() / RHS.getIEEE(), getSemantics()); + APFloat Result(*this); + (void)Result.divide(RHS, rmNearestTiesToEven); + return Result; } - void changeSign() { getIEEE().changeSign(); } - void clearSign() { getIEEE().clearSign(); } - void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); } + void changeSign() { APFLOAT_DISPATCH_ON_SEMANTICS(changeSign()); } + void clearSign() { + if (isNegative()) + changeSign(); + } + void copySign(const APFloat &RHS) { + if (isNegative() != RHS.isNegative()) + changeSign(); + } + /// A static helper to produce a copy of an APFloat value with its sign + /// copied from some other APFloat. static APFloat copySign(APFloat Value, const APFloat &Sign) { - return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()), - Value.getSemantics()); + Value.copySign(Sign); + return Value; } opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo); - opStatus convertToInteger(integerPart *Input, unsigned int Width, - bool IsSigned, roundingMode RM, + opStatus convertToInteger(MutableArrayRef<integerPart> Input, + unsigned int Width, bool IsSigned, roundingMode RM, bool *IsExact) const { - return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact); + APFLOAT_DISPATCH_ON_SEMANTICS( + convertToInteger(Input, Width, IsSigned, RM, IsExact)); } opStatus convertToInteger(APSInt &Result, roundingMode RM, - bool *IsExact) const { - return getIEEE().convertToInteger(Result, RM, IsExact); - } + bool *IsExact) const; opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM) { - return getIEEE().convertFromAPInt(Input, IsSigned, RM); + APFLOAT_DISPATCH_ON_SEMANTICS(convertFromAPInt(Input, IsSigned, RM)); } opStatus convertFromSignExtendedInteger(const integerPart *Input, unsigned int InputSize, bool IsSigned, roundingMode RM) { - return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned, - RM); + APFLOAT_DISPATCH_ON_SEMANTICS( + convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM)); } opStatus convertFromZeroExtendedInteger(const integerPart *Input, unsigned int InputSize, bool IsSigned, roundingMode RM) { - return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned, - RM); + APFLOAT_DISPATCH_ON_SEMANTICS( + convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM)); } opStatus convertFromString(StringRef, roundingMode); - APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); } + APInt bitcastToAPInt() const { + APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt()); + } double convertToDouble() const { return getIEEE().convertToDouble(); } float convertToFloat() const { return getIEEE().convertToFloat(); } bool operator==(const APFloat &) const = delete; cmpResult compare(const APFloat &RHS) const { - return getIEEE().compare(RHS.getIEEE()); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only compare APFloats with the same semantics"); + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.compare(RHS.U.IEEE); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.compare(RHS.U.Double); + llvm_unreachable("Unexpected semantics"); } bool bitwiseIsEqual(const APFloat &RHS) const { - return getIEEE().bitwiseIsEqual(RHS.getIEEE()); + if (&getSemantics() != &RHS.getSemantics()) + return false; + if (usesLayout<IEEEFloat>(getSemantics())) + return U.IEEE.bitwiseIsEqual(RHS.U.IEEE); + if (usesLayout<DoubleAPFloat>(getSemantics())) + return U.Double.bitwiseIsEqual(RHS.U.Double); + llvm_unreachable("Unexpected semantics"); } unsigned int convertToHexString(char *DST, unsigned int HexDigits, bool UpperCase, roundingMode RM) const { - return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM); + APFLOAT_DISPATCH_ON_SEMANTICS( + convertToHexString(DST, HexDigits, UpperCase, RM)); } bool isZero() const { return getCategory() == fcZero; } @@ -1033,7 +1124,7 @@ public: bool isNaN() const { return getCategory() == fcNaN; } bool isNegative() const { return getIEEE().isNegative(); } - bool isDenormal() const { return getIEEE().isDenormal(); } + bool isDenormal() const { APFLOAT_DISPATCH_ON_SEMANTICS(isDenormal()); } bool isSignaling() const { return getIEEE().isSignaling(); } bool isNormal() const { return !isDenormal() && isFiniteNonZero(); } @@ -1045,30 +1136,24 @@ public: bool isFiniteNonZero() const { return isFinite() && !isZero(); } bool isPosZero() const { return isZero() && !isNegative(); } bool isNegZero() const { return isZero() && isNegative(); } - bool isSmallest() const { return getIEEE().isSmallest(); } - bool isLargest() const { return getIEEE().isLargest(); } - bool isInteger() const { return getIEEE().isInteger(); } + bool isSmallest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isSmallest()); } + bool isLargest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isLargest()); } + bool isInteger() const { APFLOAT_DISPATCH_ON_SEMANTICS(isInteger()); } APFloat &operator=(const APFloat &RHS) = default; APFloat &operator=(APFloat &&RHS) = default; void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0, unsigned FormatMaxPadding = 3) const { - return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding); + APFLOAT_DISPATCH_ON_SEMANTICS( + toString(Str, FormatPrecision, FormatMaxPadding)); } void print(raw_ostream &) const; void dump() const; bool getExactInverse(APFloat *inv) const { - return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr); - } - - // This is for internal test only. - // TODO: Remove it after the PPCDoubleDouble transition. - const APFloat &getSecondFloat() const { - assert(&getSemantics() == &PPCDoubleDouble()); - return U.Double.getSecond(); + APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv)); } friend hash_code hash_value(const APFloat &Arg); @@ -1085,22 +1170,36 @@ public: /// xlC compiler. hash_code hash_value(const APFloat &Arg); inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) { - return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics()); + if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics())) + return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics()); + if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics())) + return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics()); + llvm_unreachable("Unexpected semantics"); } -/// \brief Equivalent of C standard library function. +/// 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. inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) { - return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics()); + if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics())) + return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics()); + if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics())) + return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics()); + llvm_unreachable("Unexpected semantics"); } -/// \brief Returns the absolute value of the argument. +/// Returns the absolute value of the argument. inline APFloat abs(APFloat X) { X.clearSign(); return X; } +/// \brief Returns the negated value of the argument. +inline APFloat neg(APFloat X) { + X.changeSign(); + return X; +} + /// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if /// both are not NaN. If either argument is a NaN, returns the other argument. LLVM_READONLY @@ -1125,4 +1224,5 @@ inline APFloat maxnum(const APFloat &A, const APFloat &B) { } // namespace llvm +#undef APFLOAT_DISPATCH_ON_SEMANTICS #endif // LLVM_ADT_APFLOAT_H diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 2c0713da256c..ab23130b137d 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -32,14 +32,6 @@ 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. -typedef uint64_t integerPart; - -const unsigned int host_char_bit = 8; -const unsigned int integerPartWidth = - host_char_bit * static_cast<unsigned int>(sizeof(integerPart)); - class APInt; inline APInt operator-(APInt); @@ -75,8 +67,18 @@ inline APInt operator-(APInt); /// uses in its IR. This simplifies its use for LLVM. /// class LLVM_NODISCARD APInt { - unsigned BitWidth; ///< The number of bits in this APInt. +public: + typedef uint64_t WordType; + /// This enum is used to hold the constants we needed for APInt. + enum : unsigned { + /// Byte size of a word. + APINT_WORD_SIZE = sizeof(WordType), + /// Bits in a word. + APINT_BITS_PER_WORD = APINT_WORD_SIZE * CHAR_BIT + }; + +private: /// This union is used to store the integer value. When the /// integer bit-width <= 64, it uses VAL, otherwise it uses pVal. union { @@ -84,14 +86,7 @@ class LLVM_NODISCARD APInt { uint64_t *pVal; ///< Used to store the >64 bits integer value. }; - /// This enum is used to hold the constants we needed for APInt. - enum { - /// Bits in a word - APINT_BITS_PER_WORD = - static_cast<unsigned int>(sizeof(uint64_t)) * CHAR_BIT, - /// Byte size of a word - APINT_WORD_SIZE = static_cast<unsigned int>(sizeof(uint64_t)) - }; + unsigned BitWidth; ///< The number of bits in this APInt. friend struct DenseMapAPIntKeyInfo; @@ -99,7 +94,7 @@ class LLVM_NODISCARD APInt { /// /// This constructor is used only internally for speed of construction of /// temporaries. It is unsafe for general use so it is not public. - APInt(uint64_t *val, unsigned bits) : BitWidth(bits), pVal(val) {} + APInt(uint64_t *val, unsigned bits) : pVal(val), BitWidth(bits) {} /// \brief Determine if this APInt just has one word to store value. /// @@ -147,7 +142,7 @@ class LLVM_NODISCARD APInt { return *this; // Mask out the high bits. - uint64_t mask = ~uint64_t(0ULL) >> (APINT_BITS_PER_WORD - wordBits); + uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - wordBits); if (isSingleWord()) VAL &= mask; else @@ -196,32 +191,38 @@ class LLVM_NODISCARD APInt { /// out-of-line slow case for shl APInt shlSlowCase(unsigned shiftAmt) const; - /// out-of-line slow case for operator& - APInt AndSlowCase(const APInt &RHS) const; - - /// out-of-line slow case for operator| - APInt OrSlowCase(const APInt &RHS) const; - - /// out-of-line slow case for operator^ - APInt XorSlowCase(const APInt &RHS) const; - /// out-of-line slow case for operator= APInt &AssignSlowCase(const APInt &RHS); /// out-of-line slow case for operator== - bool EqualSlowCase(const APInt &RHS) const; + bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY; /// out-of-line slow case for operator== - bool EqualSlowCase(uint64_t Val) const; + bool EqualSlowCase(uint64_t Val) const LLVM_READONLY; /// out-of-line slow case for countLeadingZeros - unsigned countLeadingZerosSlowCase() const; + unsigned countLeadingZerosSlowCase() const LLVM_READONLY; /// out-of-line slow case for countTrailingOnes - unsigned countTrailingOnesSlowCase() const; + unsigned countTrailingOnesSlowCase() const LLVM_READONLY; /// out-of-line slow case for countPopulation - unsigned countPopulationSlowCase() const; + unsigned countPopulationSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for setBits. + void setBitsSlowCase(unsigned loBit, unsigned hiBit); + + /// out-of-line slow case for flipAllBits. + void flipAllBitsSlowCase(); + + /// out-of-line slow case for operator&=. + APInt& AndAssignSlowCase(const APInt& RHS); + + /// out-of-line slow case for operator|=. + APInt& OrAssignSlowCase(const APInt& RHS); + + /// out-of-line slow case for operator^=. + APInt& XorAssignSlowCase(const APInt& RHS); public: /// \name Constructors @@ -238,13 +239,14 @@ public: /// \param val the initial value of the APInt /// \param isSigned how to treat signedness of val APInt(unsigned numBits, uint64_t val, bool isSigned = false) - : BitWidth(numBits), VAL(0) { + : BitWidth(numBits) { assert(BitWidth && "bitwidth too small"); - if (isSingleWord()) + if (isSingleWord()) { VAL = val; - else + clearUnusedBits(); + } else { initSlowCase(val, isSigned); - clearUnusedBits(); + } } /// \brief Construct an APInt of numBits width, initialized as bigVal[]. @@ -280,7 +282,7 @@ public: /// Simply makes *this a copy of that. /// @brief Copy Constructor. - APInt(const APInt &that) : BitWidth(that.BitWidth), VAL(0) { + APInt(const APInt &that) : BitWidth(that.BitWidth) { if (isSingleWord()) VAL = that.VAL; else @@ -288,7 +290,7 @@ public: } /// \brief Move Constructor. - APInt(APInt &&that) : BitWidth(that.BitWidth), VAL(that.VAL) { + APInt(APInt &&that) : VAL(that.VAL), BitWidth(that.BitWidth) { that.BitWidth = 0; } @@ -303,7 +305,7 @@ public: /// /// This is useful for object deserialization (pair this with the static /// method Read). - explicit APInt() : BitWidth(1), VAL(0) {} + explicit APInt() : VAL(0), BitWidth(1) {} /// \brief Returns whether this instance allocated memory. bool needsCleanup() const { return !isSingleWord(); } @@ -341,7 +343,7 @@ public: /// This checks to see if the value has all bits of the APInt are set or not. bool isAllOnesValue() const { if (isSingleWord()) - return VAL == ~integerPart(0) >> (APINT_BITS_PER_WORD - BitWidth); + return VAL == UINT64_MAX >> (APINT_BITS_PER_WORD - BitWidth); return countPopulationSlowCase() == BitWidth; } @@ -406,7 +408,7 @@ public: /// If this value is smaller than the specified limit, return it, otherwise /// return the limit value. This causes the value to saturate to the limit. - uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const { + uint64_t getLimitedValue(uint64_t Limit = UINT64_MAX) const { return (getActiveBits() > 64 || getZExtValue() > Limit) ? Limit : getZExtValue(); } @@ -418,6 +420,36 @@ public: /// width without remainder. bool isSplat(unsigned SplatSizeInBits) const; + /// \returns true if this APInt value is a sequence of \param numBits ones + /// starting at the least significant bit with the remainder zero. + bool isMask(unsigned numBits) const { + assert(numBits != 0 && "numBits must be non-zero"); + assert(numBits <= BitWidth && "numBits out of range"); + if (isSingleWord()) + return VAL == (UINT64_MAX >> (APINT_BITS_PER_WORD - numBits)); + unsigned Ones = countTrailingOnes(); + return (numBits == Ones) && ((Ones + countLeadingZeros()) == BitWidth); + } + + /// \returns true if this APInt is a non-empty sequence of ones starting at + /// the least significant bit with the remainder zero. + /// Ex. isMask(0x0000FFFFU) == true. + bool isMask() const { + if (isSingleWord()) + return isMask_64(VAL); + unsigned Ones = countTrailingOnes(); + return (Ones > 0) && ((Ones + countLeadingZeros()) == BitWidth); + } + + /// \brief Return true if this APInt value contains a sequence of ones with + /// the remainder zero. + bool isShiftedMask() const { + if (isSingleWord()) + return isShiftedMask_64(VAL); + unsigned Ones = countPopulation(); + return (Ones + countTrailingZeros() + countLeadingZeros()) == BitWidth; + } + /// @} /// \name Value Generators /// @{ @@ -501,12 +533,26 @@ public: /// /// \returns An APInt value with the requested bits set. static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit) { - assert(hiBit <= numBits && "hiBit out of range"); - assert(loBit < numBits && "loBit out of range"); - if (hiBit < loBit) - return getLowBitsSet(numBits, hiBit) | - getHighBitsSet(numBits, numBits - loBit); - return getLowBitsSet(numBits, hiBit - loBit).shl(loBit); + APInt Res(numBits, 0); + Res.setBits(loBit, hiBit); + return Res; + } + + /// \brief Get a value with upper bits starting at loBit set. + /// + /// Constructs an APInt value that has a contiguous range of bits set. The + /// bits from loBit (inclusive) to numBits (exclusive) will be set. All other + /// bits will be zero. For example, with parameters(32, 12) you would get + /// 0xFFFFF000. + /// + /// \param numBits the intended bit width of the result + /// \param loBit the index of the lowest bit to set. + /// + /// \returns An APInt value with the requested bits set. + static APInt getBitsSetFrom(unsigned numBits, unsigned loBit) { + APInt Res(numBits, 0); + Res.setBitsFrom(loBit); + return Res; } /// \brief Get a value with high bits set @@ -516,15 +562,9 @@ public: /// \param numBits the bitwidth of the result /// \param hiBitsSet the number of high-order bits set in the result. static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet) { - assert(hiBitsSet <= numBits && "Too many bits to set!"); - // Handle a degenerate case, to avoid shifting by word size - if (hiBitsSet == 0) - return APInt(numBits, 0); - unsigned shiftAmt = numBits - hiBitsSet; - // For small values, return quickly - if (numBits <= APINT_BITS_PER_WORD) - return APInt(numBits, ~0ULL << shiftAmt); - return getAllOnesValue(numBits).shl(shiftAmt); + APInt Res(numBits, 0); + Res.setHighBits(hiBitsSet); + return Res; } /// \brief Get a value with low bits set @@ -534,16 +574,9 @@ public: /// \param numBits the bitwidth of the result /// \param loBitsSet the number of low-order bits set in the result. static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet) { - assert(loBitsSet <= numBits && "Too many bits to set!"); - // Handle a degenerate case, to avoid shifting by word size - if (loBitsSet == 0) - return APInt(numBits, 0); - if (loBitsSet == APINT_BITS_PER_WORD) - return APInt(numBits, UINT64_MAX); - // For small values, return quickly. - if (loBitsSet <= APINT_BITS_PER_WORD) - return APInt(numBits, UINT64_MAX >> (APINT_BITS_PER_WORD - loBitsSet)); - return getAllOnesValue(numBits).lshr(numBits - loBitsSet); + APInt Res(numBits, 0); + Res.setLowBits(loBitsSet); + return Res; } /// \brief Return a value containing V broadcasted over NewLen bits. @@ -587,7 +620,9 @@ public: /// \brief Postfix increment operator. /// - /// \returns a new APInt value representing *this incremented by one + /// Increments *this by 1. + /// + /// \returns a new APInt value representing the original value of *this. const APInt operator++(int) { APInt API(*this); ++(*this); @@ -601,7 +636,9 @@ public: /// \brief Postfix decrement operator. /// - /// \returns a new APInt representing *this decremented by one. + /// Decrements *this by 1. + /// + /// \returns a new APInt value representing the original value of *this. const APInt operator--(int) { APInt API(*this); --(*this); @@ -613,30 +650,13 @@ public: /// \returns *this decremented by one. APInt &operator--(); - /// \brief Unary bitwise complement operator. - /// - /// Performs a bitwise complement operation on this APInt. - /// - /// \returns an APInt that is the bitwise complement of *this - APInt operator~() const { - APInt Result(*this); - Result.flipAllBits(); - return Result; - } - /// \brief Logical negation operator. /// /// Performs logical negation operation on this APInt. /// /// \returns true if *this is zero, false otherwise. bool operator!() const { - if (isSingleWord()) - return !VAL; - - for (unsigned i = 0; i != getNumWords(); ++i) - if (pVal[i]) - return false; - return true; + return *this == 0; } /// @} @@ -688,7 +708,16 @@ public: /// than 64, the value is zero filled in the unspecified high order bits. /// /// \returns *this after assignment of RHS value. - APInt &operator=(uint64_t RHS); + APInt &operator=(uint64_t RHS) { + if (isSingleWord()) { + VAL = RHS; + clearUnusedBits(); + } else { + pVal[0] = RHS; + memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); + } + return *this; + } /// \brief Bitwise AND assignment operator. /// @@ -696,7 +725,29 @@ public: /// assigned to *this. /// /// \returns *this after ANDing with RHS. - APInt &operator&=(const APInt &RHS); + APInt &operator&=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL &= RHS.VAL; + return *this; + } + return AndAssignSlowCase(RHS); + } + + /// \brief Bitwise AND assignment operator. + /// + /// Performs a bitwise AND operation on this APInt and RHS. RHS is + /// logically zero-extended or truncated to match the bit-width of + /// the LHS. + APInt &operator&=(uint64_t RHS) { + if (isSingleWord()) { + VAL &= RHS; + return *this; + } + pVal[0] &= RHS; + memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); + return *this; + } /// \brief Bitwise OR assignment operator. /// @@ -704,7 +755,14 @@ public: /// assigned *this; /// /// \returns *this after ORing with RHS. - APInt &operator|=(const APInt &RHS); + APInt &operator|=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL |= RHS.VAL; + return *this; + } + return OrAssignSlowCase(RHS); + } /// \brief Bitwise OR assignment operator. /// @@ -727,7 +785,29 @@ public: /// assigned to *this. /// /// \returns *this after XORing with RHS. - APInt &operator^=(const APInt &RHS); + APInt &operator^=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) { + VAL ^= RHS.VAL; + return *this; + } + return XorAssignSlowCase(RHS); + } + + /// \brief Bitwise XOR assignment operator. + /// + /// Performs a bitwise XOR operation on this APInt and RHS. RHS is + /// logically zero-extended or truncated to match the bit-width of + /// the LHS. + APInt &operator^=(uint64_t RHS) { + if (isSingleWord()) { + VAL ^= RHS; + clearUnusedBits(); + } else { + pVal[0] ^= RHS; + } + return *this; + } /// \brief Multiplication assignment operator. /// @@ -766,59 +846,6 @@ public: /// \name Binary Operators /// @{ - /// \brief Bitwise AND operator. - /// - /// Performs a bitwise AND operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise AND of *this and RHS. - APInt operator&(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(getBitWidth(), VAL & RHS.VAL); - return AndSlowCase(RHS); - } - APInt And(const APInt &RHS) const { return this->operator&(RHS); } - - /// \brief Bitwise OR operator. - /// - /// Performs a bitwise OR operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise OR of *this and RHS. - APInt operator|(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(getBitWidth(), VAL | RHS.VAL); - return OrSlowCase(RHS); - } - - /// \brief Bitwise OR function. - /// - /// Performs a bitwise or on *this and RHS. This is implemented by simply - /// calling operator|. - /// - /// \returns An APInt value representing the bitwise OR of *this and RHS. - APInt Or(const APInt &RHS) const { return this->operator|(RHS); } - - /// \brief Bitwise XOR operator. - /// - /// Performs a bitwise XOR operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise XOR of *this and RHS. - APInt operator^(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(BitWidth, VAL ^ RHS.VAL); - return XorSlowCase(RHS); - } - - /// \brief Bitwise XOR function. - /// - /// Performs a bitwise XOR operation on *this and RHS. This is implemented - /// through the usage of operator^. - /// - /// \returns An APInt value representing the bitwise XOR of *this and RHS. - APInt Xor(const APInt &RHS) const { return this->operator^(RHS); } - /// \brief Multiplication operator. /// /// Multiplies this APInt by RHS and returns the result. @@ -842,7 +869,14 @@ public: /// \brief Logical right-shift function. /// /// Logical right-shift this APInt by shiftAmt. - APInt lshr(unsigned shiftAmt) const; + APInt lshr(unsigned shiftAmt) const { + APInt R(*this); + R.lshrInPlace(shiftAmt); + return R; + } + + /// Logical right-shift this APInt by shiftAmt in place. + void lshrInPlace(unsigned shiftAmt); /// \brief Left-shift function. /// @@ -1012,7 +1046,7 @@ public: /// the validity of the less-than relationship. /// /// \returns true if *this < RHS when both are considered unsigned. - bool ult(const APInt &RHS) const; + bool ult(const APInt &RHS) const LLVM_READONLY; /// \brief Unsigned less than comparison /// @@ -1030,7 +1064,7 @@ public: /// validity of the less-than relationship. /// /// \returns true if *this < RHS when both are considered signed. - bool slt(const APInt &RHS) const; + bool slt(const APInt &RHS) const LLVM_READONLY; /// \brief Signed less than comparison /// @@ -1144,7 +1178,11 @@ public: /// This operation tests if there are any pairs of corresponding bits /// between this APInt and RHS that are both set. - bool intersects(const APInt &RHS) const { return (*this & RHS) != 0; } + bool intersects(const APInt &RHS) const { + APInt temp(*this); + temp &= RHS; + return temp != 0; + } /// @} /// \name Resizing Operators @@ -1203,11 +1241,9 @@ public: void setAllBits() { if (isSingleWord()) VAL = UINT64_MAX; - else { + else // Set all the bits in all the words. - for (unsigned i = 0; i < getNumWords(); ++i) - pVal[i] = UINT64_MAX; - } + memset(pVal, -1, getNumWords() * APINT_WORD_SIZE); // Clear the unused ones clearUnusedBits(); } @@ -1217,6 +1253,49 @@ public: /// Set the given bit to 1 whose position is given as "bitPosition". void setBit(unsigned bitPosition); + /// Set the sign bit to 1. + void setSignBit() { + setBit(BitWidth - 1); + } + + /// Set the bits from loBit (inclusive) to hiBit (exclusive) to 1. + void setBits(unsigned loBit, unsigned hiBit) { + assert(hiBit <= BitWidth && "hiBit out of range"); + assert(loBit <= BitWidth && "loBit out of range"); + if (loBit == hiBit) + return; + if (loBit > hiBit) { + setLowBits(hiBit); + setHighBits(BitWidth - loBit); + return; + } + if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) { + uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit)); + mask <<= loBit; + if (isSingleWord()) + VAL |= mask; + else + pVal[0] |= mask; + } else { + setBitsSlowCase(loBit, hiBit); + } + } + + /// Set the top bits starting from loBit. + void setBitsFrom(unsigned loBit) { + return setBits(loBit, BitWidth); + } + + /// Set the bottom loBits bits. + void setLowBits(unsigned loBits) { + return setBits(0, loBits); + } + + /// Set the top hiBits bits. + void setHighBits(unsigned hiBits) { + return setBits(BitWidth - hiBits, BitWidth); + } + /// \brief Set every bit to 0. void clearAllBits() { if (isSingleWord()) @@ -1232,13 +1311,12 @@ public: /// \brief Toggle every bit to its opposite value. void flipAllBits() { - if (isSingleWord()) + if (isSingleWord()) { VAL ^= UINT64_MAX; - else { - for (unsigned i = 0; i < getNumWords(); ++i) - pVal[i] ^= UINT64_MAX; + clearUnusedBits(); + } else { + flipAllBitsSlowCase(); } - clearUnusedBits(); } /// \brief Toggles a given bit to its opposite value. @@ -1247,6 +1325,12 @@ public: /// as "bitPosition". void flipBit(unsigned bitPosition); + /// Insert the bits from a smaller APInt starting at bitPosition. + void insertBits(const APInt &SubBits, unsigned bitPosition); + + /// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits). + APInt extractBits(unsigned numBits, unsigned bitPosition) const; + /// @} /// \name Value Characterization Functions /// @{ @@ -1356,7 +1440,7 @@ public: /// /// \returns 0 if the high order bit is not set, otherwise returns the number /// of 1 bits from the most significant to the least - unsigned countLeadingOnes() const; + unsigned countLeadingOnes() const LLVM_READONLY; /// Computes the number of leading bits of this APInt that are equal to its /// sign bit. @@ -1372,7 +1456,7 @@ public: /// /// \returns BitWidth if the value is zero, otherwise returns the number of /// zeros from the least significant bit to the first one bit. - unsigned countTrailingZeros() const; + unsigned countTrailingZeros() const LLVM_READONLY; /// \brief Count the number of trailing one bits. /// @@ -1589,46 +1673,50 @@ public: /// Sets the least significant part of a bignum to the input value, and zeroes /// out higher parts. - static void tcSet(integerPart *, integerPart, unsigned int); + static void tcSet(WordType *, WordType, unsigned); /// Assign one bignum to another. - static void tcAssign(integerPart *, const integerPart *, unsigned int); + static void tcAssign(WordType *, const WordType *, unsigned); /// Returns true if a bignum is zero, false otherwise. - static bool tcIsZero(const integerPart *, unsigned int); + static bool tcIsZero(const WordType *, unsigned); /// Extract the given bit of a bignum; returns 0 or 1. Zero-based. - static int tcExtractBit(const integerPart *, unsigned int bit); + static int tcExtractBit(const WordType *, unsigned bit); /// Copy the bit vector of width srcBITS from SRC, starting at bit srcLSB, to /// DST, of dstCOUNT parts, such that the bit srcLSB becomes the least /// significant bit of DST. All high bits above srcBITS in DST are /// zero-filled. - static void tcExtract(integerPart *, unsigned int dstCount, - const integerPart *, unsigned int srcBits, - unsigned int srcLSB); + static void tcExtract(WordType *, unsigned dstCount, + const WordType *, unsigned srcBits, + unsigned srcLSB); /// Set the given bit of a bignum. Zero-based. - static void tcSetBit(integerPart *, unsigned int bit); + static void tcSetBit(WordType *, unsigned bit); /// Clear the given bit of a bignum. Zero-based. - static void tcClearBit(integerPart *, unsigned int bit); + static void tcClearBit(WordType *, unsigned bit); /// Returns the bit number of the least or most significant set bit of a /// number. If the input number has no bits set -1U is returned. - static unsigned int tcLSB(const integerPart *, unsigned int); - static unsigned int tcMSB(const integerPart *parts, unsigned int n); + static unsigned tcLSB(const WordType *, unsigned n); + static unsigned tcMSB(const WordType *parts, unsigned n); /// Negate a bignum in-place. - static void tcNegate(integerPart *, unsigned int); + static void tcNegate(WordType *, unsigned); /// DST += RHS + CARRY where CARRY is zero or one. Returns the carry flag. - static integerPart tcAdd(integerPart *, const integerPart *, - integerPart carry, unsigned); + static WordType tcAdd(WordType *, const WordType *, + WordType carry, unsigned); + /// DST += RHS. Returns the carry flag. + static WordType tcAddPart(WordType *, WordType, unsigned); /// DST -= RHS + CARRY where CARRY is zero or one. Returns the carry flag. - static integerPart tcSubtract(integerPart *, const integerPart *, - integerPart carry, unsigned); + static WordType tcSubtract(WordType *, const WordType *, + WordType carry, unsigned); + /// DST -= RHS. Returns the carry flag. + static WordType tcSubtractPart(WordType *, WordType, unsigned); /// DST += SRC * MULTIPLIER + PART if add is true /// DST = SRC * MULTIPLIER + PART if add is false @@ -1640,23 +1728,23 @@ public: /// Otherwise DST is filled with the least significant DSTPARTS parts of the /// result, and if all of the omitted higher parts were zero return zero, /// otherwise overflow occurred and return one. - static int tcMultiplyPart(integerPart *dst, const integerPart *src, - integerPart multiplier, integerPart carry, - unsigned int srcParts, unsigned int dstParts, + static int tcMultiplyPart(WordType *dst, const WordType *src, + WordType multiplier, WordType carry, + unsigned srcParts, unsigned dstParts, bool add); /// DST = LHS * RHS, where DST has the same width as the operands and is /// filled with the least significant parts of the result. Returns one if /// overflow occurred, otherwise zero. DST must be disjoint from both /// operands. - static int tcMultiply(integerPart *, const integerPart *, const integerPart *, + static int tcMultiply(WordType *, const WordType *, const WordType *, unsigned); /// DST = LHS * RHS, where DST has width the sum of the widths of the /// operands. No overflow occurs. DST must be disjoint from both /// operands. Returns the number of parts required to hold the result. - static unsigned int tcFullMultiply(integerPart *, const integerPart *, - const integerPart *, unsigned, unsigned); + static unsigned tcFullMultiply(WordType *, const WordType *, + const WordType *, unsigned, unsigned); /// If RHS is zero LHS and REMAINDER are left unchanged, return one. /// Otherwise set LHS to LHS / RHS with the fractional part discarded, set @@ -1667,38 +1755,39 @@ public: /// SCRATCH is a bignum of the same size as the operands and result for use by /// the routine; its contents need not be initialized and are destroyed. LHS, /// REMAINDER and SCRATCH must be distinct. - static int tcDivide(integerPart *lhs, const integerPart *rhs, - integerPart *remainder, integerPart *scratch, - unsigned int parts); + static int tcDivide(WordType *lhs, const WordType *rhs, + WordType *remainder, WordType *scratch, + unsigned parts); /// Shift a bignum left COUNT bits. Shifted in bits are zero. There are no /// restrictions on COUNT. - static void tcShiftLeft(integerPart *, unsigned int parts, - unsigned int count); + static void tcShiftLeft(WordType *, unsigned parts, unsigned count); /// Shift a bignum right COUNT bits. Shifted in bits are zero. There are no /// restrictions on COUNT. - static void tcShiftRight(integerPart *, unsigned int parts, - unsigned int count); + static void tcShiftRight(WordType *, unsigned parts, unsigned count); /// The obvious AND, OR and XOR and complement operations. - static void tcAnd(integerPart *, const integerPart *, unsigned int); - static void tcOr(integerPart *, const integerPart *, unsigned int); - static void tcXor(integerPart *, const integerPart *, unsigned int); - static void tcComplement(integerPart *, unsigned int); + static void tcAnd(WordType *, const WordType *, unsigned); + static void tcOr(WordType *, const WordType *, unsigned); + static void tcXor(WordType *, const WordType *, unsigned); + static void tcComplement(WordType *, unsigned); /// Comparison (unsigned) of two bignums. - static int tcCompare(const integerPart *, const integerPart *, unsigned int); + static int tcCompare(const WordType *, const WordType *, unsigned); /// Increment a bignum in-place. Return the carry flag. - static integerPart tcIncrement(integerPart *, unsigned int); + static WordType tcIncrement(WordType *dst, unsigned parts) { + return tcAddPart(dst, 1, parts); + } /// Decrement a bignum in-place. Return the borrow flag. - static integerPart tcDecrement(integerPart *, unsigned int); + static WordType tcDecrement(WordType *dst, unsigned parts) { + return tcSubtractPart(dst, 1, parts); + } /// Set the least significant BITS and clear the rest. - static void tcSetLeastSignificantBits(integerPart *, unsigned int, - unsigned int bits); + static void tcSetLeastSignificantBits(WordType *, unsigned, unsigned bits); /// \brief debug method void dump() const; @@ -1723,6 +1812,74 @@ inline bool operator==(uint64_t V1, const APInt &V2) { return V2 == V1; } inline bool operator!=(uint64_t V1, const APInt &V2) { return V2 != V1; } +/// \brief Unary bitwise complement operator. +/// +/// \returns an APInt that is the bitwise complement of \p v. +inline APInt operator~(APInt v) { + v.flipAllBits(); + return v; +} + +inline APInt operator&(APInt a, const APInt &b) { + a &= b; + return a; +} + +inline APInt operator&(const APInt &a, APInt &&b) { + b &= a; + return std::move(b); +} + +inline APInt operator&(APInt a, uint64_t RHS) { + a &= RHS; + return a; +} + +inline APInt operator&(uint64_t LHS, APInt b) { + b &= LHS; + return b; +} + +inline APInt operator|(APInt a, const APInt &b) { + a |= b; + return a; +} + +inline APInt operator|(const APInt &a, APInt &&b) { + b |= a; + return std::move(b); +} + +inline APInt operator|(APInt a, uint64_t RHS) { + a |= RHS; + return a; +} + +inline APInt operator|(uint64_t LHS, APInt b) { + b |= LHS; + return b; +} + +inline APInt operator^(APInt a, const APInt &b) { + a ^= b; + return a; +} + +inline APInt operator^(const APInt &a, APInt &&b) { + b ^= a; + return std::move(b); +} + +inline APInt operator^(APInt a, uint64_t RHS) { + a ^= RHS; + return a; +} + +inline APInt operator^(uint64_t LHS, APInt b) { + b ^= LHS; + return b; +} + inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) { I.print(OS, true); return OS; @@ -1799,47 +1956,13 @@ 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); } - -/// \brief Check if the specified APInt has a N-bits signed integer value. -inline bool isSignedIntN(unsigned N, const APInt &APIVal) { - return APIVal.isSignedIntN(N); -} - -/// \returns true if the argument APInt value is a sequence of ones starting at -/// the least significant bit with the remainder zero. -inline bool isMask(unsigned numBits, const APInt &APIVal) { - return numBits <= APIVal.getBitWidth() && - 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) { - return isMask(numBits, (APIVal - APInt(numBits, 1)) | APIVal); -} - -/// \brief Returns a byte-swapped representation of the specified APInt Value. -inline APInt byteSwap(const APInt &APIVal) { return APIVal.byteSwap(); } - -/// \brief Returns the floor log base 2 of the specified APInt value. -inline unsigned logBase2(const APInt &APIVal) { return APIVal.logBase2(); } - -/// \brief Compute GCD of two APInt values. +/// \brief Compute GCD of two unsigned APInt values. /// /// This function returns the greatest common divisor of the two APInt values /// using Euclid's algorithm. /// -/// \returns the greatest common divisor of Val1 and Val2 -APInt GreatestCommonDivisor(const APInt &Val1, const APInt &Val2); +/// \returns the greatest common divisor of A and B. +APInt GreatestCommonDivisor(APInt A, APInt B); /// \brief Converts the given APInt to a double value. /// @@ -1879,83 +2002,6 @@ inline APInt RoundFloatToAPInt(float Float, unsigned width) { return RoundDoubleToAPInt(double(Float), width); } -/// \brief Arithmetic right-shift function. -/// -/// Arithmetic right-shift the APInt by shiftAmt. -inline APInt ashr(const APInt &LHS, unsigned shiftAmt) { - return LHS.ashr(shiftAmt); -} - -/// \brief Logical right-shift function. -/// -/// Logical right-shift the APInt by shiftAmt. -inline APInt lshr(const APInt &LHS, unsigned shiftAmt) { - return LHS.lshr(shiftAmt); -} - -/// \brief Left-shift function. -/// -/// Left-shift the APInt by shiftAmt. -inline APInt shl(const APInt &LHS, unsigned shiftAmt) { - return LHS.shl(shiftAmt); -} - -/// \brief Signed division function for APInt. -/// -/// Signed divide APInt LHS by APInt RHS. -inline APInt sdiv(const APInt &LHS, const APInt &RHS) { return LHS.sdiv(RHS); } - -/// \brief Unsigned division function for APInt. -/// -/// Unsigned divide APInt LHS by APInt RHS. -inline APInt udiv(const APInt &LHS, const APInt &RHS) { return LHS.udiv(RHS); } - -/// \brief Function for signed remainder operation. -/// -/// Signed remainder operation on APInt. -inline APInt srem(const APInt &LHS, const APInt &RHS) { return LHS.srem(RHS); } - -/// \brief Function for unsigned remainder operation. -/// -/// Unsigned remainder operation on APInt. -inline APInt urem(const APInt &LHS, const APInt &RHS) { return LHS.urem(RHS); } - -/// \brief Function for multiplication operation. -/// -/// Performs multiplication on APInt values. -inline APInt mul(const APInt &LHS, const APInt &RHS) { return LHS * RHS; } - -/// \brief Function for addition operation. -/// -/// Performs addition on APInt values. -inline APInt add(const APInt &LHS, const APInt &RHS) { return LHS + RHS; } - -/// \brief Function for subtraction operation. -/// -/// Performs subtraction on APInt values. -inline APInt sub(const APInt &LHS, const APInt &RHS) { return LHS - RHS; } - -/// \brief Bitwise AND function for APInt. -/// -/// Performs bitwise AND operation on APInt LHS and -/// APInt RHS. -inline APInt And(const APInt &LHS, const APInt &RHS) { return LHS & RHS; } - -/// \brief Bitwise OR function for APInt. -/// -/// Performs bitwise OR operation on APInt LHS and APInt RHS. -inline APInt Or(const APInt &LHS, const APInt &RHS) { return LHS | RHS; } - -/// \brief Bitwise XOR function for APInt. -/// -/// Performs bitwise XOR operation on APInt. -inline APInt Xor(const APInt &LHS, const APInt &RHS) { return LHS ^ RHS; } - -/// \brief Bitwise complement function. -/// -/// Performs a bitwise complement operation on APInt. -inline APInt Not(const APInt &APIVal) { return ~APIVal; } - } // End of APIntOps namespace // See friend declaration above. This additional declaration is required in diff --git a/include/llvm/ADT/APSInt.h b/include/llvm/ADT/APSInt.h index 813b3686d6b1..5b6dfa4a4b64 100644 --- a/include/llvm/ADT/APSInt.h +++ b/include/llvm/ADT/APSInt.h @@ -235,19 +235,16 @@ public: assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned); } - APSInt And(const APSInt &RHS) const { return this->operator&(RHS); } APSInt operator|(const APSInt& RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned); } - APSInt Or(const APSInt &RHS) const { return this->operator|(RHS); } APSInt operator^(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned); } - APSInt Xor(const APSInt &RHS) const { return this->operator^(RHS); } APSInt operator*(const APSInt& RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); diff --git a/include/llvm/ADT/ArrayRef.h b/include/llvm/ADT/ArrayRef.h index b3fe31f4a806..6b35d0aec8b2 100644 --- a/include/llvm/ADT/ArrayRef.h +++ b/include/llvm/ADT/ArrayRef.h @@ -487,6 +487,18 @@ namespace llvm { return ArrayRef<T>(Arr); } + /// Construct a MutableArrayRef from a single element. + template<typename T> + MutableArrayRef<T> makeMutableArrayRef(T &OneElt) { + return OneElt; + } + + /// Construct a MutableArrayRef from a pointer and length. + template<typename T> + MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) { + return MutableArrayRef<T>(data, length); + } + /// @} /// @name ArrayRef Comparison Operators /// @{ diff --git a/include/llvm/ADT/BitVector.h b/include/llvm/ADT/BitVector.h index cf3756d0d9c1..8240d01ae977 100644 --- a/include/llvm/ADT/BitVector.h +++ b/include/llvm/ADT/BitVector.h @@ -161,6 +161,17 @@ public: return -1; } + /// find_first_unset - Returns the index of the first unset bit, -1 if all + /// of the bits are set. + int find_first_unset() const { + for (unsigned i = 0; i < NumBitWords(size()); ++i) + if (Bits[i] != ~0UL) { + unsigned Result = i * BITWORD_SIZE + countTrailingOnes(Bits[i]); + return Result < size() ? Result : -1; + } + return -1; + } + /// find_next - 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 { @@ -184,6 +195,30 @@ public: return -1; } + /// find_next_unset - Returns the index of the next usnet bit following the + /// "Prev" bit. Returns -1 if all remaining bits are set. + int find_next_unset(unsigned Prev) const { + ++Prev; + if (Prev >= Size) + return -1; + + unsigned WordPos = Prev / BITWORD_SIZE; + unsigned BitPos = Prev % BITWORD_SIZE; + BitWord Copy = Bits[WordPos]; + // Mask in previous bits. + BitWord Mask = (1 << BitPos) - 1; + Copy |= Mask; + + if (Copy != ~0UL) + return next_unset_in_word(WordPos, Copy); + + // Check subsequent words. + for (unsigned i = WordPos + 1; i < NumBitWords(size()); ++i) + if (Bits[i] != ~0UL) + return next_unset_in_word(i, Bits[i]); + return -1; + } + /// clear - Clear all bits. void clear() { Size = 0; @@ -503,6 +538,11 @@ public: } private: + int next_unset_in_word(int WordIndex, BitWord Word) const { + unsigned Result = WordIndex * BITWORD_SIZE + countTrailingOnes(Word); + return Result < size() ? Result : -1; + } + unsigned NumBitWords(unsigned S) const { return (S + BITWORD_SIZE-1) / BITWORD_SIZE; } @@ -539,7 +579,8 @@ private: } void init_words(BitWord *B, unsigned NumWords, bool t) { - memset(B, 0 - (int)t, NumWords*sizeof(BitWord)); + if (NumWords > 0) + memset(B, 0 - (int)t, NumWords*sizeof(BitWord)); } template<bool AddBits, bool InvertMask> diff --git a/include/llvm/ADT/BreadthFirstIterator.h b/include/llvm/ADT/BreadthFirstIterator.h new file mode 100644 index 000000000000..eaeecb6e057f --- /dev/null +++ b/include/llvm/ADT/BreadthFirstIterator.h @@ -0,0 +1,164 @@ +//===- llvm/ADT/BreadthFirstIterator.h - Breadth First iterator -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file builds on the ADT/GraphTraits.h file to build a generic breadth +// first graph iterator. This file exposes the following functions/types: +// +// bf_begin/bf_end/bf_iterator +// * Normal breadth-first iteration - visit a graph level-by-level. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BREADTHFIRSTITERATOR_H +#define LLVM_ADT_BREADTHFIRSTITERATOR_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/iterator_range.h" +#include <iterator> +#include <queue> +#include <set> +#include <utility> + +namespace llvm { + +// bf_iterator_storage - A private class which is used to figure out where to +// store the visited set. We only provide a non-external variant for now. +template <class SetType> class bf_iterator_storage { +public: + SetType Visited; +}; + +// The visited state for the iteration is a simple set. +template <typename NodeRef, unsigned SmallSize = 8> +using bf_iterator_default_set = SmallPtrSet<NodeRef, SmallSize>; + +// Generic Breadth first search iterator. +template <class GraphT, + class SetType = + bf_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>, + class GT = GraphTraits<GraphT>> +class bf_iterator + : public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>, + public bf_iterator_storage<SetType> { + typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super; + + typedef typename GT::NodeRef NodeRef; + typedef typename GT::ChildIteratorType ChildItTy; + + // First element is the node reference, second is the next child to visit. + typedef std::pair<NodeRef, Optional<ChildItTy>> QueueElement; + + // Visit queue - used to maintain BFS ordering. + // Optional<> because we need markers for levels. + std::queue<Optional<QueueElement>> VisitQueue; + + // Current level. + unsigned Level; + +private: + inline bf_iterator(NodeRef Node) { + this->Visited.insert(Node); + Level = 0; + + // Also, insert a dummy node as marker. + VisitQueue.push(QueueElement(Node, None)); + VisitQueue.push(None); + } + + inline bf_iterator() = default; + + inline void toNext() { + Optional<QueueElement> Head = VisitQueue.front(); + QueueElement H = Head.getValue(); + NodeRef Node = H.first; + Optional<ChildItTy> &ChildIt = H.second; + + if (!ChildIt) + ChildIt.emplace(GT::child_begin(Node)); + while (*ChildIt != GT::child_end(Node)) { + NodeRef Next = *(*ChildIt)++; + + // Already visited? + if (this->Visited.insert(Next).second) + VisitQueue.push(QueueElement(Next, None)); + } + VisitQueue.pop(); + + // Go to the next element skipping markers if needed. + if (!VisitQueue.empty()) { + Head = VisitQueue.front(); + if (Head != None) + return; + Level += 1; + VisitQueue.pop(); + + // Don't push another marker if this is the last + // element. + if (!VisitQueue.empty()) + VisitQueue.push(None); + } + } + +public: + typedef typename super::pointer pointer; + + // Provide static begin and end methods as our public "constructors" + static bf_iterator begin(const GraphT &G) { + return bf_iterator(GT::getEntryNode(G)); + } + + static bf_iterator end(const GraphT &G) { return bf_iterator(); } + + bool operator==(const bf_iterator &RHS) const { + return VisitQueue == RHS.VisitQueue; + } + + bool operator!=(const bf_iterator &RHS) const { return !(*this == RHS); } + + const NodeRef &operator*() const { return VisitQueue.front()->first; } + + // This is a nonstandard operator-> that dereferenfces the pointer an extra + // time so that you can actually call methods on the node, because the + // contained type is a pointer. + NodeRef operator->() const { return **this; } + + bf_iterator &operator++() { // Pre-increment + toNext(); + return *this; + } + + bf_iterator operator++(int) { // Post-increment + bf_iterator ItCopy = *this; + ++*this; + return ItCopy; + } + + unsigned getLevel() const { return Level; } +}; + +// Provide global constructors that automatically figure out correct types. +template <class T> bf_iterator<T> bf_begin(const T &G) { + return bf_iterator<T>::begin(G); +} + +template <class T> bf_iterator<T> bf_end(const T &G) { + return bf_iterator<T>::end(G); +} + +// Provide an accessor method to use them in range-based patterns. +template <class T> iterator_range<bf_iterator<T>> breadth_first(const T &G) { + return make_range(bf_begin(G), bf_end(G)); +} + +} // end namespace llvm + +#endif // LLVM_ADT_BREADTHFIRSTITERATOR_H diff --git a/include/llvm/ADT/DenseMap.h b/include/llvm/ADT/DenseMap.h index 0b4b09d4b733..fd8d3bf368a8 100644 --- a/include/llvm/ADT/DenseMap.h +++ b/include/llvm/ADT/DenseMap.h @@ -53,6 +53,9 @@ class DenseMapIterator; template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, typename BucketT> class DenseMapBase : public DebugEpochBase { + template <typename T> + using const_arg_type_t = typename const_pointer_or_const_ref<T>::type; + public: typedef unsigned size_type; typedef KeyT key_type; @@ -119,18 +122,18 @@ public: } /// Return 1 if the specified key is in the map, 0 otherwise. - size_type count(const KeyT &Val) const { + size_type count(const_arg_type_t<KeyT> Val) const { const BucketT *TheBucket; return LookupBucketFor(Val, TheBucket) ? 1 : 0; } - iterator find(const KeyT &Val) { + iterator find(const_arg_type_t<KeyT> Val) { BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return iterator(TheBucket, getBucketsEnd(), *this, true); return end(); } - const_iterator find(const KeyT &Val) const { + const_iterator find(const_arg_type_t<KeyT> Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return const_iterator(TheBucket, getBucketsEnd(), *this, true); @@ -159,7 +162,7 @@ public: /// lookup - Return the entry for the specified key, or a default /// constructed value if no such entry exists. - ValueT lookup(const KeyT &Val) const { + ValueT lookup(const_arg_type_t<KeyT> Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return TheBucket->getSecond(); @@ -389,6 +392,8 @@ protected: return KeyInfoT::getHashValue(Val); } static const KeyT getEmptyKey() { + static_assert(std::is_base_of<DenseMapBase, DerivedT>::value, + "Must pass the derived type to this template!"); return KeyInfoT::getEmptyKey(); } static const KeyT getTombstoneKey() { diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index a844ebcccf5b..bb973ac65063 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -60,6 +60,16 @@ template<> struct DenseMapInfo<char> { } }; +// Provide DenseMapInfo for unsigned shorts. +template <> struct DenseMapInfo<unsigned short> { + static inline unsigned short getEmptyKey() { return 0xFFFF; } + static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; } + static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; } + static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) { + return LHS == RHS; + } +}; + // Provide DenseMapInfo for unsigned ints. template<> struct DenseMapInfo<unsigned> { static inline unsigned getEmptyKey() { return ~0U; } @@ -95,6 +105,14 @@ template<> struct DenseMapInfo<unsigned long long> { } }; +// Provide DenseMapInfo for shorts. +template <> struct DenseMapInfo<short> { + static inline short getEmptyKey() { return 0x7FFF; } + static inline short getTombstoneKey() { return -0x7FFF - 1; } + static unsigned getHashValue(const short &Val) { return Val * 37U; } + static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; } +}; + // Provide DenseMapInfo for ints. template<> struct DenseMapInfo<int> { static inline int getEmptyKey() { return 0x7fffffff; } diff --git a/include/llvm/ADT/DenseSet.h b/include/llvm/ADT/DenseSet.h index b25d3b7cba6f..fcf304c3ecc4 100644 --- a/include/llvm/ADT/DenseSet.h +++ b/include/llvm/ADT/DenseSet.h @@ -48,6 +48,8 @@ class DenseSetImpl { static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT), "DenseMap buckets unexpectedly large!"); MapTy TheMap; + template <typename T> + using const_arg_type_t = typename const_pointer_or_const_ref<T>::type; public: typedef ValueT key_type; @@ -78,7 +80,7 @@ public: } /// Return 1 if the specified key is in the set, 0 otherwise. - size_type count(const ValueT &V) const { + size_type count(const_arg_type_t<ValueT> V) const { return TheMap.count(V); } @@ -90,9 +92,12 @@ public: // Iterators. + class ConstIterator; + class Iterator { typename MapTy::iterator I; friend class DenseSetImpl; + friend class ConstIterator; public: typedef typename MapTy::iterator::difference_type difference_type; @@ -101,20 +106,24 @@ public: typedef value_type &reference; typedef std::forward_iterator_tag iterator_category; + Iterator() = default; Iterator(const typename MapTy::iterator &i) : I(i) {} ValueT &operator*() { return I->getFirst(); } + const ValueT &operator*() const { return I->getFirst(); } ValueT *operator->() { return &I->getFirst(); } + const ValueT *operator->() const { 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; } + bool operator==(const ConstIterator& X) const { return I == X.I; } + bool operator!=(const ConstIterator& X) const { return I != X.I; } }; class ConstIterator { typename MapTy::const_iterator I; friend class DenseSet; + friend class Iterator; public: typedef typename MapTy::const_iterator::difference_type difference_type; @@ -123,10 +132,14 @@ public: typedef value_type &reference; typedef std::forward_iterator_tag iterator_category; + ConstIterator(const Iterator &B) : I(B.I) {} + + ConstIterator() = default; + ConstIterator(const typename MapTy::const_iterator &i) : I(i) {} - const ValueT &operator*() { return I->getFirst(); } - const ValueT *operator->() { return &I->getFirst(); } + const ValueT &operator*() const { return I->getFirst(); } + const ValueT *operator->() const { return &I->getFirst(); } ConstIterator& operator++() { ++I; return *this; } ConstIterator operator++(int) { auto T = *this; ++I; return T; } @@ -143,8 +156,8 @@ public: const_iterator begin() const { return ConstIterator(TheMap.begin()); } const_iterator end() const { return ConstIterator(TheMap.end()); } - iterator find(const ValueT &V) { return Iterator(TheMap.find(V)); } - const_iterator find(const ValueT &V) const { + iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); } + const_iterator find(const_arg_type_t<ValueT> V) const { return ConstIterator(TheMap.find(V)); } diff --git a/include/llvm/ADT/DepthFirstIterator.h b/include/llvm/ADT/DepthFirstIterator.h index c54573204588..b020d48cb3f0 100644 --- a/include/llvm/ADT/DepthFirstIterator.h +++ b/include/llvm/ADT/DepthFirstIterator.h @@ -135,7 +135,7 @@ private: } } this->Visited.completed(Node); - + // Oops, ran out of successors... go up a level on the stack. VisitStack.pop_back(); } while (!VisitStack.empty()); diff --git a/include/llvm/ADT/GraphTraits.h b/include/llvm/ADT/GraphTraits.h index 29bbcb010eee..2c88c4271b48 100644 --- a/include/llvm/ADT/GraphTraits.h +++ b/include/llvm/ADT/GraphTraits.h @@ -18,6 +18,8 @@ #ifndef LLVM_ADT_GRAPHTRAITS_H #define LLVM_ADT_GRAPHTRAITS_H +#include "llvm/ADT/iterator_range.h" + namespace llvm { // GraphTraits - This class should be specialized by different graph types... @@ -86,6 +88,33 @@ struct Inverse { // inverse falls back to the original graph. template <class T> struct GraphTraits<Inverse<Inverse<T>>> : GraphTraits<T> {}; +// Provide iterator ranges for the graph traits nodes and children +template <class GraphType> +iterator_range<typename GraphTraits<GraphType>::nodes_iterator> +nodes(const GraphType &G) { + return make_range(GraphTraits<GraphType>::nodes_begin(G), + GraphTraits<GraphType>::nodes_end(G)); +} +template <class GraphType> +iterator_range<typename GraphTraits<Inverse<GraphType>>::nodes_iterator> +inverse_nodes(const GraphType &G) { + return make_range(GraphTraits<Inverse<GraphType>>::nodes_begin(G), + GraphTraits<Inverse<GraphType>>::nodes_end(G)); +} + +template <class GraphType> +iterator_range<typename GraphTraits<GraphType>::ChildIteratorType> +children(const typename GraphTraits<GraphType>::NodeRef &G) { + return make_range(GraphTraits<GraphType>::child_begin(G), + GraphTraits<GraphType>::child_end(G)); +} + +template <class GraphType> +iterator_range<typename GraphTraits<Inverse<GraphType>>::ChildIteratorType> +inverse_children(const typename GraphTraits<GraphType>::NodeRef &G) { + return make_range(GraphTraits<Inverse<GraphType>>::child_begin(G), + GraphTraits<Inverse<GraphType>>::child_end(G)); +} } // End llvm namespace #endif diff --git a/include/llvm/ADT/None.h b/include/llvm/ADT/None.h index d69ec17c15f9..c7a99c61994e 100644 --- a/include/llvm/ADT/None.h +++ b/include/llvm/ADT/None.h @@ -19,8 +19,9 @@ namespace llvm { /// \brief A simple null object to allow implicit construction of Optional<T> /// and similar types without having to spell out the specialization's name. -enum class NoneType { None }; -const NoneType None = None; +// (constant value 1 in an attempt to workaround MSVC build issue... ) +enum class NoneType { None = 1 }; +const NoneType None = NoneType::None; } #endif diff --git a/include/llvm/ADT/PointerUnion.h b/include/llvm/ADT/PointerUnion.h index a8ac18645f3a..9eb15524c0f3 100644 --- a/include/llvm/ADT/PointerUnion.h +++ b/include/llvm/ADT/PointerUnion.h @@ -31,7 +31,7 @@ template <typename T> struct PointerUnionTypeSelectorReturn { /// Get a type based on whether two types are the same or not. /// /// For: -/// +/// /// \code /// typedef typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return Ret; /// \endcode @@ -190,17 +190,17 @@ public: }; template <typename PT1, typename PT2> -static bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { +bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { return lhs.getOpaqueValue() == rhs.getOpaqueValue(); } template <typename PT1, typename PT2> -static bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { +bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { return lhs.getOpaqueValue() != rhs.getOpaqueValue(); } template <typename PT1, typename PT2> -static bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { +bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) { return lhs.getOpaqueValue() < rhs.getOpaqueValue(); } diff --git a/include/llvm/ADT/PostOrderIterator.h b/include/llvm/ADT/PostOrderIterator.h index e519b5c07964..8fc08eb252eb 100644 --- a/include/llvm/ADT/PostOrderIterator.h +++ b/include/llvm/ADT/PostOrderIterator.h @@ -268,6 +268,10 @@ inverse_post_order_ext(const T &G, SetType &S) { // with a postorder iterator to build the data structures). The moral of this // story is: Don't create more ReversePostOrderTraversal classes than necessary. // +// Because it does the traversal in its constructor, it won't invalidate when +// BasicBlocks are removed, *but* it may contain erased blocks. Some places +// rely on this behavior (i.e. GVN). +// // This class should be used like this: // { // ReversePostOrderTraversal<Function*> RPOT(FuncPtr); // Expensive to create diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index ec121e0d55cd..15945adbe589 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -23,11 +23,13 @@ #include <cstdlib> // for qsort #include <functional> #include <iterator> +#include <limits> #include <memory> #include <tuple> #include <utility> // for std::pair #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" @@ -44,6 +46,10 @@ namespace detail { template <typename RangeT> using IterOfRange = decltype(std::begin(std::declval<RangeT &>())); +template <typename RangeT> +using ValueOfRange = typename std::remove_reference<decltype( + *std::begin(std::declval<RangeT &>()))>::type; + } // End detail namespace //===----------------------------------------------------------------------===// @@ -123,7 +129,7 @@ inline void deleter(T *Ptr) { //===----------------------------------------------------------------------===// // mapped_iterator - This is a simple iterator adapter that causes a function to -// be dereferenced whenever operator* is invoked on the iterator. +// be applied whenever operator* is invoked on the iterator. // template <class RootIt, class UnaryFunc> class mapped_iterator { @@ -134,9 +140,8 @@ public: iterator_category; typedef typename std::iterator_traits<RootIt>::difference_type difference_type; - typedef typename std::result_of< - UnaryFunc(decltype(*std::declval<RootIt>()))> - ::type value_type; + typedef decltype(std::declval<UnaryFunc>()(*std::declval<RootIt>())) + value_type; typedef void pointer; //typedef typename UnaryFunc::result_type *pointer; @@ -356,65 +361,126 @@ template <size_t... I> struct index_sequence; template <class... Ts> struct index_sequence_for; namespace detail { -template <typename... Iters> class zip_first { -public: - typedef std::input_iterator_tag iterator_category; - typedef std::tuple<decltype(*std::declval<Iters>())...> value_type; +using std::declval; + +// We have to alias this since inlining the actual type at the usage site +// in the parameter list of iterator_facade_base<> below ICEs MSVC 2017. +template<typename... Iters> struct ZipTupleType { + typedef std::tuple<decltype(*declval<Iters>())...> type; +}; + +template <typename ZipType, typename... Iters> +using zip_traits = iterator_facade_base< + ZipType, typename std::common_type<std::bidirectional_iterator_tag, + typename std::iterator_traits< + Iters>::iterator_category...>::type, + // ^ TODO: Implement random access methods. + typename ZipTupleType<Iters...>::type, + typename std::iterator_traits<typename std::tuple_element< + 0, std::tuple<Iters...>>::type>::difference_type, + // ^ FIXME: This follows boost::make_zip_iterator's assumption that all + // inner iterators have the same difference_type. It would fail if, for + // instance, the second field's difference_type were non-numeric while the + // first is. + typename ZipTupleType<Iters...>::type *, + typename ZipTupleType<Iters...>::type>; + +template <typename ZipType, typename... Iters> +struct zip_common : public zip_traits<ZipType, Iters...> { + using Base = zip_traits<ZipType, Iters...>; + using value_type = typename Base::value_type; + std::tuple<Iters...> iterators; -private: - template <size_t... Ns> value_type deres(index_sequence<Ns...>) { +protected: + template <size_t... Ns> value_type deref(index_sequence<Ns...>) const { return value_type(*std::get<Ns>(iterators)...); } - template <size_t... Ns> decltype(iterators) tup_inc(index_sequence<Ns...>) { + template <size_t... Ns> + decltype(iterators) tup_inc(index_sequence<Ns...>) const { return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...); } + template <size_t... Ns> + decltype(iterators) tup_dec(index_sequence<Ns...>) const { + return std::tuple<Iters...>(std::prev(std::get<Ns>(iterators))...); + } + public: - value_type operator*() { return deres(index_sequence_for<Iters...>{}); } + zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {} + + value_type operator*() { return deref(index_sequence_for<Iters...>{}); } - void operator++() { iterators = tup_inc(index_sequence_for<Iters...>{}); } + const value_type operator*() const { + return deref(index_sequence_for<Iters...>{}); + } - bool operator!=(const zip_first<Iters...> &other) const { - return std::get<0>(iterators) != std::get<0>(other.iterators); + ZipType &operator++() { + iterators = tup_inc(index_sequence_for<Iters...>{}); + return *reinterpret_cast<ZipType *>(this); } - zip_first(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {} + + ZipType &operator--() { + static_assert(Base::IsBidirectional, + "All inner iterators must be at least bidirectional."); + iterators = tup_dec(index_sequence_for<Iters...>{}); + return *reinterpret_cast<ZipType *>(this); + } +}; + +template <typename... Iters> +struct zip_first : public zip_common<zip_first<Iters...>, Iters...> { + using Base = zip_common<zip_first<Iters...>, Iters...>; + + bool operator==(const zip_first<Iters...> &other) const { + return std::get<0>(this->iterators) == std::get<0>(other.iterators); + } + + zip_first(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {} }; -template <typename... Iters> class zip_shortest : public zip_first<Iters...> { +template <typename... Iters> +class zip_shortest : public zip_common<zip_shortest<Iters...>, Iters...> { template <size_t... Ns> - bool test(const zip_first<Iters...> &other, index_sequence<Ns...>) const { + bool test(const zip_shortest<Iters...> &other, index_sequence<Ns...>) const { return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) != std::get<Ns>(other.iterators)...}, identity<bool>{}); } public: - bool operator!=(const zip_first<Iters...> &other) const { - return test(other, index_sequence_for<Iters...>{}); + using Base = zip_common<zip_shortest<Iters...>, Iters...>; + + bool operator==(const zip_shortest<Iters...> &other) const { + return !test(other, index_sequence_for<Iters...>{}); } - zip_shortest(Iters &&... ts) - : zip_first<Iters...>(std::forward<Iters>(ts)...) {} + + zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {} }; template <template <typename...> class ItType, typename... Args> class zippy { public: - typedef ItType<decltype(std::begin(std::declval<Args>()))...> iterator; + using iterator = ItType<decltype(std::begin(std::declval<Args>()))...>; + using iterator_category = typename iterator::iterator_category; + using value_type = typename iterator::value_type; + using difference_type = typename iterator::difference_type; + using pointer = typename iterator::pointer; + using reference = typename iterator::reference; private: std::tuple<Args...> ts; - template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) { + template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const { return iterator(std::begin(std::get<Ns>(ts))...); } - template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) { + template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const { return iterator(std::end(std::get<Ns>(ts))...); } public: - iterator begin() { return begin_impl(index_sequence_for<Args...>{}); } - iterator end() { return end_impl(index_sequence_for<Args...>{}); } + iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); } + iterator end() const { return end_impl(index_sequence_for<Args...>{}); } zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {} }; } // End detail namespace @@ -777,6 +843,13 @@ auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { return std::remove_if(std::begin(Range), std::end(Range), P); } +/// Provide wrappers to std::copy_if which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename OutputIt, typename UnaryPredicate> +OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) { + return std::copy_if(std::begin(Range), std::end(Range), Out, P); +} + /// Wrapper function around std::find to detect if an element exists /// in a container. template <typename R, typename E> @@ -815,6 +888,15 @@ auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { return std::partition(std::begin(Range), std::end(Range), P); } +/// \brief Given a range of type R, iterate the entire range and return a +/// SmallVector with elements of the vector. This is useful, for example, +/// when you want to iterate a range and then sort the results. +template <unsigned Size, typename R> +SmallVector<typename std::remove_const<detail::ValueOfRange<R>>::type, Size> +to_vector(R &&Range) { + return {std::begin(Range), std::end(Range)}; +} + /// Provide a container algorithm similar to C++ Library Fundamentals v2's /// `erase_if` which is equivalent to: /// @@ -909,47 +991,85 @@ template <typename T> struct deref { }; namespace detail { -template <typename R> class enumerator_impl { -public: - template <typename X> struct result_pair { - result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {} +template <typename R> class enumerator_iter; - const std::size_t Index; - X Value; - }; +template <typename R> struct result_pair { + friend class enumerator_iter<R>; + + result_pair() : Index(-1) {} + result_pair(std::size_t Index, IterOfRange<R> Iter) + : Index(Index), Iter(Iter) {} - class iterator { - typedef - typename std::iterator_traits<IterOfRange<R>>::reference iter_reference; - typedef result_pair<iter_reference> result_type; + result_pair<R> &operator=(const result_pair<R> &Other) { + Index = Other.Index; + Iter = Other.Iter; + return *this; + } - public: - iterator(IterOfRange<R> &&Iter, std::size_t Index) - : Iter(Iter), Index(Index) {} + std::size_t index() const { return Index; } + const ValueOfRange<R> &value() const { return *Iter; } + ValueOfRange<R> &value() { return *Iter; } - result_type operator*() const { return result_type(Index, *Iter); } +private: + std::size_t Index; + IterOfRange<R> Iter; +}; - iterator &operator++() { - ++Iter; - ++Index; - return *this; - } +template <typename R> +class enumerator_iter + : public iterator_facade_base< + enumerator_iter<R>, std::forward_iterator_tag, result_pair<R>, + typename std::iterator_traits<IterOfRange<R>>::difference_type, + typename std::iterator_traits<IterOfRange<R>>::pointer, + typename std::iterator_traits<IterOfRange<R>>::reference> { + using result_type = result_pair<R>; - bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; } +public: + explicit enumerator_iter(IterOfRange<R> EndIter) + : Result(std::numeric_limits<size_t>::max(), EndIter) { } - private: - IterOfRange<R> Iter; - std::size_t Index; - }; + enumerator_iter(std::size_t Index, IterOfRange<R> Iter) + : Result(Index, Iter) {} + + result_type &operator*() { return Result; } + const result_type &operator*() const { return Result; } + enumerator_iter<R> &operator++() { + assert(Result.Index != std::numeric_limits<size_t>::max()); + ++Result.Iter; + ++Result.Index; + return *this; + } + + bool operator==(const enumerator_iter<R> &RHS) const { + // Don't compare indices here, only iterators. It's possible for an end + // iterator to have different indices depending on whether it was created + // by calling std::end() versus incrementing a valid iterator. + return Result.Iter == RHS.Result.Iter; + } + + enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) { + Result = Other.Result; + return *this; + } + +private: + result_type Result; +}; + +template <typename R> class enumerator { public: - explicit enumerator_impl(R &&Range) : Range(std::forward<R>(Range)) {} + explicit enumerator(R &&Range) : TheRange(std::forward<R>(Range)) {} - iterator begin() { return iterator(std::begin(Range), 0); } - iterator end() { return iterator(std::end(Range), std::size_t(-1)); } + enumerator_iter<R> begin() { + return enumerator_iter<R>(0, std::begin(TheRange)); + } + enumerator_iter<R> end() { + return enumerator_iter<R>(std::end(TheRange)); + } private: - R Range; + R TheRange; }; } @@ -968,8 +1088,8 @@ private: /// Item 2 - C /// Item 3 - D /// -template <typename R> detail::enumerator_impl<R> enumerate(R &&Range) { - return detail::enumerator_impl<R>(std::forward<R>(Range)); +template <typename R> detail::enumerator<R> enumerate(R &&TheRange) { + return detail::enumerator<R>(std::forward<R>(TheRange)); } namespace detail { diff --git a/include/llvm/ADT/ScopedHashTable.h b/include/llvm/ADT/ScopedHashTable.h index ad805b0991c1..d52128e294a3 100644 --- a/include/llvm/ADT/ScopedHashTable.h +++ b/include/llvm/ADT/ScopedHashTable.h @@ -182,8 +182,8 @@ public: return TopLevelMap.count(Key); } - V lookup(const K &Key) { - typename DenseMap<K, ValTy*, KInfo>::iterator I = TopLevelMap.find(Key); + V lookup(const K &Key) const { + auto I = TopLevelMap.find(Key); if (I != TopLevelMap.end()) return I->second->getValue(); diff --git a/include/llvm/ADT/SetVector.h b/include/llvm/ADT/SetVector.h index 4dc18bc52178..13378aa3a04e 100644 --- a/include/llvm/ADT/SetVector.h +++ b/include/llvm/ADT/SetVector.h @@ -119,6 +119,12 @@ public: return vector_.rend(); } + /// \brief Return the first element of the SetVector. + const T &front() const { + assert(!empty() && "Cannot call front() on empty SetVector!"); + return vector_.front(); + } + /// \brief Return the last element of the SetVector. const T &back() const { assert(!empty() && "Cannot call back() on empty SetVector!"); @@ -232,7 +238,7 @@ 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. diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h index bb99e0cf221f..edb37da38da1 100644 --- a/include/llvm/ADT/SmallBitVector.h +++ b/include/llvm/ADT/SmallBitVector.h @@ -216,6 +216,18 @@ public: return getPointer()->find_first(); } + /// Returns the index of the first unset bit, -1 if all of the bits are set. + int find_first_unset() const { + if (isSmall()) { + if (count() == getSmallSize()) + return -1; + + uintptr_t Bits = getSmallBits(); + return countTrailingOnes(Bits); + } + return getPointer()->find_first_unset(); + } + /// 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 { @@ -230,6 +242,23 @@ public: return getPointer()->find_next(Prev); } + /// Returns the index of the next unset bit following the "Prev" bit. + /// Returns -1 if the next unset bit is not found. + int find_next_unset(unsigned Prev) const { + if (isSmall()) { + ++Prev; + uintptr_t Bits = getSmallBits(); + // Mask in previous bits. + uintptr_t Mask = (1 << Prev) - 1; + Bits |= Mask; + + if (Bits == ~uintptr_t(0) || Prev + 1 >= getSmallSize()) + return -1; + return countTrailingOnes(Bits); + } + return getPointer()->find_next_unset(Prev); + } + /// Clear all bits. void clear() { if (!isSmall()) diff --git a/include/llvm/ADT/SmallPtrSet.h b/include/llvm/ADT/SmallPtrSet.h index 49feb9da897a..196ab6338047 100644 --- a/include/llvm/ADT/SmallPtrSet.h +++ b/include/llvm/ADT/SmallPtrSet.h @@ -18,6 +18,7 @@ #include "llvm/Config/abi-breaking.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/type_traits.h" #include <cassert> #include <cstddef> #include <cstring> @@ -166,8 +167,8 @@ protected: const void *const *P = find_imp(Ptr); if (P == EndPointer()) return false; - - const void ** Loc = const_cast<const void **>(P); + + const void **Loc = const_cast<const void **>(P); assert(*Loc == Ptr && "broken find!"); *Loc = getTombstoneMarker(); NumTombstones++; @@ -193,7 +194,7 @@ protected: return Bucket; return EndPointer(); } - + private: bool isSmall() const { return CurArray == SmallArray; } @@ -259,11 +260,10 @@ protected: } #if LLVM_ENABLE_ABI_BREAKING_CHECKS void RetreatIfNotValid() { - --Bucket; - assert(Bucket <= End); + assert(Bucket >= End); while (Bucket != End && - (*Bucket == SmallPtrSetImplBase::getEmptyMarker() || - *Bucket == SmallPtrSetImplBase::getTombstoneMarker())) { + (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() || + Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) { --Bucket; } } @@ -288,6 +288,12 @@ public: // Most methods provided by baseclass. const PtrTy operator*() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate<bool>::value) { + assert(Bucket > End); + return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1])); + } +#endif assert(Bucket < End); return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket)); } @@ -295,6 +301,7 @@ public: inline SmallPtrSetIterator& operator++() { // Preincrement #if LLVM_ENABLE_ABI_BREAKING_CHECKS if (ReverseIterate<bool>::value) { + --Bucket; RetreatIfNotValid(); return *this; } @@ -343,7 +350,9 @@ struct RoundUpToPowerOfTwo { /// to avoid encoding a particular small size in the interface boundary. template <typename PtrType> class SmallPtrSetImpl : public SmallPtrSetImplBase { + using ConstPtrType = typename add_const_past_pointer<PtrType>::type; typedef PointerLikeTypeTraits<PtrType> PtrTraits; + typedef PointerLikeTypeTraits<ConstPtrType> ConstPtrTraits; protected: // Constructors that forward to the base. @@ -367,7 +376,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, EndPointer()), p.second); + return std::make_pair(makeIterator(p.first), p.second); } /// erase - If the set contains the specified pointer, remove it and return @@ -375,14 +384,10 @@ public: bool erase(PtrType Ptr) { return erase_imp(PtrTraits::getAsVoidPointer(Ptr)); } - /// count - Return 1 if the specified pointer is in the set, 0 otherwise. - size_type count(PtrType Ptr) const { - return find(Ptr) != endPtr() ? 1 : 0; - } - iterator find(PtrType Ptr) const { - auto *P = find_imp(PtrTraits::getAsVoidPointer(Ptr)); - return iterator(P, EndPointer()); + size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; } + iterator find(ConstPtrType Ptr) const { + return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr))); } template <typename IterT> @@ -395,25 +400,23 @@ public: insert(IL.begin(), IL.end()); } - inline iterator begin() const { + iterator begin() const { #if LLVM_ENABLE_ABI_BREAKING_CHECKS if (ReverseIterate<bool>::value) - return endPtr(); + return makeIterator(EndPointer() - 1); #endif - return iterator(CurArray, EndPointer()); + return makeIterator(CurArray); } - inline iterator end() const { + iterator end() const { return makeIterator(EndPointer()); } + +private: + /// Create an iterator that dereferences to same place as the given pointer. + iterator makeIterator(const void *const *P) const { #if LLVM_ENABLE_ABI_BREAKING_CHECKS if (ReverseIterate<bool>::value) - return iterator(CurArray, CurArray); + return iterator(P == EndPointer() ? CurArray : P + 1, CurArray); #endif - return endPtr(); - } - -private: - inline iterator endPtr() const { - const void *const *End = EndPointer(); - return iterator(End, End); + return iterator(P, EndPointer()); } }; diff --git a/include/llvm/ADT/SparseBitVector.h b/include/llvm/ADT/SparseBitVector.h index e2822c46e266..a82cef6028f9 100644 --- a/include/llvm/ADT/SparseBitVector.h +++ b/include/llvm/ADT/SparseBitVector.h @@ -132,6 +132,17 @@ public: llvm_unreachable("Illegal empty element"); } + /// find_last - Returns the index of the last set bit. + int find_last() const { + for (unsigned I = 0; I < BITWORDS_PER_ELEMENT; ++I) { + unsigned Idx = BITWORDS_PER_ELEMENT - I - 1; + if (Bits[Idx] != 0) + return Idx * BITWORD_SIZE + BITWORD_SIZE - + countLeadingZeros(Bits[Idx]) - 1; + } + llvm_unreachable("Illegal empty element"); + } + /// find_next - Returns the index of the next set bit starting from the /// "Curr" bit. Returns -1 if the next set bit is not found. int find_next(unsigned Curr) const { @@ -768,6 +779,14 @@ public: return (First.index() * ElementSize) + First.find_first(); } + // Return the last set bit in the bitmap. Return -1 if no bits are set. + int find_last() const { + if (Elements.empty()) + return -1; + const SparseBitVectorElement<ElementSize> &Last = *(Elements.rbegin()); + return (Last.index() * ElementSize) + Last.find_last(); + } + // Return true if the SparseBitVector is empty bool empty() const { return Elements.empty(); diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index 488748a5f605..8214782bfe80 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -234,6 +234,13 @@ inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) { return detail::join_impl(Begin, End, Separator, tag()); } +/// Joins the strings in the range [R.begin(), R.end()), adding Separator +/// between the elements. +template <typename Range> +inline std::string join(Range &&R, StringRef Separator) { + return join(R.begin(), R.end(), Separator); +} + /// Joins the strings in the parameter pack \p Items, adding \p Separator /// between the elements. All arguments must be implicitly convertible to /// std::string, or there should be an overload of std::string::operator+=() diff --git a/include/llvm/ADT/StringMap.h b/include/llvm/ADT/StringMap.h index 24e3ecf71b13..c36fda7d6906 100644 --- a/include/llvm/ADT/StringMap.h +++ b/include/llvm/ADT/StringMap.h @@ -15,13 +15,13 @@ #define LLVM_ADT_STRINGMAP_H #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include <cassert> #include <cstdint> #include <cstdlib> #include <cstring> -#include <utility> #include <initializer_list> #include <new> #include <utility> @@ -32,6 +32,7 @@ namespace llvm { class StringMapConstIterator; template<typename ValueT> class StringMapIterator; + template <typename ValueT> class StringMapKeyIterator; template<typename ValueTy> class StringMapEntry; @@ -312,6 +313,11 @@ public: return const_iterator(TheTable+NumBuckets, true); } + llvm::iterator_range<StringMapKeyIterator<ValueTy>> keys() const { + return make_range(StringMapKeyIterator<ValueTy>(begin()), + StringMapKeyIterator<ValueTy>(end())); + } + iterator find(StringRef Key) { int Bucket = FindKey(Key); if (Bucket == -1) return end(); @@ -444,42 +450,39 @@ public: } }; -template <typename ValueTy> class StringMapConstIterator { +template <typename DerivedTy, typename ValueTy> +class StringMapIterBase + : public iterator_facade_base<DerivedTy, std::forward_iterator_tag, + ValueTy> { protected: StringMapEntryBase **Ptr = nullptr; public: - typedef StringMapEntry<ValueTy> value_type; - - StringMapConstIterator() = default; + StringMapIterBase() = default; - explicit StringMapConstIterator(StringMapEntryBase **Bucket, - bool NoAdvance = false) - : Ptr(Bucket) { + explicit StringMapIterBase(StringMapEntryBase **Bucket, + bool NoAdvance = false) + : Ptr(Bucket) { if (!NoAdvance) AdvancePastEmptyBuckets(); } - const value_type &operator*() const { - return *static_cast<StringMapEntry<ValueTy>*>(*Ptr); - } - const value_type *operator->() const { - return static_cast<StringMapEntry<ValueTy>*>(*Ptr); + DerivedTy &operator=(const DerivedTy &Other) { + Ptr = Other.Ptr; + return static_cast<DerivedTy &>(*this); } - bool operator==(const StringMapConstIterator &RHS) const { - return Ptr == RHS.Ptr; - } - bool operator!=(const StringMapConstIterator &RHS) const { - return Ptr != RHS.Ptr; - } + bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; } - inline StringMapConstIterator& operator++() { // Preincrement + DerivedTy &operator++() { // Preincrement ++Ptr; AdvancePastEmptyBuckets(); - return *this; + return static_cast<DerivedTy &>(*this); } - StringMapConstIterator operator++(int) { // Postincrement - StringMapConstIterator tmp = *this; ++*this; return tmp; + + DerivedTy operator++(int) { // Post-increment + DerivedTy Tmp(Ptr); + ++*this; + return Tmp; } private: @@ -489,22 +492,67 @@ private: } }; -template<typename ValueTy> -class StringMapIterator : public StringMapConstIterator<ValueTy> { +template <typename ValueTy> +class StringMapConstIterator + : public StringMapIterBase<StringMapConstIterator<ValueTy>, + const StringMapEntry<ValueTy>> { + using base = StringMapIterBase<StringMapConstIterator<ValueTy>, + const StringMapEntry<ValueTy>>; + public: - StringMapIterator() = default; + StringMapConstIterator() = default; + explicit StringMapConstIterator(StringMapEntryBase **Bucket, + bool NoAdvance = false) + : base(Bucket, NoAdvance) {} + + const StringMapEntry<ValueTy> &operator*() const { + return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr); + } +}; + +template <typename ValueTy> +class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>, + StringMapEntry<ValueTy>> { + using base = + StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>; +public: + StringMapIterator() = default; explicit StringMapIterator(StringMapEntryBase **Bucket, bool NoAdvance = false) - : StringMapConstIterator<ValueTy>(Bucket, NoAdvance) { - } + : base(Bucket, NoAdvance) {} StringMapEntry<ValueTy> &operator*() const { - return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr); + return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr); + } + + operator StringMapConstIterator<ValueTy>() const { + return StringMapConstIterator<ValueTy>(this->Ptr, true); } - StringMapEntry<ValueTy> *operator->() const { - return static_cast<StringMapEntry<ValueTy>*>(*this->Ptr); +}; + +template <typename ValueTy> +class StringMapKeyIterator + : public iterator_adaptor_base<StringMapKeyIterator<ValueTy>, + StringMapConstIterator<ValueTy>, + std::forward_iterator_tag, StringRef> { + using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>, + StringMapConstIterator<ValueTy>, + std::forward_iterator_tag, StringRef>; + +public: + StringMapKeyIterator() = default; + + explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter) + : base(std::move(Iter)) {} + + StringRef &operator*() { + Key = this->wrapped()->getKey(); + return Key; } + +private: + StringRef Key; }; } // end namespace llvm diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index d80a848c44a1..ce48f6d3bad3 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -557,6 +557,14 @@ namespace llvm { /// string is well-formed in the given radix. bool getAsInteger(unsigned Radix, APInt &Result) const; + /// Parse the current string as an IEEE double-precision floating + /// point value. The string must be a well-formed double. + /// + /// If \p AllowInexact is false, the function will fail if the string + /// cannot be represented exactly. Otherwise, the function only fails + /// in case of an overflow or underflow. + bool getAsDouble(double &Result, bool AllowInexact = true) const; + /// @} /// @name String Operations /// @{ @@ -600,7 +608,7 @@ namespace llvm { return drop_back(size() - N); } - /// Return a StringRef equal to 'this' but with only the first \p N + /// Return a StringRef equal to 'this' but with only the last \p N /// elements remaining. If \p N is greater than the length of the /// string, the entire string is returned. LLVM_NODISCARD diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index d4130e1e85ae..e271075b7e2a 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -110,6 +110,7 @@ public: ARMSubArch_v7m, ARMSubArch_v7s, ARMSubArch_v7k, + ARMSubArch_v7ve, ARMSubArch_v6, ARMSubArch_v6m, ARMSubArch_v6k, @@ -206,6 +207,7 @@ public: COFF, ELF, MachO, + Wasm, }; private: @@ -558,7 +560,8 @@ public: /// Tests whether the OS uses glibc. bool isOSGlibc() const { - return getOS() == Triple::Linux || getOS() == Triple::KFreeBSD; + return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD) && + !isAndroid(); } /// Tests whether the OS uses the ELF binary format. @@ -576,6 +579,11 @@ public: return getObjectFormat() == Triple::MachO; } + /// Tests whether the OS uses the Wasm binary format. + bool isOSBinFormatWasm() const { + return getObjectFormat() == Triple::Wasm; + } + /// Tests whether the target is the PS4 CPU bool isPS4CPU() const { return getArch() == Triple::x86_64 && @@ -592,6 +600,19 @@ public: /// Tests whether the target is Android bool isAndroid() const { return getEnvironment() == Triple::Android; } + bool isAndroidVersionLT(unsigned Major) const { + assert(isAndroid() && "Not an Android triple!"); + + unsigned Env[3]; + getEnvironmentVersion(Env[0], Env[1], Env[2]); + + // 64-bit targets did not exist before API level 21 (Lollipop). + if (isArch64Bit() && Env[0] < 21) + Env[0] = 21; + + return Env[0] < Major; + } + /// Tests whether the environment is musl-libc bool isMusl() const { return getEnvironment() == Triple::Musl || diff --git a/include/llvm/ADT/iterator.h b/include/llvm/ADT/iterator.h index 6470e09db86c..28dcdf9613ef 100644 --- a/include/llvm/ADT/iterator.h +++ b/include/llvm/ADT/iterator.h @@ -10,6 +10,7 @@ #ifndef LLVM_ADT_ITERATOR_H #define LLVM_ADT_ITERATOR_H +#include "llvm/ADT/iterator_range.h" #include <cstddef> #include <iterator> #include <type_traits> @@ -91,6 +92,8 @@ protected: public: DerivedT operator+(DifferenceTypeT n) const { + static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, + "Must pass the derived type to this template!"); static_assert( IsRandomAccess, "The '+' operator is only defined for random access iterators."); @@ -114,6 +117,8 @@ public: } DerivedT &operator++() { + static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, + "Must pass the derived type to this template!"); return static_cast<DerivedT *>(this)->operator+=(1); } DerivedT operator++(int) { @@ -160,9 +165,15 @@ public: return !static_cast<const DerivedT *>(this)->operator<(RHS); } + PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); } PointerT operator->() const { return &static_cast<const DerivedT *>(this)->operator*(); } + ReferenceProxy operator[](DifferenceTypeT n) { + static_assert(IsRandomAccess, + "Subscripting is only defined for random access iterators."); + return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n)); + } ReferenceProxy operator[](DifferenceTypeT n) const { static_assert(IsRandomAccess, "Subscripting is only defined for random access iterators."); @@ -202,7 +213,10 @@ protected: iterator_adaptor_base() = default; - explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {} + explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) { + static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value, + "Must pass the derived type to this template!"); + } const WrappedIteratorT &wrapped() const { return I; } @@ -283,6 +297,15 @@ struct pointee_iterator T &operator*() const { return **this->I; } }; +template <typename RangeT, typename WrappedIteratorT = + decltype(std::begin(std::declval<RangeT>()))> +iterator_range<pointee_iterator<WrappedIteratorT>> +make_pointee_range(RangeT &&Range) { + using PointeeIteratorT = pointee_iterator<WrappedIteratorT>; + return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))), + PointeeIteratorT(std::end(std::forward<RangeT>(Range)))); +} + template <typename WrappedIteratorT, typename T = decltype(&*std::declval<WrappedIteratorT>())> class pointer_iterator @@ -300,6 +323,15 @@ public: const T &operator*() const { return Ptr = &*this->I; } }; +template <typename RangeT, typename WrappedIteratorT = + decltype(std::begin(std::declval<RangeT>()))> +iterator_range<pointer_iterator<WrappedIteratorT>> +make_pointer_range(RangeT &&Range) { + using PointerIteratorT = pointer_iterator<WrappedIteratorT>; + return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))), + PointerIteratorT(std::end(std::forward<RangeT>(Range)))); +} + } // end namespace llvm #endif // LLVM_ADT_ITERATOR_H diff --git a/include/llvm/Analysis/AliasAnalysis.h b/include/llvm/Analysis/AliasAnalysis.h index d8e50438e722..1b8b9751faa1 100644 --- a/include/llvm/Analysis/AliasAnalysis.h +++ b/include/llvm/Analysis/AliasAnalysis.h @@ -443,11 +443,7 @@ public: /// getModRefInfo (for fences) - Return information about whether /// a particular store modifies or reads the specified memory location. - ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc) { - // Conservatively correct. (We could possibly be a bit smarter if - // Loc is a alloca that doesn't escape.) - return MRI_ModRef; - } + ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc); /// getModRefInfo (for fences) - A convenience wrapper. ModRefInfo getModRefInfo(const FenceInst *S, const Value *P, uint64_t Size) { @@ -528,6 +524,14 @@ public: /// Check whether or not an instruction may read or write the specified /// memory location. /// + /// Note explicitly that getModRefInfo considers the effects of reading and + /// writing the memory location, and not the effect of ordering relative to + /// other instructions. Thus, a volatile load is considered to be Ref, + /// because it does not actually write memory, it just can't be reordered + /// relative to other volatiles (or removed). Atomic ordered loads/stores are + /// considered ModRef ATM because conservatively, the visible effect appears + /// as if memory was written, not just an ordering constraint. + /// /// An instruction that doesn't read or write memory may be trivially LICM'd /// for example. /// diff --git a/include/llvm/Analysis/AliasSetTracker.h b/include/llvm/Analysis/AliasSetTracker.h index 5d11b22c6eed..eac97501c759 100644 --- a/include/llvm/Analysis/AliasSetTracker.h +++ b/include/llvm/Analysis/AliasSetTracker.h @@ -121,7 +121,10 @@ class AliasSet : public ilist_node<AliasSet> { AliasSet *Forward; /// All instructions without a specific address in this alias set. - std::vector<AssertingVH<Instruction> > UnknownInsts; + /// In rare cases this vector can have a null'ed out WeakVH + /// instances (can happen if some other loop pass deletes an + /// instruction in this list). + std::vector<WeakVH> UnknownInsts; /// Number of nodes pointing to this AliasSet plus the number of AliasSets /// forwarding to it. @@ -171,7 +174,7 @@ class AliasSet : public ilist_node<AliasSet> { Instruction *getUnknownInst(unsigned i) const { assert(i < UnknownInsts.size()); - return UnknownInsts[i]; + return cast_or_null<Instruction>(UnknownInsts[i]); } public: diff --git a/include/llvm/Analysis/AssumptionCache.h b/include/llvm/Analysis/AssumptionCache.h index 79287ed76f2e..f833f417c7dd 100644 --- a/include/llvm/Analysis/AssumptionCache.h +++ b/include/llvm/Analysis/AssumptionCache.h @@ -31,11 +31,10 @@ namespace llvm { /// \brief A cache of @llvm.assume calls within a function. /// /// This cache provides fast lookup of assumptions within a function by caching -/// them and amortizing the cost of scanning for them across all queries. The -/// cache is also conservatively self-updating so that it will never return -/// incorrect results about a function even as the function is being mutated. -/// However, flushing the cache and rebuilding it (or explicitly updating it) -/// may allow it to discover new assumptions. +/// them and amortizing the cost of scanning for them across all queries. Passes +/// that create new assumptions are required to call registerAssumption() to +/// register any new @llvm.assume calls that they create. Deletions of +/// @llvm.assume calls do not require special handling. class AssumptionCache { /// \brief The function for which this cache is handling assumptions. /// @@ -87,6 +86,13 @@ public: /// its instructions. AssumptionCache(Function &F) : F(F), Scanned(false) {} + /// This cache is designed to be self-updating and so it should never be + /// invalidated. + bool invalidate(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &) { + return false; + } + /// \brief Add an @llvm.assume intrinsic to this function's cache. /// /// The call passed in must be an instruction within this function and must @@ -196,7 +202,10 @@ public: AssumptionCacheTracker(); ~AssumptionCacheTracker() override; - void releaseMemory() override { AssumptionCaches.shrink_and_clear(); } + void releaseMemory() override { + verifyAnalysis(); + AssumptionCaches.shrink_and_clear(); + } void verifyAnalysis() const override; bool doFinalization(Module &) override { diff --git a/include/llvm/Analysis/BasicAliasAnalysis.h b/include/llvm/Analysis/BasicAliasAnalysis.h index addfffa01061..14e4bded264a 100644 --- a/include/llvm/Analysis/BasicAliasAnalysis.h +++ b/include/llvm/Analysis/BasicAliasAnalysis.h @@ -233,6 +233,24 @@ FunctionPass *createBasicAAWrapperPass(); /// populated to the best of our ability for a particular function when inside /// of a \c ModulePass or a \c CallGraphSCCPass. BasicAAResult createLegacyPMBasicAAResult(Pass &P, Function &F); + +/// This class is a functor to be used in legacy module or SCC passes for +/// computing AA results for a function. We store the results in fields so that +/// they live long enough to be queried, but we re-use them each time. +class LegacyAARGetter { + Pass &P; + Optional<BasicAAResult> BAR; + Optional<AAResults> AAR; + +public: + LegacyAARGetter(Pass &P) : P(P) {} + AAResults &operator()(Function &F) { + BAR.emplace(createLegacyPMBasicAAResult(P, F)); + AAR.emplace(createLegacyPMAAResults(P, F, *BAR)); + return *AAR; + } +}; + } #endif diff --git a/include/llvm/Analysis/BlockFrequencyInfo.h b/include/llvm/Analysis/BlockFrequencyInfo.h index 562041d11fa1..cbae01c9102f 100644 --- a/include/llvm/Analysis/BlockFrequencyInfo.h +++ b/include/llvm/Analysis/BlockFrequencyInfo.h @@ -45,6 +45,10 @@ public: ~BlockFrequencyInfo(); + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); + const Function *getFunction() const; const BranchProbabilityInfo *getBPI() const; void view() const; @@ -69,6 +73,12 @@ public: // Set the frequency of the given basic block. void setBlockFreq(const BasicBlock *BB, uint64_t Freq); + /// Set the frequency of \p ReferenceBB to \p Freq and scale the frequencies + /// of the blocks in \p BlocksToScale such that their frequencies relative + /// to \p ReferenceBB remain unchanged. + void setBlockFreqAndScale(const BasicBlock *ReferenceBB, uint64_t Freq, + SmallPtrSetImpl<BasicBlock *> &BlocksToScale); + /// calculate - compute block frequency info for the given function. void calculate(const Function &F, const BranchProbabilityInfo &BPI, const LoopInfo &LI); diff --git a/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/include/llvm/Analysis/BlockFrequencyInfoImpl.h index 3f4428d18740..e3d81fea49ea 100644 --- a/include/llvm/Analysis/BlockFrequencyInfoImpl.h +++ b/include/llvm/Analysis/BlockFrequencyInfoImpl.h @@ -1291,11 +1291,14 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits { } std::string getNodeLabel(NodeRef Node, const BlockFrequencyInfoT *Graph, - GVDAGType GType) { + GVDAGType GType, int layout_order = -1) { std::string Result; raw_string_ostream OS(Result); - OS << Node->getName().str() << " : "; + if (layout_order != -1) + OS << Node->getName() << "[" << layout_order << "] : "; + else + OS << Node->getName() << " : "; switch (GType) { case GVDT_Fraction: Graph->printBlockFreq(OS, Node); diff --git a/include/llvm/Analysis/BranchProbabilityInfo.h b/include/llvm/Analysis/BranchProbabilityInfo.h index 14b7a7f529f7..6a876679543d 100644 --- a/include/llvm/Analysis/BranchProbabilityInfo.h +++ b/include/llvm/Analysis/BranchProbabilityInfo.h @@ -164,6 +164,8 @@ private: /// \brief Track the set of blocks that always lead to a cold call. SmallPtrSet<const BasicBlock *, 16> PostDominatedByColdCall; + void updatePostDominatedByUnreachable(const BasicBlock *BB); + void updatePostDominatedByColdCall(const BasicBlock *BB); bool calcUnreachableHeuristics(const BasicBlock *BB); bool calcMetadataWeights(const BasicBlock *BB); bool calcColdCallHeuristics(const BasicBlock *BB); diff --git a/include/llvm/Analysis/CFGPrinter.h b/include/llvm/Analysis/CFGPrinter.h index efaa9d6df8ea..5786769cc500 100644 --- a/include/llvm/Analysis/CFGPrinter.h +++ b/include/llvm/Analysis/CFGPrinter.h @@ -140,8 +140,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { std::string Str; raw_string_ostream OS(Str); - SwitchInst::ConstCaseIt Case = - SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo); + auto Case = *SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo); OS << Case.getCaseValue()->getValue(); return OS.str(); } diff --git a/include/llvm/Analysis/CGSCCPassManager.h b/include/llvm/Analysis/CGSCCPassManager.h index 6fbe532112b2..398bbfb0c413 100644 --- a/include/llvm/Analysis/CGSCCPassManager.h +++ b/include/llvm/Analysis/CGSCCPassManager.h @@ -334,6 +334,7 @@ public: InvalidSCCSet, nullptr, nullptr}; PreservedAnalyses PA = PreservedAnalyses::all(); + CG.buildRefSCCs(); for (auto RCI = CG.postorder_ref_scc_begin(), RCE = CG.postorder_ref_scc_end(); RCI != RCE;) { diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index 4ecbaa75ac75..ea85436ee580 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -272,7 +272,7 @@ public: private: friend class CallGraph; - AssertingVH<Function> F; + Function *F; std::vector<CallRecord> CalledFunctions; diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h index 517842c8b0dc..ff6ca1959153 100644 --- a/include/llvm/Analysis/ConstantFolding.h +++ b/include/llvm/Analysis/ConstantFolding.h @@ -100,6 +100,12 @@ Constant *ConstantFoldExtractValueInstruction(Constant *Agg, /// successful; if not, null is returned. Constant *ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx); +/// \brief Attempt to constant fold a shufflevector instruction with the +/// specified operands and indices. The constant result is returned if +/// successful; if not, null is returned. +Constant *ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2, + Constant *Mask); + /// ConstantFoldLoadFromConstPtr - Return the value that a load from C would /// produce if it is constant and determinable. If this is not determinable, /// return null. diff --git a/include/llvm/Analysis/DominanceFrontier.h b/include/llvm/Analysis/DominanceFrontier.h index b9667f801ed3..8cae63c3c869 100644 --- a/include/llvm/Analysis/DominanceFrontier.h +++ b/include/llvm/Analysis/DominanceFrontier.h @@ -141,6 +141,10 @@ public: typedef DominanceFrontierBase<BasicBlock>::DomSetType DomSetType; typedef DominanceFrontierBase<BasicBlock>::iterator iterator; typedef DominanceFrontierBase<BasicBlock>::const_iterator const_iterator; + + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); }; class DominanceFrontierWrapperPass : public FunctionPass { diff --git a/include/llvm/Analysis/IndirectCallSiteVisitor.h b/include/llvm/Analysis/IndirectCallSiteVisitor.h index 71a8cb886321..3c40cc0235cc 100644 --- a/include/llvm/Analysis/IndirectCallSiteVisitor.h +++ b/include/llvm/Analysis/IndirectCallSiteVisitor.h @@ -21,16 +21,8 @@ struct PGOIndirectCallSiteVisitor 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); + if (CS.isIndirectCall()) + IndirectCallInsts.push_back(CS.getInstruction()); } }; diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index 5e7b00261f63..17e5cb6db02d 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -21,6 +21,7 @@ namespace llvm { class AssumptionCacheTracker; +class BlockFrequencyInfo; class CallSite; class DataLayout; class Function; @@ -137,6 +138,9 @@ struct InlineParams { /// Threshold to use when the callsite is considered hot. Optional<int> HotCallSiteThreshold; + + /// Threshold to use when the callsite is considered cold. + Optional<int> ColdCallSiteThreshold; }; /// Generate the parameters to tune the inline cost analysis based only on the @@ -171,6 +175,7 @@ InlineCost getInlineCost(CallSite CS, const InlineParams &Params, TargetTransformInfo &CalleeTTI, std::function<AssumptionCache &(Function &)> &GetAssumptionCache, + Optional<function_ref<BlockFrequencyInfo &(Function &)>> GetBFI, ProfileSummaryInfo *PSI); /// \brief Get an InlineCost with the callee explicitly specified. @@ -182,6 +187,7 @@ InlineCost getInlineCost(CallSite CS, Function *Callee, const InlineParams &Params, TargetTransformInfo &CalleeTTI, std::function<AssumptionCache &(Function &)> &GetAssumptionCache, + Optional<function_ref<BlockFrequencyInfo &(Function &)>> GetBFI, ProfileSummaryInfo *PSI); /// \brief Minimal filter to detect invalid constructs for inlining. diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index 47d6118313cb..b829e995db05 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -42,6 +42,7 @@ namespace llvm { class Instruction; class DataLayout; class FastMathFlags; + class OptimizationRemarkEmitter; class TargetLibraryInfo; class Type; class Value; @@ -246,6 +247,14 @@ namespace llvm { AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr); + /// Given operands for a ShuffleVectorInst, fold the result or return null. + Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask, + Type *RetTy, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr, + const DominatorTree *DT = nullptr, + AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr); + //=== Helper functions for higher up the class hierarchy. @@ -296,7 +305,8 @@ namespace llvm { Value *SimplifyInstruction(Instruction *I, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, - AssumptionCache *AC = nullptr); + AssumptionCache *AC = nullptr, + OptimizationRemarkEmitter *ORE = nullptr); /// Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively. /// diff --git a/include/llvm/Analysis/LazyBlockFrequencyInfo.h b/include/llvm/Analysis/LazyBlockFrequencyInfo.h index 5a02b9dce463..71ce0842f6a9 100644 --- a/include/llvm/Analysis/LazyBlockFrequencyInfo.h +++ b/include/llvm/Analysis/LazyBlockFrequencyInfo.h @@ -9,7 +9,7 @@ // // 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 +// the analysis pass is executed but rather when the BFI result is explicitly // requested by the analysis client. // //===----------------------------------------------------------------------===// @@ -27,10 +27,58 @@ class BranchProbabilityInfo; class Function; class LoopInfo; +/// 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. +template <typename FunctionT, typename BranchProbabilityInfoPassT, + typename LoopInfoT, typename BlockFrequencyInfoT> +class LazyBlockFrequencyInfo { +public: + LazyBlockFrequencyInfo() + : Calculated(false), F(nullptr), BPIPass(nullptr), LI(nullptr) {} + + /// Set up the per-function input. + void setAnalysis(const FunctionT *F, BranchProbabilityInfoPassT *BPIPass, + const LoopInfoT *LI) { + this->F = F; + this->BPIPass = BPIPass; + this->LI = LI; + } + + /// Retrieve the BFI with the block frequencies computed. + BlockFrequencyInfoT &getCalculated() { + if (!Calculated) { + assert(F && BPIPass && LI && "call setAnalysis"); + BFI.calculate( + *F, BPIPassTrait<BranchProbabilityInfoPassT>::getBPI(BPIPass), *LI); + Calculated = true; + } + return BFI; + } + + const BlockFrequencyInfoT &getCalculated() const { + return const_cast<LazyBlockFrequencyInfo *>(this)->getCalculated(); + } + + void releaseMemory() { + BFI.releaseMemory(); + Calculated = false; + setAnalysis(nullptr, nullptr, nullptr); + } + +private: + BlockFrequencyInfoT BFI; + bool Calculated; + const FunctionT *F; + BranchProbabilityInfoPassT *BPIPass; + const LoopInfoT *LI; +}; + /// \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. +/// rather when the BFI result is explicitly requested by the analysis client. /// /// There are some additional requirements for any client pass that wants to use /// the analysis: @@ -49,54 +97,12 @@ class LoopInfo; /// /// 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), BPIPass(nullptr), LI(nullptr) {} - - /// Set up the per-function input. - void setAnalysis(const Function *F, LazyBranchProbabilityInfoPass *BPIPass, - const LoopInfo *LI) { - this->F = F; - this->BPIPass = BPIPass; - this->LI = LI; - } - /// Retrieve the BFI with the block frequencies computed. - BlockFrequencyInfo &getCalculated() { - if (!Calculated) { - assert(F && BPIPass && LI && "call setAnalysis"); - BFI.calculate(*F, BPIPass->getBPI(), *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; - LazyBranchProbabilityInfoPass *BPIPass; - const LoopInfo *LI; - }; - - LazyBlockFrequencyInfo LBFI; +class LazyBlockFrequencyInfoPass : public FunctionPass { +private: + LazyBlockFrequencyInfo<Function, LazyBranchProbabilityInfoPass, LoopInfo, + BlockFrequencyInfo> + LBFI; public: static char ID; diff --git a/include/llvm/Analysis/LazyBranchProbabilityInfo.h b/include/llvm/Analysis/LazyBranchProbabilityInfo.h index c76fa1e819ae..067d7ebfd1f5 100644 --- a/include/llvm/Analysis/LazyBranchProbabilityInfo.h +++ b/include/llvm/Analysis/LazyBranchProbabilityInfo.h @@ -105,5 +105,17 @@ public: /// \brief Helper for client passes to initialize dependent passes for LBPI. void initializeLazyBPIPassPass(PassRegistry &Registry); + +/// \brief Simple trait class that provides a mapping between BPI passes and the +/// corresponding BPInfo. +template <typename PassT> struct BPIPassTrait { + static PassT &getBPI(PassT *P) { return *P; } +}; + +template <> struct BPIPassTrait<LazyBranchProbabilityInfoPass> { + static BranchProbabilityInfo &getBPI(LazyBranchProbabilityInfoPass *P) { + return P->getBPI(); + } +}; } #endif diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index bca0aebe2eef..ad7f5c80549f 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -106,6 +106,7 @@ class raw_ostream; class LazyCallGraph { public: class Node; + class EdgeSequence; class SCC; class RefSCC; class edge_iterator; @@ -121,16 +122,6 @@ public: /// 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 @@ -141,7 +132,6 @@ public: 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. @@ -158,197 +148,251 @@ public: /// 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. + /// Get the call graph node referenced by this edge. /// - /// 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; + /// This requires that the edge is not null. + Node &getNode() const; - /// Get the call graph node for this edge, building it if necessary. + /// Get the function referenced by this edge. /// - /// 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); + /// This requires that the edge is not null. + Function &getFunction() const; private: - friend class LazyCallGraph::Node; + friend class LazyCallGraph::EdgeSequence; friend class LazyCallGraph::RefSCC; - PointerIntPair<PointerUnion<Function *, Node *>, 1, Kind> Value; + PointerIntPair<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. + /// The edge sequence object. /// - /// This represents a single node. It's primary roles are to cache the list of - /// callees, de-duplicate and provide fast testing of whether a function is - /// a callee, and facilitate iteration of child nodes in the graph. - class Node { + /// This typically exists entirely within the node but is exposed as + /// a separate type because a node doesn't initially have edges. An explicit + /// population step is required to produce this sequence at first and it is + /// then cached in the node. It is also used to represent edges entering the + /// graph from outside the module to model the graph's roots. + /// + /// The sequence itself both iterable and indexable. The indexes remain + /// stable even as the sequence mutates (including removal). + class EdgeSequence { friend class LazyCallGraph; - friend class LazyCallGraph::SCC; + friend class LazyCallGraph::Node; friend class LazyCallGraph::RefSCC; - LazyCallGraph *G; - Function &F; + typedef SmallVector<Edge, 4> VectorT; + typedef SmallVectorImpl<Edge> VectorImplT; - // We provide for the DFS numbering and Tarjan walk lowlink numbers to be - // 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; + public: + /// An iterator used for the edges to both entry nodes and child nodes. + class iterator + : public iterator_adaptor_base<iterator, VectorImplT::iterator, + std::forward_iterator_tag> { + friend class LazyCallGraph; + friend class LazyCallGraph::Node; + + VectorImplT::iterator E; + + // Build the iterator for a specific position in the edge list. + iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E) + : iterator_adaptor_base(BaseI), E(E) { + while (I != E && !*I) + ++I; + } - mutable EdgeVectorT Edges; - DenseMap<Function *, int> EdgeIndexMap; + public: + iterator() {} - /// Basic constructor implements the scanning of F into Edges and - /// EdgeIndexMap. - Node(LazyCallGraph &G, Function &F); + using iterator_adaptor_base::operator++; + iterator &operator++() { + do { + ++I; + } while (I != E && !*I); + return *this; + } + }; - /// Internal helper to insert an edge to a function. - void insertEdgeInternal(Function &ChildF, Edge::Kind EK); + /// An iterator over specifically call edges. + /// + /// This has the same iteration properties as the \c iterator, but + /// restricts itself to edges which represent actual calls. + class call_iterator + : public iterator_adaptor_base<call_iterator, VectorImplT::iterator, + std::forward_iterator_tag> { + friend class LazyCallGraph; + friend class LazyCallGraph::Node; + + VectorImplT::iterator E; + + /// Advance the iterator to the next valid, call edge. + void advanceToNextEdge() { + while (I != E && (!*I || !I->isCall())) + ++I; + } - /// Internal helper to insert an edge to a node. - void insertEdgeInternal(Node &ChildN, Edge::Kind EK); + // Build the iterator for a specific position in the edge list. + call_iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E) + : iterator_adaptor_base(BaseI), E(E) { + advanceToNextEdge(); + } - /// Internal helper to change an edge kind. - void setEdgeKind(Function &ChildF, Edge::Kind EK); + public: + call_iterator() {} - /// Internal helper to remove the edge to the given function. - void removeEdgeInternal(Function &ChildF); + using iterator_adaptor_base::operator++; + call_iterator &operator++() { + ++I; + advanceToNextEdge(); + return *this; + } + }; - void clear() { - Edges.clear(); - EdgeIndexMap.clear(); - } + iterator begin() { return iterator(Edges.begin(), Edges.end()); } + iterator end() { return iterator(Edges.end(), Edges.end()); } - /// Print the name of this node's function. - friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) { - return OS << N.F.getName(); + Edge &operator[](int i) { return Edges[i]; } + Edge &operator[](Node &N) { + assert(EdgeIndexMap.find(&N) != EdgeIndexMap.end() && "No such edge!"); + return Edges[EdgeIndexMap.find(&N)->second]; } - - /// Dump the name of this node's function to stderr. - void dump() const; - - public: - LazyCallGraph &getGraph() const { return *G; } - - Function &getFunction() const { return F; } - - edge_iterator begin() const { - return edge_iterator(Edges.begin(), Edges.end()); + Edge *lookup(Node &N) { + auto EI = EdgeIndexMap.find(&N); + return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr; } - 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]; + call_iterator call_begin() { + return call_iterator(Edges.begin(), Edges.end()); } - const Edge &operator[](Node &N) const { return (*this)[N.getFunction()]; } + call_iterator call_end() { return call_iterator(Edges.end(), Edges.end()); } - const Edge *lookup(Function &F) const { - auto EI = EdgeIndexMap.find(&F); - return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr; + iterator_range<call_iterator> calls() { + return make_range(call_begin(), call_end()); } - 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()); - } + bool empty() { + for (auto &E : Edges) + if (E) + return false; - iterator_range<call_edge_iterator> calls() const { - return make_range(call_begin(), call_end()); + return true; } - /// Equality is defined as address equality. - bool operator==(const Node &N) const { return this == &N; } - bool operator!=(const Node &N) const { return !operator==(N); } - }; + private: + VectorT Edges; + DenseMap<Node *, int> EdgeIndexMap; - /// A lazy iterator used for both the entry nodes and child nodes. - /// - /// When this iterator is dereferenced, if not yet available, a function will - /// 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 edge_iterator - : public iterator_adaptor_base<edge_iterator, EdgeVectorImplT::iterator, - std::forward_iterator_tag> { - friend class LazyCallGraph; - friend class LazyCallGraph::Node; + EdgeSequence() = default; - EdgeVectorImplT::iterator E; + /// Internal helper to insert an edge to a node. + void insertEdgeInternal(Node &ChildN, Edge::Kind EK); - // 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; - } + /// Internal helper to change an edge kind. + void setEdgeKind(Node &ChildN, Edge::Kind EK); - public: - edge_iterator() {} + /// Internal helper to remove the edge to the given function. + bool removeEdgeInternal(Node &ChildN); - using iterator_adaptor_base::operator++; - edge_iterator &operator++() { - do { - ++I; - } while (I != E && !*I); - return *this; - } + /// Internal helper to replace an edge key with a new one. + /// + /// This should be used when the function for a particular node in the + /// graph gets replaced and we are updating all of the edges to that node + /// to use the new function as the key. + void replaceEdgeKey(Function &OldTarget, Function &NewTarget); }; - /// A lazy iterator over specifically call edges. + /// A node in the call graph. + /// + /// This represents a single node. It's primary roles are to cache the list of + /// callees, de-duplicate and provide fast testing of whether a function is + /// a callee, and facilitate iteration of child nodes in the graph. /// - /// 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> { + /// The node works much like an optional in order to lazily populate the + /// edges of each node. Until populated, there are no edges. Once populated, + /// you can access the edges by dereferencing the node or using the `->` + /// operator as if the node was an `Optional<EdgeSequence>`. + class Node { friend class LazyCallGraph; - friend class LazyCallGraph::Node; + friend class LazyCallGraph::RefSCC; - EdgeVectorImplT::iterator E; + public: + LazyCallGraph &getGraph() const { return *G; } - /// Advance the iterator to the next valid, call edge. - void advanceToNextEdge() { - while (I != E && (!*I || !I->isCall())) - ++I; + Function &getFunction() const { return *F; } + + StringRef getName() const { return F->getName(); } + + /// Equality is defined as address equality. + bool operator==(const Node &N) const { return this == &N; } + bool operator!=(const Node &N) const { return !operator==(N); } + + /// Tests whether the node has been populated with edges. + operator bool() const { return Edges.hasValue(); } + + // We allow accessing the edges by dereferencing or using the arrow + // operator, essentially wrapping the internal optional. + EdgeSequence &operator*() const { + // Rip const off because the node itself isn't changing here. + return const_cast<EdgeSequence &>(*Edges); } + EdgeSequence *operator->() const { return &**this; } - // 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(); + /// Populate the edges of this node if necessary. + /// + /// The first time this is called it will populate the edges for this node + /// in the graph. It does this by scanning the underlying function, so once + /// this is done, any changes to that function must be explicitly reflected + /// in updates to the graph. + /// + /// \returns the populated \c EdgeSequence to simplify walking it. + /// + /// This will not update or re-scan anything if called repeatedly. Instead, + /// the edge sequence is cached and returned immediately on subsequent + /// calls. + EdgeSequence &populate() { + if (Edges) + return *Edges; + + return populateSlow(); } - public: - call_edge_iterator() {} + private: + LazyCallGraph *G; + Function *F; - using iterator_adaptor_base::operator++; - call_edge_iterator &operator++() { - ++I; - advanceToNextEdge(); - return *this; + // We provide for the DFS numbering and Tarjan walk lowlink numbers to be + // 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; + + Optional<EdgeSequence> Edges; + + /// Basic constructor implements the scanning of F into Edges and + /// EdgeIndexMap. + Node(LazyCallGraph &G, Function &F) + : G(&G), F(&F), DFSNumber(0), LowLink(0) {} + + /// Implementation of the scan when populating. + EdgeSequence &populateSlow(); + + /// Internal helper to directly replace the function with a new one. + /// + /// This is used to facilitate tranfsormations which need to replace the + /// formal Function object but directly move the body and users from one to + /// the other. + void replaceFunction(Function &NewF); + + void clear() { Edges.reset(); } + + /// 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; }; /// An SCC of the call graph. @@ -789,19 +833,26 @@ public: /// already existing edges. void insertTrivialRefEdge(Node &SourceN, Node &TargetN); + /// Directly replace a node's function with a new function. + /// + /// This should be used when moving the body and users of a function to + /// a new formal function object but not otherwise changing the call graph + /// structure in any way. + /// + /// It requires that the old function in the provided node have zero uses + /// and the new function must have calls and references to it establishing + /// an equivalent graph. + void replaceNodeFunction(Node &N, Function &NewF); + ///@} }; /// A post-order depth-first RefSCC iterator over the call graph. /// - /// This iterator triggers the Tarjan DFS-based formation of the RefSCC (and - /// SCC) DAG for the call graph, walking it lazily in depth-first post-order. - /// That is, it always visits RefSCCs for the target of a reference edge - /// prior to visiting the RefSCC for a source of the edge (when they are in - /// different RefSCCs). - /// - /// When forming each RefSCC, the call edges within it are used to form SCCs - /// within it, so iterating this also controls the lazy formation of SCCs. + /// This iterator walks the cached post-order sequence of RefSCCs. However, + /// it trades stability for flexibility. It is restricted to a forward + /// iterator but will survive mutations which insert new RefSCCs and continue + /// to point to the same RefSCC even if it moves in the post-order sequence. class postorder_ref_scc_iterator : public iterator_facade_base<postorder_ref_scc_iterator, std::forward_iterator_tag, RefSCC> { @@ -825,12 +876,9 @@ public: /// populating it if necessary. static RefSCC *getRC(LazyCallGraph &G, int Index) { if (Index == (int)G.PostOrderRefSCCs.size()) - if (!G.buildNextRefSCCInPostOrder()) - // We're at the end. - return nullptr; + // We're at the end. + return nullptr; - assert(Index < (int)G.PostOrderRefSCCs.size() && - "Built the next post-order RefSCC without growing list!"); return G.PostOrderRefSCCs[Index]; } @@ -859,17 +907,21 @@ public: LazyCallGraph(LazyCallGraph &&G); LazyCallGraph &operator=(LazyCallGraph &&RHS); - edge_iterator begin() { - return edge_iterator(EntryEdges.begin(), EntryEdges.end()); - } - edge_iterator end() { - return edge_iterator(EntryEdges.end(), EntryEdges.end()); - } + EdgeSequence::iterator begin() { return EntryEdges.begin(); } + EdgeSequence::iterator end() { return EntryEdges.end(); } + + void buildRefSCCs(); postorder_ref_scc_iterator postorder_ref_scc_begin() { + if (!EntryEdges.empty()) + assert(!PostOrderRefSCCs.empty() && + "Must form RefSCCs before iterating them!"); return postorder_ref_scc_iterator(*this); } postorder_ref_scc_iterator postorder_ref_scc_end() { + if (!EntryEdges.empty()) + assert(!PostOrderRefSCCs.empty() && + "Must form RefSCCs before iterating them!"); return postorder_ref_scc_iterator(*this, postorder_ref_scc_iterator::IsAtEndT()); } @@ -920,19 +972,19 @@ public: /// below. /// Update the call graph after inserting a new edge. - void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK); + void insertEdge(Node &SourceN, Node &TargetN, Edge::Kind EK); /// Update the call graph after inserting a new edge. - void insertEdge(Function &Caller, Function &Callee, Edge::Kind EK) { - return insertEdge(get(Caller), Callee, EK); + void insertEdge(Function &Source, Function &Target, Edge::Kind EK) { + return insertEdge(get(Source), get(Target), EK); } /// Update the call graph after deleting an edge. - void removeEdge(Node &Caller, Function &Callee); + void removeEdge(Node &SourceN, Node &TargetN); /// Update the call graph after deleting an edge. - void removeEdge(Function &Caller, Function &Callee) { - return removeEdge(get(Caller), Callee); + void removeEdge(Function &Source, Function &Target) { + return removeEdge(get(Source), get(Target)); } ///@} @@ -1013,14 +1065,11 @@ private: /// Maps function->node for fast lookup. DenseMap<const Function *, Node *> NodeMap; - /// The entry nodes to the graph. + /// The entry edges into the graph. /// - /// These nodes are reachable through "external" means. Put another way, they + /// These edges are from "external" sources. Put another way, they /// escape at the module scope. - EdgeVectorT EntryEdges; - - /// Map of the entry nodes in the graph to their indices in \c EntryEdges. - DenseMap<Function *, int> EntryIndexMap; + EdgeSequence EntryEdges; /// Allocator that holds all the call graph SCCs. SpecificBumpPtrAllocator<SCC> SCCBPA; @@ -1045,18 +1094,6 @@ private: /// 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 *, edge_iterator>, 4> DFSStack; - - /// 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 RefSCC. - SmallVector<Node *, 4> PendingRefSCCStack; - - /// Counter for the next DFS number to assign. - int NextDFSNumber; - /// Helper to insert a new function, with an already looked-up entry in /// the NodeMap. Node &insertInto(Function &F, Node *&MappedN); @@ -1078,6 +1115,23 @@ private: return new (RefSCCBPA.Allocate()) RefSCC(std::forward<Ts>(Args)...); } + /// Common logic for building SCCs from a sequence of roots. + /// + /// This is a very generic implementation of the depth-first walk and SCC + /// formation algorithm. It uses a generic sequence of roots and generic + /// callbacks for each step. This is designed to be used to implement both + /// the RefSCC formation and SCC formation with shared logic. + /// + /// Currently this is a relatively naive implementation of Tarjan's DFS + /// algorithm to form the SCCs. + /// + /// FIXME: We should consider newer variants such as Nuutila. + template <typename RootsT, typename GetBeginT, typename GetEndT, + typename GetNodeT, typename FormSCCCallbackT> + static void buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin, + GetEndT &&GetEnd, GetNodeT &&GetNode, + FormSCCCallbackT &&FormSCC); + /// Build the SCCs for a RefSCC out of a list of nodes. void buildSCCs(RefSCC &RC, node_stack_range Nodes); @@ -1098,22 +1152,12 @@ private: "Index does not point back at RC!"); return IndexIt->second; } - - /// Builds the next node in the post-order RefSCC walk of the call graph and - /// appends it to the \c PostOrderRefSCCs vector. - /// - /// Returns true if a new RefSCC was successfully constructed, and false if - /// there are no more RefSCCs to build in the graph. - bool buildNextRefSCCInPostOrder(); }; 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 LazyCallGraph::Edge::operator bool() const { return Value.getPointer(); } inline LazyCallGraph::Edge::Kind LazyCallGraph::Edge::getKind() const { assert(*this && "Queried a null edge!"); @@ -1125,51 +1169,32 @@ inline bool LazyCallGraph::Edge::isCall() const { return getKind() == Call; } -inline Function &LazyCallGraph::Edge::getFunction() const { +inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode() 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(); + return *Value.getPointer(); } -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) { +inline Function &LazyCallGraph::Edge::getFunction() const { 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; + return getNode().getFunction(); } // Provide GraphTraits specializations for call graphs. template <> struct GraphTraits<LazyCallGraph::Node *> { typedef LazyCallGraph::Node *NodeRef; - typedef LazyCallGraph::edge_iterator ChildIteratorType; + typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType; static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->end(); } + static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); } + static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); } }; template <> struct GraphTraits<LazyCallGraph *> { typedef LazyCallGraph::Node *NodeRef; - typedef LazyCallGraph::edge_iterator ChildIteratorType; + typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType; static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->end(); } + static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); } + static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); } }; /// An analysis pass which computes the call graph for a module. diff --git a/include/llvm/Analysis/LazyValueInfo.h b/include/llvm/Analysis/LazyValueInfo.h index 610791023a7d..49e088e533dc 100644 --- a/include/llvm/Analysis/LazyValueInfo.h +++ b/include/llvm/Analysis/LazyValueInfo.h @@ -32,6 +32,7 @@ namespace llvm { class LazyValueInfo { friend class LazyValueInfoWrapperPass; AssumptionCache *AC = nullptr; + const DataLayout *DL = nullptr; class TargetLibraryInfo *TLI = nullptr; DominatorTree *DT = nullptr; void *PImpl = nullptr; @@ -40,16 +41,17 @@ class LazyValueInfo { public: ~LazyValueInfo(); LazyValueInfo() {} - LazyValueInfo(AssumptionCache *AC_, TargetLibraryInfo *TLI_, + LazyValueInfo(AssumptionCache *AC_, const DataLayout *DL_, TargetLibraryInfo *TLI_, DominatorTree *DT_) - : AC(AC_), TLI(TLI_), DT(DT_) {} + : AC(AC_), DL(DL_), TLI(TLI_), DT(DT_) {} LazyValueInfo(LazyValueInfo &&Arg) - : AC(Arg.AC), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) { + : AC(Arg.AC), DL(Arg.DL), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) { Arg.PImpl = nullptr; } LazyValueInfo &operator=(LazyValueInfo &&Arg) { releaseMemory(); AC = Arg.AC; + DL = Arg.DL; TLI = Arg.TLI; DT = Arg.DT; PImpl = Arg.PImpl; @@ -98,8 +100,15 @@ public: /// Inform the analysis cache that we have erased a block. void eraseBlock(BasicBlock *BB); + /// Print the \LazyValueInfoCache. + void printCache(Function &F, raw_ostream &OS); + // For old PM pass. Delete once LazyValueInfoWrapperPass is gone. void releaseMemory(); + + /// Handle invalidation events in the new pass manager. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv); }; /// \brief Analysis to compute lazy value information. diff --git a/include/llvm/Analysis/Loads.h b/include/llvm/Analysis/Loads.h index e167f36219d2..a59c1f88e229 100644 --- a/include/llvm/Analysis/Loads.h +++ b/include/llvm/Analysis/Loads.h @@ -85,8 +85,37 @@ Value *FindAvailableLoadedValue(LoadInst *Load, BasicBlock::iterator &ScanFrom, unsigned MaxInstsToScan = DefMaxInstsToScan, AliasAnalysis *AA = nullptr, - bool *IsLoadCSE = nullptr); + bool *IsLoadCSE = nullptr, + unsigned *NumScanedInst = nullptr); +/// Scan backwards to see if we have the value of the given pointer 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. +/// +/// \param Ptr The pointer we want the load and store to originate from. +/// \param AccessTy The access type of the pointer. +/// \param AtLeastAtomic Are we looking for at-least an atomic load/store ? In +/// case it is false, we can return an atomic or non-atomic load or store. In +/// case it is true, we need to return an atomic load or store. +/// \param ScanBB The basic block to scan. +/// \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] IsLoad Whether the returned value is a load from the same +/// location in memory, as opposed to the value operand of a store. +/// +/// \returns The found value, or nullptr if no value is found. +Value *FindAvailablePtrLoadStore(Value *Ptr, Type *AccessTy, bool AtLeastAtomic, + BasicBlock *ScanBB, + BasicBlock::iterator &ScanFrom, + unsigned MaxInstsToScan, AliasAnalysis *AA, + bool *IsLoad, unsigned *NumScanedInst); } #endif diff --git a/include/llvm/Analysis/LoopAccessAnalysis.h b/include/llvm/Analysis/LoopAccessAnalysis.h index 901b193c7e2d..2568903c57f3 100644 --- a/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/include/llvm/Analysis/LoopAccessAnalysis.h @@ -38,39 +38,6 @@ class SCEVUnionPredicate; class LoopAccessInfo; class OptimizationRemarkEmitter; -/// Optimization analysis message produced during vectorization. Messages inform -/// the user why vectorization did not occur. -class LoopAccessReport { - std::string Message; - const Instruction *Instr; - -protected: - LoopAccessReport(const Twine &Message, const Instruction *I) - : Message(Message.str()), Instr(I) {} - -public: - LoopAccessReport(const Instruction *I = nullptr) : Instr(I) {} - - template <typename A> LoopAccessReport &operator<<(const A &Value) { - raw_string_ostream Out(Message); - Out << Value; - return *this; - } - - const Instruction *getInstr() const { return Instr; } - - std::string &str() { return Message; } - const std::string &str() const { return Message; } - operator Twine() { return Message; } - - /// \brief Emit an analysis note for \p PassName with the debug location from - /// the instruction in \p Message if available. Otherwise use the location of - /// \p TheLoop. - static void emitAnalysis(const LoopAccessReport &Message, const Loop *TheLoop, - const char *PassName, - OptimizationRemarkEmitter &ORE); -}; - /// \brief Collection of parameters shared beetween the Loop Vectorizer and the /// Loop Access Analysis. struct VectorizerParams { @@ -126,7 +93,7 @@ struct VectorizerParams { class MemoryDepChecker { public: typedef PointerIntPair<Value *, 1, bool> MemAccessInfo; - typedef SmallPtrSet<MemAccessInfo, 8> MemAccessInfoSet; + typedef SmallVector<MemAccessInfo, 8> MemAccessInfoList; /// \brief Set of potential dependent memory accesses. typedef EquivalenceClasses<MemAccessInfo> DepCandidates; @@ -221,7 +188,7 @@ public: /// \brief Check whether the dependencies between the accesses are safe. /// /// Only checks sets with elements in \p CheckDeps. - bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoSet &CheckDeps, + bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoList &CheckDeps, const ValueToValueMap &Strides); /// \brief No memory dependence was encountered that would inhibit diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index 20e6af2727fe..996794b660a9 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -26,7 +26,7 @@ // * 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 +// in the CFG. There can be strongly connected components 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. @@ -364,7 +364,7 @@ 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. +/// in the CFG are necessarily loops. class Loop : public LoopBase<BasicBlock, Loop> { public: /// \brief A range representing the start and end location of a loop. @@ -469,7 +469,7 @@ public: /// the loop that branches to the loop header. /// /// The LoopID metadata node should have one or more operands and the first - /// operand should should be the node itself. + /// operand should be the node itself. void setLoopID(MDNode *LoopID) const; /// Return true if no exit block for the loop has a predecessor that is @@ -478,7 +478,8 @@ public: /// Return all unique successor blocks of this loop. /// These are the blocks _outside of the current loop_ which are branched to. - /// This assumes that loop exits are in canonical form. + /// This assumes that loop exits are in canonical form, i.e. all exits are + /// dedicated exits. void getUniqueExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const; /// If getUniqueExitBlocks would return exactly one block, return that block. @@ -570,6 +571,23 @@ public: reverse_iterator rend() const { return TopLevelLoops.rend(); } bool empty() const { return TopLevelLoops.empty(); } + /// Return all of the loops in the function in preorder across the loop + /// nests, with siblings in forward program order. + /// + /// Note that because loops form a forest of trees, preorder is equivalent to + /// reverse postorder. + SmallVector<LoopT *, 4> getLoopsInPreorder(); + + /// Return all of the loops in the function in preorder across the loop + /// nests, with siblings in *reverse* program order. + /// + /// Note that because loops form a forest of trees, preorder is equivalent to + /// reverse postorder. + /// + /// Also note that this is *not* a reverse preorder. Only the siblings are in + /// reverse program order. + SmallVector<LoopT *, 4> getLoopsInReverseSiblingPreorder(); + /// 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. LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); } @@ -682,6 +700,10 @@ public: return *this; } + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); + // Most of the public interface is provided via LoopInfoBase. /// Update LoopInfo after removing the last backedge from a loop. This updates diff --git a/include/llvm/Analysis/LoopInfoImpl.h b/include/llvm/Analysis/LoopInfoImpl.h index 833a2202a568..761f8721b54f 100644 --- a/include/llvm/Analysis/LoopInfoImpl.h +++ b/include/llvm/Analysis/LoopInfoImpl.h @@ -507,6 +507,55 @@ analyze(const DominatorTreeBase<BlockT> &DomTree) { DFS.traverse(DomRoot->getBlock()); } +template <class BlockT, class LoopT> +SmallVector<LoopT *, 4> LoopInfoBase<BlockT, LoopT>::getLoopsInPreorder() { + SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist; + // The outer-most loop actually goes into the result in the same relative + // order as we walk it. But LoopInfo stores the top level loops in reverse + // program order so for here we reverse it to get forward program order. + // FIXME: If we change the order of LoopInfo we will want to remove the + // reverse here. + for (LoopT *RootL : reverse(*this)) { + assert(PreOrderWorklist.empty() && + "Must start with an empty preorder walk worklist."); + PreOrderWorklist.push_back(RootL); + do { + LoopT *L = PreOrderWorklist.pop_back_val(); + // Sub-loops are stored in forward program order, but will process the + // worklist backwards so append them in reverse order. + PreOrderWorklist.append(L->rbegin(), L->rend()); + PreOrderLoops.push_back(L); + } while (!PreOrderWorklist.empty()); + } + + return PreOrderLoops; +} + +template <class BlockT, class LoopT> +SmallVector<LoopT *, 4> +LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() { + SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist; + // The outer-most loop actually goes into the result in the same relative + // order as we walk it. LoopInfo stores the top level loops in reverse + // program order so we walk in order here. + // FIXME: If we change the order of LoopInfo we will want to add a reverse + // here. + for (LoopT *RootL : *this) { + assert(PreOrderWorklist.empty() && + "Must start with an empty preorder walk worklist."); + PreOrderWorklist.push_back(RootL); + do { + LoopT *L = PreOrderWorklist.pop_back_val(); + // Sub-loops are stored in forward program order, but will process the + // worklist backwards so we can just append them in order. + PreOrderWorklist.append(L->begin(), L->end()); + PreOrderLoops.push_back(L); + } while (!PreOrderWorklist.empty()); + } + + return PreOrderLoops; +} + // Debugging template<class BlockT, class LoopT> void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const { @@ -528,15 +577,48 @@ bool compareVectors(std::vector<T> &BB1, std::vector<T> &BB2) { } template <class BlockT, class LoopT> -static void -addInnerLoopsToHeadersMap(DenseMap<BlockT *, const LoopT *> &LoopHeaders, - const LoopInfoBase<BlockT, LoopT> &LI, - const LoopT &L) { +void addInnerLoopsToHeadersMap(DenseMap<BlockT *, const LoopT *> &LoopHeaders, + const LoopInfoBase<BlockT, LoopT> &LI, + const LoopT &L) { LoopHeaders[L.getHeader()] = &L; for (LoopT *SL : L) addInnerLoopsToHeadersMap(LoopHeaders, LI, *SL); } +#ifndef NDEBUG +template <class BlockT, class LoopT> +static void compareLoops(const LoopT *L, const LoopT *OtherL, + DenseMap<BlockT *, const LoopT *> &OtherLoopHeaders) { + BlockT *H = L->getHeader(); + BlockT *OtherH = OtherL->getHeader(); + assert(H == OtherH && + "Mismatched headers even though found in the same map entry!"); + + assert(L->getLoopDepth() == OtherL->getLoopDepth() && + "Mismatched loop depth!"); + const LoopT *ParentL = L, *OtherParentL = OtherL; + do { + assert(ParentL->getHeader() == OtherParentL->getHeader() && + "Mismatched parent loop headers!"); + ParentL = ParentL->getParentLoop(); + OtherParentL = OtherParentL->getParentLoop(); + } while (ParentL); + + for (const LoopT *SubL : *L) { + BlockT *SubH = SubL->getHeader(); + const LoopT *OtherSubL = OtherLoopHeaders.lookup(SubH); + assert(OtherSubL && "Inner loop is missing in computed loop info!"); + OtherLoopHeaders.erase(SubH); + compareLoops(SubL, OtherSubL, OtherLoopHeaders); + } + + std::vector<BlockT *> BBs = L->getBlocks(); + std::vector<BlockT *> OtherBBs = OtherL->getBlocks(); + assert(compareVectors(BBs, OtherBBs) && + "Mismatched basic blocks in the loops!"); +} +#endif + template <class BlockT, class LoopT> void LoopInfoBase<BlockT, LoopT>::verify( const DominatorTreeBase<BlockT> &DomTree) const { @@ -559,42 +641,32 @@ void LoopInfoBase<BlockT, LoopT>::verify( LoopInfoBase<BlockT, LoopT> OtherLI; OtherLI.analyze(DomTree); - DenseMap<BlockT *, const LoopT *> LoopHeaders1; - DenseMap<BlockT *, const LoopT *> LoopHeaders2; - - for (LoopT *L : *this) - addInnerLoopsToHeadersMap(LoopHeaders1, *this, *L); + // Build a map we can use to move from our LI to the computed one. This + // allows us to ignore the particular order in any layer of the loop forest + // while still comparing the structure. + DenseMap<BlockT *, const LoopT *> OtherLoopHeaders; for (LoopT *L : OtherLI) - addInnerLoopsToHeadersMap(LoopHeaders2, OtherLI, *L); - assert(LoopHeaders1.size() == LoopHeaders2.size() && - "LoopInfo is incorrect."); - - auto compareLoops = [&](const LoopT *L1, const LoopT *L2) { - BlockT *H1 = L1->getHeader(); - BlockT *H2 = L2->getHeader(); - if (H1 != H2) - return false; - std::vector<BlockT *> BB1 = L1->getBlocks(); - std::vector<BlockT *> BB2 = L2->getBlocks(); - if (!compareVectors(BB1, BB2)) - return false; - - std::vector<BlockT *> SubLoopHeaders1; - std::vector<BlockT *> SubLoopHeaders2; - for (LoopT *L : *L1) - SubLoopHeaders1.push_back(L->getHeader()); - for (LoopT *L : *L2) - SubLoopHeaders2.push_back(L->getHeader()); - - if (!compareVectors(SubLoopHeaders1, SubLoopHeaders2)) - return false; - return true; - }; - - for (auto &I : LoopHeaders1) { - BlockT *H = I.first; - bool LoopsMatch = compareLoops(LoopHeaders1[H], LoopHeaders2[H]); - assert(LoopsMatch && "LoopInfo is incorrect."); + addInnerLoopsToHeadersMap(OtherLoopHeaders, OtherLI, *L); + + // Walk the top level loops and ensure there is a corresponding top-level + // loop in the computed version and then recursively compare those loop + // nests. + for (LoopT *L : *this) { + BlockT *Header = L->getHeader(); + const LoopT *OtherL = OtherLoopHeaders.lookup(Header); + assert(OtherL && "Top level loop is missing in computed loop info!"); + // Now that we've matched this loop, erase its header from the map. + OtherLoopHeaders.erase(Header); + // And recursively compare these loops. + compareLoops(L, OtherL, OtherLoopHeaders); + } + + // Any remaining entries in the map are loops which were found when computing + // a fresh LoopInfo but not present in the current one. + if (!OtherLoopHeaders.empty()) { + for (const auto &HeaderAndLoop : OtherLoopHeaders) + dbgs() << "Found new loop: " << *HeaderAndLoop.second << "\n"; + llvm_unreachable("Found new loops when recomputing LoopInfo!"); } #endif } diff --git a/include/llvm/Analysis/MemoryBuiltins.h b/include/llvm/Analysis/MemoryBuiltins.h index b58f07e69475..c5514316f75f 100644 --- a/include/llvm/Analysis/MemoryBuiltins.h +++ b/include/llvm/Analysis/MemoryBuiltins.h @@ -32,12 +32,6 @@ 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 /// like). @@ -129,17 +123,36 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) { // Utility functions to compute size of objects. // +/// Various options to control the behavior of getObjectSize. +struct ObjectSizeOpts { + /// Controls how we handle conditional statements with unknown conditions. + enum class Mode : uint8_t { + /// Fail to evaluate an unknown condition. + Exact, + /// Evaluate all branches of an unknown condition. If all evaluations + /// succeed, pick the minimum size. + Min, + /// Same as Min, except we pick the maximum size of all of the branches. + Max + }; + + /// How we want to evaluate this object's size. + Mode EvalMode = Mode::Exact; + /// Whether to round the result up to the alignment of allocas, byval + /// arguments, and global variables. + bool RoundToAlign = false; + /// If this is true, null pointers in address space 0 will be treated as + /// though they can't be evaluated. Otherwise, null is always considered to + /// point to a 0 byte region of memory. + bool NullIsUnknownSize = false; +}; + /// \brief Compute the size of the object pointed by Ptr. Returns true and the /// object size in Size if successful, and false otherwise. In this context, by /// object we mean the region of memory starting at Ptr to the end of the /// 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, - ObjSizeMode Mode = ObjSizeMode::Exact); + const TargetLibraryInfo *TLI, ObjectSizeOpts Opts = {}); /// Try to turn a call to @llvm.objectsize into an integer value of the given /// Type. Returns null on failure. @@ -160,8 +173,7 @@ class ObjectSizeOffsetVisitor const DataLayout &DL; const TargetLibraryInfo *TLI; - bool RoundToAlign; - ObjSizeMode Mode; + ObjectSizeOpts Options; unsigned IntTyBits; APInt Zero; SmallPtrSet<Instruction *, 8> SeenInsts; @@ -174,8 +186,7 @@ class ObjectSizeOffsetVisitor public: ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, - LLVMContext &Context, bool RoundToAlign = false, - ObjSizeMode Mode = ObjSizeMode::Exact); + LLVMContext &Context, ObjectSizeOpts Options = {}); SizeOffsetType compute(Value *V); diff --git a/include/llvm/Transforms/Utils/MemorySSA.h b/include/llvm/Analysis/MemorySSA.h index 408c6a157cd0..db31ae9f4f10 100644 --- a/include/llvm/Transforms/Utils/MemorySSA.h +++ b/include/llvm/Analysis/MemorySSA.h @@ -6,71 +6,71 @@ // 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. +/// +/// \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 +#ifndef LLVM_ANALYSIS_MEMORYSSA_H +#define LLVM_ANALYSIS_MEMORYSSA_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" @@ -79,6 +79,7 @@ #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/PHITransAddr.h" @@ -91,9 +92,7 @@ #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> @@ -104,12 +103,16 @@ namespace llvm { -class DominatorTree; class Function; class Instruction; class MemoryAccess; class LLVMContext; class raw_ostream; +namespace MSSAHelpers { +struct AllAccessTag {}; +struct DefsOnlyTag {}; +} + enum { // Used to signify what the default invalid ID is for MemoryAccess's // getID() @@ -123,21 +126,30 @@ using const_memoryaccess_def_iterator = // \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; - +class MemoryAccess + : public User, + public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>, + public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>> { public: + using AllAccessType = + ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>; + using DefsOnlyType = + ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>; + // 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(const MemoryAccess &) = delete; + MemoryAccess &operator=(const MemoryAccess &) = delete; ~MemoryAccess() override; + void *operator new(size_t, unsigned) = delete; + void *operator new(size_t) = delete; + BasicBlock *getBlock() const { return Block; } virtual void print(raw_ostream &OS) const = 0; @@ -155,6 +167,33 @@ public: memoryaccess_def_iterator defs_end(); const_memoryaccess_def_iterator defs_end() const; + /// \brief Get the iterators for the all access list and the defs only list + /// We default to the all access list. + AllAccessType::self_iterator getIterator() { + return this->AllAccessType::getIterator(); + } + AllAccessType::const_self_iterator getIterator() const { + return this->AllAccessType::getIterator(); + } + AllAccessType::reverse_self_iterator getReverseIterator() { + return this->AllAccessType::getReverseIterator(); + } + AllAccessType::const_reverse_self_iterator getReverseIterator() const { + return this->AllAccessType::getReverseIterator(); + } + DefsOnlyType::self_iterator getDefsIterator() { + return this->DefsOnlyType::getIterator(); + } + DefsOnlyType::const_self_iterator getDefsIterator() const { + return this->DefsOnlyType::getIterator(); + } + DefsOnlyType::reverse_self_iterator getReverseDefsIterator() { + return this->DefsOnlyType::getReverseIterator(); + } + DefsOnlyType::const_reverse_self_iterator getReverseDefsIterator() const { + return this->DefsOnlyType::getReverseIterator(); + } + protected: friend class MemorySSA; friend class MemoryUseOrDef; @@ -162,6 +201,10 @@ protected: friend class MemoryDef; friend class MemoryPhi; + /// \brief Used by MemorySSA to change the block of a MemoryAccess when it is + /// moved. + void setBlock(BasicBlock *BB) { Block = BB; } + /// \brief Used for debugging and tracking things about MemoryAccesses. /// Guaranteed unique among MemoryAccesses, no guarantees otherwise. virtual unsigned getID() const = 0; @@ -171,8 +214,6 @@ protected: : User(Type::getVoidTy(C), Vty, nullptr, NumOperands), Block(BB) {} private: - MemoryAccess(const MemoryAccess &); - void operator=(const MemoryAccess &); BasicBlock *Block; }; @@ -189,10 +230,10 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MemoryAccess &MA) { /// This class should never be instantiated directly; make a MemoryUse or /// MemoryDef instead. class MemoryUseOrDef : public MemoryAccess { +public: 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. @@ -201,21 +242,36 @@ public: /// \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; } + // Sadly, these have to be public because they are needed in some of the + // iterators. + virtual bool isOptimized() const = 0; + virtual MemoryAccess *getOptimized() const = 0; + virtual void setOptimized(MemoryAccess *) = 0; + + /// \brief Reset the ID of what this MemoryUse was optimized to, causing it to + /// be rewalked by the walker if necessary. + /// This really should only be called by tests. + virtual void resetOptimized() = 0; + protected: friend class MemorySSA; - + friend class MemorySSAUpdater; 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); } + void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) { + if (!Optimized) { + setOperand(0, DMA); + return; + } + setOptimized(DMA); + } private: Instruction *MemoryInst; @@ -232,35 +288,37 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUseOrDef, MemoryAccess) /// 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), OptimizedID(0) {} - static inline bool classof(const MemoryUse *) { return true; } + // allocate space for exactly one operand + void *operator new(size_t s) { return User::operator new(s, 1); } + void *operator new(size_t, unsigned) = delete; + static inline bool classof(const Value *MA) { return MA->getValueID() == MemoryUseVal; } void print(raw_ostream &OS) const override; - void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) { - if (Optimized) - OptimizedID = DMA->getID(); - MemoryUseOrDef::setDefiningAccess(DMA); + + virtual void setOptimized(MemoryAccess *DMA) override { + OptimizedID = DMA->getID(); + setOperand(0, DMA); } - bool isOptimized() const { + + virtual bool isOptimized() const override { return getDefiningAccess() && OptimizedID == getDefiningAccess()->getID(); } - /// \brief Reset the ID of what this MemoryUse was optimized to, causing it to - /// be rewalked by the walker if necessary. - /// This really should only be called by tests. - void resetOptimized() { OptimizedID = INVALID_MEMORYACCESS_ID; } + + virtual MemoryAccess *getOptimized() const override { + return getDefiningAccess(); + } + virtual void resetOptimized() override { + OptimizedID = INVALID_MEMORYACCESS_ID; + } protected: friend class MemorySSA; @@ -287,23 +345,35 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUse, MemoryAccess) /// 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) {} + : MemoryUseOrDef(C, DMA, MemoryDefVal, MI, BB), ID(Ver), + Optimized(nullptr), OptimizedID(INVALID_MEMORYACCESS_ID) {} + + // allocate space for exactly one operand + void *operator new(size_t s) { return User::operator new(s, 1); } + void *operator new(size_t, unsigned) = delete; - static inline bool classof(const MemoryDef *) { return true; } static inline bool classof(const Value *MA) { return MA->getValueID() == MemoryDefVal; } + virtual void setOptimized(MemoryAccess *MA) override { + Optimized = MA; + OptimizedID = getDefiningAccess()->getID(); + } + virtual MemoryAccess *getOptimized() const override { return Optimized; } + virtual bool isOptimized() const override { + return getOptimized() && getDefiningAccess() && + OptimizedID == getDefiningAccess()->getID(); + } + virtual void resetOptimized() override { + OptimizedID = INVALID_MEMORYACCESS_ID; + } + void print(raw_ostream &OS) const override; protected: @@ -313,6 +383,8 @@ protected: private: const unsigned ID; + MemoryAccess *Optimized; + unsigned int OptimizedID; }; template <> @@ -352,7 +424,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryDef, MemoryAccess) /// 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); } @@ -365,6 +436,8 @@ public: allocHungoffUses(ReservedSpace); } + void *operator new(size_t, unsigned) = delete; + // Block iterator interface. This provides access to the list of incoming // basic blocks, which parallels the list of incoming values. typedef BasicBlock **block_iterator; @@ -457,7 +530,6 @@ public: return getIncomingValue(Idx); } - static inline bool classof(const MemoryPhi *) { return true; } static inline bool classof(const Value *V) { return V->getValueID() == MemoryPhiVal; } @@ -466,6 +538,7 @@ public: 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. @@ -529,7 +602,14 @@ public: return LiveOnEntryDef.get(); } - using AccessList = iplist<MemoryAccess>; + // Sadly, iplists, by default, owns and deletes pointers added to the + // list. It's not currently possible to have two iplists for the same type, + // where one owns the pointers, and one does not. This is because the traits + // are per-type, not per-tag. If this ever changes, we should make the + // DefList an iplist. + using AccessList = iplist<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>; + using DefsList = + simple_ilist<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>; /// \brief Return the list of MemoryAccess's for a given basic block. /// @@ -538,62 +618,13 @@ public: return getWritableBlockAccesses(BB); } - /// \brief Create an empty MemoryPhi in MemorySSA for a given basic block. - /// Only one MemoryPhi for a block exists at a time, so this function will - /// assert if you try to create one where it already exists. - 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. - /// Note: If a MemoryAccess already exists for I, this function will make it - /// inaccessible and it *must* have removeMemoryAccess called on it. - MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition, - const BasicBlock *BB, - InsertionPlace Point); - /// \brief Create a MemoryAccess in MemorySSA before or after an existing - /// MemoryAccess. + /// \brief Return the list of MemoryDef's and MemoryPhi's for a given basic + /// block. /// - /// 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. - /// Note: If a MemoryAccess already exists for I, this function will make it - /// inaccessible and it *must* have removeMemoryAccess called on it. - MemoryUseOrDef *createMemoryAccessBefore(Instruction *I, - MemoryAccess *Definition, - MemoryUseOrDef *InsertPt); - MemoryUseOrDef *createMemoryAccessAfter(Instruction *I, - MemoryAccess *Definition, - MemoryAccess *InsertPt); - - // \brief Splice \p What to just before \p Where. - // - // In order to be efficient, the following conditions must be met: - // - \p Where dominates \p What, - // - All memory accesses in [\p Where, \p What) are no-alias with \p What. - // - // TODO: relax the MemoryDef requirement on Where. - void spliceMemoryAccessAbove(MemoryDef *Where, MemoryUseOrDef *What); - - /// \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 *); + /// This list is not modifiable by the user. + const DefsList *getBlockDefs(const BasicBlock *BB) const { + return getWritableBlockDefs(BB); + } /// \brief Given two memory accesses in the same basic block, determine /// whether MemoryAccess \p A dominates MemoryAccess \p B. @@ -611,20 +642,51 @@ public: /// all uses, uses appear in the right places). This is used by unit tests. void verifyMemorySSA() const; + /// Used in various insertion functions to specify whether we are talking + /// about the beginning or end of a block. + enum InsertionPlace { Beginning, End }; + protected: // Used by Memory SSA annotater, dumpers, and wrapper pass friend class MemorySSAAnnotatedWriter; friend class MemorySSAPrinterLegacyPass; + friend class MemorySSAUpdater; + void verifyDefUses(Function &F) const; void verifyDomination(Function &F) const; void verifyOrdering(Function &F) const; - // This is used by the use optimizer class + // This is used by the use optimizer and updater. AccessList *getWritableBlockAccesses(const BasicBlock *BB) const { auto It = PerBlockAccesses.find(BB); return It == PerBlockAccesses.end() ? nullptr : It->second.get(); } + // This is used by the use optimizer and updater. + DefsList *getWritableBlockDefs(const BasicBlock *BB) const { + auto It = PerBlockDefs.find(BB); + return It == PerBlockDefs.end() ? nullptr : It->second.get(); + } + + // These is used by the updater to perform various internal MemorySSA + // machinsations. They do not always leave the IR in a correct state, and + // relies on the updater to fixup what it breaks, so it is not public. + + void moveTo(MemoryUseOrDef *What, BasicBlock *BB, AccessList::iterator Where); + void moveTo(MemoryUseOrDef *What, BasicBlock *BB, InsertionPlace Point); + // Rename the dominator tree branch rooted at BB. + void renamePass(BasicBlock *BB, MemoryAccess *IncomingVal, + SmallPtrSetImpl<BasicBlock *> &Visited) { + renamePass(DT->getNode(BB), IncomingVal, Visited, true, true); + } + void removeFromLookups(MemoryAccess *); + void removeFromLists(MemoryAccess *, bool ShouldDelete = true); + void insertIntoListsForBlock(MemoryAccess *, const BasicBlock *, + InsertionPlace); + void insertIntoListsBefore(MemoryAccess *, const BasicBlock *, + AccessList::iterator); + MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *); + private: class CachingWalker; class OptimizeUses; @@ -635,32 +697,39 @@ private: void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const; using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>; + using DefsMap = DenseMap<const BasicBlock *, std::unique_ptr<DefsList>>; void determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks); - void computeDomLevels(DenseMap<DomTreeNode *, unsigned> &DomLevels); void markUnreachableAsLiveOnEntry(BasicBlock *BB); bool dominatesUse(const MemoryAccess *, const MemoryAccess *) const; + MemoryPhi *createMemoryPhi(BasicBlock *BB); MemoryUseOrDef *createNewAccess(Instruction *); - MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *); MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace); - void removeFromLookups(MemoryAccess *); - void placePHINodes(const SmallPtrSetImpl<BasicBlock *> &, const DenseMap<const BasicBlock *, unsigned int> &); - MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *); + MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *, bool); + void renameSuccessorPhis(BasicBlock *, MemoryAccess *, bool); void renamePass(DomTreeNode *, MemoryAccess *IncomingVal, - SmallPtrSet<BasicBlock *, 16> &Visited); + SmallPtrSetImpl<BasicBlock *> &Visited, + bool SkipVisited = false, bool RenameAllUses = false); AccessList *getOrCreateAccessList(const BasicBlock *); + DefsList *getOrCreateDefsList(const BasicBlock *); void renumberBlock(const BasicBlock *) const; - AliasAnalysis *AA; DominatorTree *DT; Function &F; // Memory SSA mappings DenseMap<const Value *, MemoryAccess *> ValueToMemoryAccess; + // These two mappings contain the main block to access/def mappings for + // MemorySSA. The list contained in PerBlockAccesses really owns all the + // MemoryAccesses. + // Both maps maintain the invariant that if a block is found in them, the + // corresponding list is not empty, and if a block is not found in them, the + // corresponding list is empty. AccessMap PerBlockAccesses; + DefsMap PerBlockDefs; std::unique_ptr<MemoryAccess> LiveOnEntryDef; // Domination mappings @@ -674,21 +743,33 @@ private: unsigned NextID; }; +// Internal MemorySSA utils, for use by MemorySSA classes and walkers +class MemorySSAUtil { +protected: + friend class MemorySSAWalker; + friend class GVNHoist; + // This function should not be used by new passes. + static bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU, + AliasAnalysis &AA); +}; + // 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; + + static char ID; }; /// An analysis that produces \c MemorySSA for a function. /// class MemorySSAAnalysis : public AnalysisInfoMixin<MemorySSAAnalysis> { friend AnalysisInfoMixin<MemorySSAAnalysis>; + static AnalysisKey Key; public: @@ -711,6 +792,7 @@ class MemorySSAPrinterPass : public PassInfoMixin<MemorySSAPrinterPass> { public: explicit MemorySSAPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; @@ -725,6 +807,7 @@ public: MemorySSAWrapperPass(); static char ID; + bool runOnFunction(Function &) override; void releaseMemory() override; MemorySSA &getMSSA() { return *MSSA; } @@ -753,7 +836,7 @@ private: class MemorySSAWalker { public: MemorySSAWalker(MemorySSA *); - virtual ~MemorySSAWalker() {} + virtual ~MemorySSAWalker() = default; using MemoryAccessSet = SmallVector<MemoryAccess *, 8>; @@ -825,6 +908,7 @@ public: // Keep the overrides below from hiding the Instruction overload of // getClobberingMemoryAccess. using MemorySSAWalker::getClobberingMemoryAccess; + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) override; MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, const MemoryLocation &) override; @@ -843,8 +927,9 @@ class memoryaccess_def_iterator_base 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) {} + memoryaccess_def_iterator_base(T *Start) : Access(Start) {} + memoryaccess_def_iterator_base() = default; + bool operator==(const memoryaccess_def_iterator_base &Other) const { return Access == Other.Access && (!Access || ArgNo == Other.ArgNo); } @@ -883,8 +968,8 @@ public: } private: - T *Access; - unsigned ArgNo; + T *Access = nullptr; + unsigned ArgNo = 0; }; inline memoryaccess_def_iterator MemoryAccess::defs_begin() { @@ -947,10 +1032,7 @@ public: fillInCurrentPair(); } - upward_defs_iterator() - : DefIterator(), Location(), OriginalAccess(), WalkingPhi(false) { - CurrentPair.first = nullptr; - } + upward_defs_iterator() { CurrentPair.first = nullptr; } bool operator==(const upward_defs_iterator &Other) const { return DefIterator == Other.DefIterator; @@ -995,8 +1077,8 @@ private: MemoryAccessPair CurrentPair; memoryaccess_def_iterator DefIterator; MemoryLocation Location; - MemoryAccess *OriginalAccess; - bool WalkingPhi; + MemoryAccess *OriginalAccess = nullptr; + bool WalkingPhi = false; }; inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) { @@ -1005,10 +1087,69 @@ inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) { inline upward_defs_iterator upward_defs_end() { return upward_defs_iterator(); } -// Return true when MD may alias MU, return false otherwise. -bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU, - AliasAnalysis &AA); +inline iterator_range<upward_defs_iterator> +upward_defs(const MemoryAccessPair &Pair) { + return make_range(upward_defs_begin(Pair), upward_defs_end()); +} + +/// Walks the defining accesses of MemoryDefs. Stops after we hit something that +/// has no defining use (e.g. a MemoryPhi or liveOnEntry). Note that, when +/// comparing against a null def_chain_iterator, this will compare equal only +/// after walking said Phi/liveOnEntry. +/// +/// The UseOptimizedChain flag specifies whether to walk the clobbering +/// access chain, or all the accesses. +/// +/// Normally, MemoryDef are all just def/use linked together, so a def_chain on +/// a MemoryDef will walk all MemoryDefs above it in the program until it hits +/// a phi node. The optimized chain walks the clobbering access of a store. +/// So if you are just trying to find, given a store, what the next +/// thing that would clobber the same memory is, you want the optimized chain. +template <class T, bool UseOptimizedChain = false> +struct def_chain_iterator + : public iterator_facade_base<def_chain_iterator<T, UseOptimizedChain>, + std::forward_iterator_tag, MemoryAccess *> { + def_chain_iterator() : MA(nullptr) {} + def_chain_iterator(T MA) : MA(MA) {} + + T operator*() const { return MA; } + + def_chain_iterator &operator++() { + // N.B. liveOnEntry has a null defining access. + if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) { + if (UseOptimizedChain && MUD->isOptimized()) + MA = MUD->getOptimized(); + else + MA = MUD->getDefiningAccess(); + } else { + MA = nullptr; + } + + return *this; + } + + bool operator==(const def_chain_iterator &O) const { return MA == O.MA; } + +private: + T MA; +}; + +template <class T> +inline iterator_range<def_chain_iterator<T>> +def_chain(T MA, MemoryAccess *UpTo = nullptr) { +#ifdef EXPENSIVE_CHECKS + assert((!UpTo || find(def_chain(MA), UpTo) != def_chain_iterator<T>()) && + "UpTo isn't in the def chain!"); +#endif + return make_range(def_chain_iterator<T>(MA), def_chain_iterator<T>(UpTo)); +} + +template <class T> +inline iterator_range<def_chain_iterator<T, true>> optimized_def_chain(T MA) { + return make_range(def_chain_iterator<T, true>(MA), + def_chain_iterator<T, true>(nullptr)); +} } // end namespace llvm -#endif // LLVM_TRANSFORMS_UTILS_MEMORYSSA_H +#endif // LLVM_ANALYSIS_MEMORYSSA_H diff --git a/include/llvm/Analysis/MemorySSAUpdater.h b/include/llvm/Analysis/MemorySSAUpdater.h new file mode 100644 index 000000000000..d30eeeaa95b6 --- /dev/null +++ b/include/llvm/Analysis/MemorySSAUpdater.h @@ -0,0 +1,153 @@ +//===- MemorySSAUpdater.h - Memory SSA Updater-------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// \file +// \brief An automatic updater for MemorySSA that handles arbitrary insertion, +// deletion, and moves. It performs phi insertion where necessary, and +// automatically updates the MemorySSA IR to be correct. +// While updating loads or removing instructions is often easy enough to not +// need this, updating stores should generally not be attemped outside this +// API. +// +// Basic API usage: +// Create the memory access you want for the instruction (this is mainly so +// we know where it is, without having to duplicate the entire set of create +// functions MemorySSA supports). +// Call insertDef or insertUse depending on whether it's a MemoryUse or a +// MemoryDef. +// That's it. +// +// For moving, first, move the instruction itself using the normal SSA +// instruction moving API, then just call moveBefore, moveAfter,or moveTo with +// the right arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_MEMORYSSAUPDATER_H +#define LLVM_ANALYSIS_MEMORYSSAUPDATER_H + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.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/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Analysis/MemorySSA.h" + +namespace llvm { + +class Function; +class Instruction; +class MemoryAccess; +class LLVMContext; +class raw_ostream; + +class MemorySSAUpdater { +private: + MemorySSA *MSSA; + SmallVector<MemoryPhi *, 8> InsertedPHIs; + SmallPtrSet<BasicBlock *, 8> VisitedBlocks; + +public: + MemorySSAUpdater(MemorySSA *MSSA) : MSSA(MSSA) {} + /// Insert a definition into the MemorySSA IR. RenameUses will rename any use + /// below the new def block (and any inserted phis). RenameUses should be set + /// to true if the definition may cause new aliases for loads below it. This + /// is not the case for hoisting or sinking or other forms of code *movement*. + /// It *is* the case for straight code insertion. + /// For example: + /// store a + /// if (foo) { } + /// load a + /// + /// Moving the store into the if block, and calling insertDef, does not + /// require RenameUses. + /// However, changing it to: + /// store a + /// if (foo) { store b } + /// load a + /// Where a mayalias b, *does* require RenameUses be set to true. + void insertDef(MemoryDef *Def, bool RenameUses = false); + void insertUse(MemoryUse *Use); + void moveBefore(MemoryUseOrDef *What, MemoryUseOrDef *Where); + void moveAfter(MemoryUseOrDef *What, MemoryUseOrDef *Where); + void moveToPlace(MemoryUseOrDef *What, BasicBlock *BB, + MemorySSA::InsertionPlace Where); + + // The below are utility functions. Other than creation of accesses to pass + // to insertDef, and removeAccess to remove accesses, you should generally + // not attempt to update memoryssa yourself. It is very non-trivial to get + // the edge cases right, and the above calls already operate in near-optimal + // time bounds. + + /// \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. + /// Note: If a MemoryAccess already exists for I, this function will make it + /// inaccessible and it *must* have removeMemoryAccess called on it. + MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition, + const BasicBlock *BB, + MemorySSA::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. + /// + /// Note: If a MemoryAccess already exists for I, this function will make it + /// inaccessible and it *must* have removeMemoryAccess called on it. + MemoryUseOrDef *createMemoryAccessBefore(Instruction *I, + MemoryAccess *Definition, + MemoryUseOrDef *InsertPt); + MemoryUseOrDef *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 *); + +private: + // Move What before Where in the MemorySSA IR. + template <class WhereType> + void moveTo(MemoryUseOrDef *What, BasicBlock *BB, WhereType Where); + MemoryAccess *getPreviousDef(MemoryAccess *); + MemoryAccess *getPreviousDefInBlock(MemoryAccess *); + MemoryAccess *getPreviousDefFromEnd(BasicBlock *); + MemoryAccess *getPreviousDefRecursive(BasicBlock *); + MemoryAccess *recursePhi(MemoryAccess *Phi); + template <class RangeType> + MemoryAccess *tryRemoveTrivialPhi(MemoryPhi *Phi, RangeType &Operands); + void fixupDefs(const SmallVectorImpl<MemoryAccess *> &); +}; +} // end namespace llvm + +#endif // LLVM_ANALYSIS_MEMORYSSAUPDATER_H diff --git a/include/llvm/Analysis/ObjectUtils.h b/include/llvm/Analysis/ObjectUtils.h new file mode 100644 index 000000000000..2ad3b1717009 --- /dev/null +++ b/include/llvm/Analysis/ObjectUtils.h @@ -0,0 +1,42 @@ +//===- Analysis/ObjectUtils.h - analysis utils for object 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_ANALYSIS_OBJECT_UTILS_H +#define LLVM_ANALYSIS_OBJECT_UTILS_H + +#include "llvm/IR/GlobalVariable.h" + +namespace llvm { + +/// True if GV can be left out of the object symbol table. This is the case +/// for linkonce_odr values whose address is not significant. While legal, it is +/// not normally profitable to omit them from the .o symbol table. Using this +/// analysis makes sense when the information can be passed down to the linker +/// or we are in LTO. +inline bool canBeOmittedFromSymbolTable(const GlobalValue *GV) { + if (!GV->hasLinkOnceODRLinkage()) + return false; + + // We assume that anyone who sets global unnamed_addr on a non-constant knows + // what they're doing. + if (GV->hasGlobalUnnamedAddr()) + return true; + + // If it is a non constant variable, it needs to be uniqued across shared + // objects. + if (auto *Var = dyn_cast<GlobalVariable>(GV)) + if (!Var->isConstant()) + return false; + + return GV->hasAtLeastLocalUnnamedAddr(); +} + +} + +#endif diff --git a/include/llvm/Analysis/OptimizationDiagnosticInfo.h b/include/llvm/Analysis/OptimizationDiagnosticInfo.h index 39269269c244..edd9140a3493 100644 --- a/include/llvm/Analysis/OptimizationDiagnosticInfo.h +++ b/include/llvm/Analysis/OptimizationDiagnosticInfo.h @@ -38,7 +38,7 @@ class Value; /// enabled in the LLVM context. class OptimizationRemarkEmitter { public: - OptimizationRemarkEmitter(Function *F, BlockFrequencyInfo *BFI) + OptimizationRemarkEmitter(const Function *F, BlockFrequencyInfo *BFI) : F(F), BFI(BFI) {} /// \brief This variant can be used to generate ORE on demand (without the @@ -52,7 +52,7 @@ public: /// operation since BFI and all its required analyses are computed. This is /// for example useful for CGSCC passes that can't use function analyses /// passes in the old PM. - OptimizationRemarkEmitter(Function *F); + OptimizationRemarkEmitter(const Function *F); OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg) : F(Arg.F), BFI(Arg.BFI) {} @@ -63,136 +63,16 @@ public: return *this; } - /// The new interface to emit remarks. - void emit(DiagnosticInfoOptimizationBase &OptDiag); - - /// Emit an optimization-applied message. - /// - /// \p PassName is the name of the pass emitting the message. If -Rpass= is - /// given and \p PassName matches the regular expression in -Rpass, then the - /// remark will be emitted. \p Fn is the function triggering the remark, \p - /// DLoc is the debug location where the diagnostic is generated. \p V is the - /// IR Value that identifies the code region. \p Msg is the message string to - /// use. - void emitOptimizationRemark(const char *PassName, const DebugLoc &DLoc, - const 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 emitOptimizationRemark(const char *PassName, Loop *L, const Twine &Msg); - - /// \brief Same as above but derives the debug location and the code region - /// from the debug location and the basic block of \p Inst, respectively. - void emitOptimizationRemark(const char *PassName, Instruction *Inst, - const Twine &Msg) { - emitOptimizationRemark(PassName, Inst->getDebugLoc(), Inst->getParent(), - Msg); - } - - /// 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 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. If \p IsVerbose is - /// true, the message is considered verbose and will only be emitted when - /// verbose output is turned on. - void emitOptimizationRemarkMissed(const char *PassName, const DebugLoc &DLoc, - const Value *V, const Twine &Msg, - bool IsVerbose = false); - - /// \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, bool IsVerbose = false); - - /// \brief Same as above but derives the debug location and the code region - /// from the debug location and the basic block of \p Inst, respectively. - void emitOptimizationRemarkMissed(const char *PassName, Instruction *Inst, - const Twine &Msg, bool IsVerbose = false) { - emitOptimizationRemarkMissed(PassName, Inst->getDebugLoc(), - Inst->getParent(), Msg, IsVerbose); - } - - /// Emit an optimization analysis remark message. - /// - /// \p PassName is the name of the pass emitting the message. If - /// -Rpass-analysis= is given and \p PassName matches the regular expression - /// in -Rpass, then the remark will be emitted. \p 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. If \p IsVerbose is - /// true, the message is considered verbose and will only be emitted when - /// verbose output is turned on. - void emitOptimizationRemarkAnalysis(const char *PassName, - const DebugLoc &DLoc, const Value *V, - const Twine &Msg, bool IsVerbose = false); - - /// \brief Same as above but derives the IR Value for the code region and the - /// debug location from the Loop parameter \p L. - void emitOptimizationRemarkAnalysis(const char *PassName, Loop *L, - const Twine &Msg, bool IsVerbose = false); + /// Handle invalidation events in the new pass manager. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv); - /// \brief Same as above but derives the debug location and the code region - /// from the debug location and the basic block of \p Inst, respectively. - void emitOptimizationRemarkAnalysis(const char *PassName, Instruction *Inst, - const Twine &Msg, - bool IsVerbose = false) { - emitOptimizationRemarkAnalysis(PassName, Inst->getDebugLoc(), - Inst->getParent(), Msg, IsVerbose); - } - - /// \brief This variant allows specifying what should be emitted for missed - /// and analysis remarks in one call. - /// - /// \p PassName is the name of the pass emitting the message. If - /// -Rpass-missed= is given and \p PassName matches the regular expression, \p - /// MsgForMissedRemark is emitted. - /// - /// If -Rpass-analysis= is given and \p PassName matches the regular - /// expression, \p MsgForAnalysisRemark is emitted. - /// - /// The debug location and the code region is derived from \p Inst. If \p - /// IsVerbose is true, the message is considered verbose and will only be - /// emitted when verbose output is turned on. - void emitOptimizationRemarkMissedAndAnalysis( - const char *PassName, Instruction *Inst, const Twine &MsgForMissedRemark, - const Twine &MsgForAnalysisRemark, bool IsVerbose = false) { - emitOptimizationRemarkAnalysis(PassName, Inst, MsgForAnalysisRemark, - IsVerbose); - emitOptimizationRemarkMissed(PassName, Inst, MsgForMissedRemark, IsVerbose); - } - - /// \brief Emit an optimization analysis remark related to floating-point - /// non-commutativity. + /// \brief Output the remark via the diagnostic handler and to the + /// optimization record file. /// - /// \p PassName is the name of the pass emitting the message. If - /// -Rpass-analysis= is given and \p PassName matches the regular expression - /// in -Rpass, then the remark will be emitted. \p Fn is the function - /// triggering the remark, \p DLoc is the debug location where the diagnostic - /// is generated.\p V is the IR Value that identifies the code region. \p Msg - /// is the message string to use. - void emitOptimizationRemarkAnalysisFPCommute(const char *PassName, - const DebugLoc &DLoc, - const Value *V, - const Twine &Msg); - - /// \brief Emit an optimization analysis remark related to pointer aliasing. - /// - /// \p PassName is the name of the pass emitting the message. If - /// -Rpass-analysis= is given and \p PassName matches the regular expression - /// in -Rpass, then the remark will be emitted. \p Fn is the function - /// triggering the remark, \p DLoc is the debug location where the diagnostic - /// is generated.\p V is the IR Value that identifies the code region. \p Msg - /// is the message string to use. - void emitOptimizationRemarkAnalysisAliasing(const char *PassName, - const DebugLoc &DLoc, - const 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 emitOptimizationRemarkAnalysisAliasing(const char *PassName, Loop *L, - const Twine &Msg); + /// This is the new interface that should be now used rather than the legacy + /// emit* APIs. + void emit(DiagnosticInfoOptimizationBase &OptDiag); /// \brief Whether we allow for extra compile-time budget to perform more /// analysis to produce fewer false positives. @@ -208,7 +88,7 @@ public: } private: - Function *F; + const Function *F; BlockFrequencyInfo *BFI; @@ -220,7 +100,7 @@ private: Optional<uint64_t> computeHotness(const Value *V); /// Similar but use value from \p OptDiag and update hotness there. - void computeHotness(DiagnosticInfoOptimizationBase &OptDiag); + void computeHotness(DiagnosticInfoIROptimization &OptDiag); /// \brief Only allow verbose messages if we know we're filtering by hotness /// (BFI is only set in this case). @@ -274,5 +154,11 @@ public: /// \brief Run the analysis pass over a function and produce BFI. Result run(Function &F, FunctionAnalysisManager &AM); }; + +namespace yaml { +template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> { + static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag); +}; +} } #endif // LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H diff --git a/include/llvm/Analysis/PostDominators.h b/include/llvm/Analysis/PostDominators.h index 34361dac8c16..94ee3b03bb86 100644 --- a/include/llvm/Analysis/PostDominators.h +++ b/include/llvm/Analysis/PostDominators.h @@ -26,6 +26,10 @@ struct PostDominatorTree : public DominatorTreeBase<BasicBlock> { typedef DominatorTreeBase<BasicBlock> Base; PostDominatorTree() : DominatorTreeBase<BasicBlock>(true) {} + + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); }; /// \brief Analysis pass which computes a \c PostDominatorTree. diff --git a/include/llvm/Analysis/ProfileSummaryInfo.h b/include/llvm/Analysis/ProfileSummaryInfo.h index d7fe76e278e3..1aec35c3e677 100644 --- a/include/llvm/Analysis/ProfileSummaryInfo.h +++ b/include/llvm/Analysis/ProfileSummaryInfo.h @@ -29,6 +29,7 @@ namespace llvm { class BasicBlock; class BlockFrequencyInfo; +class CallSite; class ProfileSummary; /// \brief Analysis providing profile information. /// @@ -44,7 +45,7 @@ class ProfileSummaryInfo { private: Module &M; std::unique_ptr<ProfileSummary> Summary; - void computeSummary(); + bool computeSummary(); void computeThresholds(); // Count thresholds to answer isHotCount and isColdCount queries. Optional<uint64_t> HotCountThreshold, ColdCountThreshold; @@ -53,16 +54,29 @@ public: ProfileSummaryInfo(Module &M) : M(M) {} ProfileSummaryInfo(ProfileSummaryInfo &&Arg) : M(Arg.M), Summary(std::move(Arg.Summary)) {} + /// Returns the profile count for \p CallInst. + static Optional<uint64_t> getProfileCount(const Instruction *CallInst, + BlockFrequencyInfo *BFI); /// \brief Returns true if \p F has hot function entry. bool isFunctionEntryHot(const Function *F); + /// Returns true if \p F has hot function entry or hot call edge. + bool isFunctionHotInCallGraph(const Function *F); /// \brief Returns true if \p F has cold function entry. bool isFunctionEntryCold(const Function *F); + /// Returns true if \p F has cold function entry or cold call edge. + bool isFunctionColdInCallGraph(const Function *F); /// \brief Returns true if \p F is a hot function. bool isHotCount(uint64_t C); /// \brief Returns true if count \p C is considered cold. bool isColdCount(uint64_t C); /// \brief Returns true if BasicBlock \p B is considered hot. bool isHotBB(const BasicBlock *B, BlockFrequencyInfo *BFI); + /// \brief Returns true if BasicBlock \p B is considered cold. + bool isColdBB(const BasicBlock *B, BlockFrequencyInfo *BFI); + /// \brief Returns true if CallSite \p CS is considered hot. + bool isHotCallSite(const CallSite &CS, BlockFrequencyInfo *BFI); + /// \brief Returns true if Callsite \p CS is considered cold. + bool isColdCallSite(const CallSite &CS, BlockFrequencyInfo *BFI); }; /// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo. diff --git a/include/llvm/Analysis/PtrUseVisitor.h b/include/llvm/Analysis/PtrUseVisitor.h index 6e61fc3be384..2fe7c6725266 100644 --- a/include/llvm/Analysis/PtrUseVisitor.h +++ b/include/llvm/Analysis/PtrUseVisitor.h @@ -196,7 +196,10 @@ class PtrUseVisitor : protected InstVisitor<DerivedT>, typedef InstVisitor<DerivedT> Base; public: - PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) {} + PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) { + static_assert(std::is_base_of<PtrUseVisitor, DerivedT>::value, + "Must pass the derived type to this template!"); + } /// \brief Recursively visit the uses of the given pointer. /// \returns An info struct about the pointer. See \c PtrInfo for details. diff --git a/include/llvm/Analysis/RegionInfo.h b/include/llvm/Analysis/RegionInfo.h index f2f27a137a88..caeb21db613e 100644 --- a/include/llvm/Analysis/RegionInfo.h +++ b/include/llvm/Analysis/RegionInfo.h @@ -886,6 +886,10 @@ public: return *this; } + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); + // updateStatistics - Update statistic about created regions. void updateStatistics(Region *R) final; diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 1a93f9aa5fd2..9a50de540f2b 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -543,6 +543,12 @@ private: /// predicate by splitting it into a set of independent predicates. bool ProvingSplitPredicate; + /// Memoized values for the GetMinTrailingZeros + DenseMap<const SCEV *, uint32_t> MinTrailingZerosCache; + + /// Private helper method for the GetMinTrailingZeros method + uint32_t GetMinTrailingZerosImpl(const SCEV *S); + /// Information about the number of loop iterations for which a loop exit's /// branch condition evaluates to the not-taken path. This is a temporary /// pair of exact and max expressions that are eventually summarized in @@ -600,14 +606,14 @@ private: /// Information about the number of times a particular loop exit may be /// reached before exiting the loop. struct ExitNotTakenInfo { - AssertingVH<BasicBlock> ExitingBlock; + PoisoningVH<BasicBlock> ExitingBlock; const SCEV *ExactNotTaken; std::unique_ptr<SCEVUnionPredicate> Predicate; bool hasAlwaysTruePredicate() const { return !Predicate || Predicate->isAlwaysTrue(); } - explicit ExitNotTakenInfo(AssertingVH<BasicBlock> ExitingBlock, + explicit ExitNotTakenInfo(PoisoningVH<BasicBlock> ExitingBlock, const SCEV *ExactNotTaken, std::unique_ptr<SCEVUnionPredicate> Predicate) : ExitingBlock(ExitingBlock), ExactNotTaken(ExactNotTaken), @@ -972,6 +978,20 @@ private: /// Test whether the condition described by Pred, LHS, and RHS is true /// whenever the condition described by Pred, FoundLHS, and FoundRHS is + /// true. Here LHS is an operation that includes FoundLHS as one of its + /// arguments. + bool isImpliedViaOperations(ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS, + const SCEV *FoundLHS, const SCEV *FoundRHS, + unsigned Depth = 0); + + /// Test whether the condition described by Pred, LHS, and RHS is true. + /// Use only simple non-recursive types of checks, such as range analysis etc. + bool isKnownViaSimpleReasoning(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. bool isImpliedCondOperandsHelper(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, const SCEV *FoundLHS, @@ -1065,18 +1085,6 @@ private: bool isMonotonicPredicateImpl(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred, bool &Increasing); - /// Return true if, for all loop invariant X, the predicate "LHS `Pred` X" - /// is monotonically increasing or decreasing. In the former case set - /// `Increasing` to true and in the latter case set `Increasing` to false. - /// - /// A predicate is said to be monotonically increasing if may go from being - /// false to being true as the loop iterates, but never the other way - /// around. A predicate is said to be monotonically decreasing if may go - /// from being true to being false as the loop iterates, but never the other - /// way around. - 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. @@ -1129,6 +1137,9 @@ public: /// return true. For pointer types, this is the pointer-sized integer type. Type *getEffectiveSCEVType(Type *Ty) const; + // Returns a wider type among {Ty1, Ty2}. + Type *getWiderType(Type *Ty1, Type *Ty2) const; + /// Return true if the SCEV is a scAddRecExpr or it contains /// scAddRecExpr. The result will be cached in HasRecMap. /// @@ -1152,7 +1163,8 @@ public: const SCEV *getSignExtendExpr(const SCEV *Op, Type *Ty); const SCEV *getAnyExtendExpr(const SCEV *Op, Type *Ty); const SCEV *getAddExpr(SmallVectorImpl<const SCEV *> &Ops, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap); + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0); const SCEV *getAddExpr(const SCEV *LHS, const SCEV *RHS, SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) { SmallVector<const SCEV *, 2> Ops = {LHS, RHS}; @@ -1301,7 +1313,7 @@ public: /// /// Implemented in terms of the \c getSmallConstantTripCount overload with /// the single exiting block passed to it. See that routine for details. - unsigned getSmallConstantTripCount(Loop *L); + unsigned getSmallConstantTripCount(const Loop *L); /// Returns the maximum trip count of this loop as a normal unsigned /// value. Returns 0 if the trip count is unknown or not constant. This @@ -1310,12 +1322,12 @@ public: /// before taking the branch. For loops with multiple exits, it may not be /// the number times that the loop header executes if the loop exits /// prematurely via another branch. - unsigned getSmallConstantTripCount(Loop *L, BasicBlock *ExitingBlock); + unsigned getSmallConstantTripCount(const Loop *L, BasicBlock *ExitingBlock); /// Returns the upper bound of the loop trip count as a normal unsigned /// value. /// Returns 0 if the trip count is unknown or not constant. - unsigned getSmallConstantMaxTripCount(Loop *L); + unsigned getSmallConstantMaxTripCount(const Loop *L); /// 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 @@ -1323,7 +1335,7 @@ public: /// /// Implemented in terms of the \c getSmallConstantTripMultiple overload with /// the single exiting block passed to it. See that routine for details. - unsigned getSmallConstantTripMultiple(Loop *L); + unsigned getSmallConstantTripMultiple(const Loop *L); /// Returns the largest constant divisor of the trip count of this loop as a /// normal unsigned value, if possible. This means that the actual trip @@ -1331,12 +1343,13 @@ public: /// count could very well be zero as well!). As explained in the comments /// for getSmallConstantTripCount, this assumes that control exits the loop /// via ExitingBlock. - unsigned getSmallConstantTripMultiple(Loop *L, BasicBlock *ExitingBlock); + unsigned getSmallConstantTripMultiple(const Loop *L, + BasicBlock *ExitingBlock); /// Get the expression for the number of loop iterations for which this loop /// is guaranteed not to exit via ExitingBlock. Otherwise return /// SCEVCouldNotCompute. - const SCEV *getExitCount(Loop *L, BasicBlock *ExitingBlock); + const SCEV *getExitCount(const Loop *L, BasicBlock *ExitingBlock); /// If the specified loop has a predictable backedge-taken count, return it, /// otherwise return a SCEVCouldNotCompute object. The backedge-taken count @@ -1432,6 +1445,18 @@ public: bool isKnownPredicate(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS); + /// Return true if, for all loop invariant X, the predicate "LHS `Pred` X" + /// is monotonically increasing or decreasing. In the former case set + /// `Increasing` to true and in the latter case set `Increasing` to false. + /// + /// A predicate is said to be monotonically increasing if may go from being + /// false to being true as the loop iterates, but never the other way + /// around. A predicate is said to be monotonically decreasing if may go + /// from being true to being false as the loop iterates, but never the other + /// way around. + bool isMonotonicPredicate(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred, + bool &Increasing); + /// Return true if the result of the predicate LHS `Pred` RHS is loop /// invariant with respect to L. Set InvariantPred, InvariantLHS and /// InvariantLHS so that InvariantLHS `InvariantPred` InvariantRHS is the @@ -1613,6 +1638,10 @@ private: bool doesIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride, bool IsSigned, bool NoWrap); + /// Get add expr already created or create a new one + const SCEV *getOrCreateAddExpr(SmallVectorImpl<const SCEV *> &Ops, + SCEV::NoWrapFlags Flags); + private: FoldingSet<SCEV> UniqueSCEVs; FoldingSet<SCEVPredicate> UniquePreds; diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h index fdcd8be00dde..2c693bceb24d 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h @@ -595,58 +595,82 @@ namespace llvm { const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) { const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand()); - return SE.getTruncateExpr(Operand, Expr->getType()); + return Operand == Expr->getOperand() + ? Expr + : SE.getTruncateExpr(Operand, Expr->getType()); } const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) { const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand()); - return SE.getZeroExtendExpr(Operand, Expr->getType()); + return Operand == Expr->getOperand() + ? Expr + : SE.getZeroExtendExpr(Operand, Expr->getType()); } const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) { const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand()); - return SE.getSignExtendExpr(Operand, Expr->getType()); + return Operand == Expr->getOperand() + ? Expr + : SE.getSignExtendExpr(Operand, Expr->getType()); } const SCEV *visitAddExpr(const SCEVAddExpr *Expr) { SmallVector<const SCEV *, 2> Operands; - for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) - Operands.push_back(((SC*)this)->visit(Expr->getOperand(i))); - return SE.getAddExpr(Operands); + bool Changed = false; + for (auto *Op : Expr->operands()) { + Operands.push_back(((SC*)this)->visit(Op)); + Changed |= Op != Operands.back(); + } + return !Changed ? Expr : SE.getAddExpr(Operands); } const SCEV *visitMulExpr(const SCEVMulExpr *Expr) { SmallVector<const SCEV *, 2> Operands; - for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) - Operands.push_back(((SC*)this)->visit(Expr->getOperand(i))); - return SE.getMulExpr(Operands); + bool Changed = false; + for (auto *Op : Expr->operands()) { + Operands.push_back(((SC*)this)->visit(Op)); + Changed |= Op != Operands.back(); + } + return !Changed ? Expr : SE.getMulExpr(Operands); } const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) { - return SE.getUDivExpr(((SC*)this)->visit(Expr->getLHS()), - ((SC*)this)->visit(Expr->getRHS())); + auto *LHS = ((SC *)this)->visit(Expr->getLHS()); + auto *RHS = ((SC *)this)->visit(Expr->getRHS()); + bool Changed = LHS != Expr->getLHS() || RHS != Expr->getRHS(); + return !Changed ? Expr : SE.getUDivExpr(LHS, RHS); } const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) { SmallVector<const SCEV *, 2> Operands; - for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) - Operands.push_back(((SC*)this)->visit(Expr->getOperand(i))); - return SE.getAddRecExpr(Operands, Expr->getLoop(), - Expr->getNoWrapFlags()); + bool Changed = false; + for (auto *Op : Expr->operands()) { + Operands.push_back(((SC*)this)->visit(Op)); + Changed |= Op != Operands.back(); + } + return !Changed ? Expr + : SE.getAddRecExpr(Operands, Expr->getLoop(), + Expr->getNoWrapFlags()); } const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) { SmallVector<const SCEV *, 2> Operands; - for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) - Operands.push_back(((SC*)this)->visit(Expr->getOperand(i))); - return SE.getSMaxExpr(Operands); + bool Changed = false; + for (auto *Op : Expr->operands()) { + Operands.push_back(((SC *)this)->visit(Op)); + Changed |= Op != Operands.back(); + } + return !Changed ? Expr : SE.getSMaxExpr(Operands); } const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) { SmallVector<const SCEV *, 2> Operands; - for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) - Operands.push_back(((SC*)this)->visit(Expr->getOperand(i))); - return SE.getUMaxExpr(Operands); + bool Changed = false; + for (auto *Op : Expr->operands()) { + Operands.push_back(((SC*)this)->visit(Op)); + Changed |= Op != Operands.back(); + } + return !Changed ? Expr : SE.getUMaxExpr(Operands); } const SCEV *visitUnknown(const SCEVUnknown *Expr) { diff --git a/include/llvm/Analysis/ScalarEvolutionNormalization.h b/include/llvm/Analysis/ScalarEvolutionNormalization.h index 7c6423a21cfa..b73ad95278a0 100644 --- a/include/llvm/Analysis/ScalarEvolutionNormalization.h +++ b/include/llvm/Analysis/ScalarEvolutionNormalization.h @@ -37,42 +37,33 @@ #define LLVM_ANALYSIS_SCALAREVOLUTIONNORMALIZATION_H #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ScalarEvolutionExpressions.h" namespace llvm { -class Instruction; -class DominatorTree; class Loop; class ScalarEvolution; class SCEV; -class Value; -/// TransformKind - Different types of transformations that -/// TransformForPostIncUse can do. -enum TransformKind { - /// Normalize - Normalize according to the given loops. - Normalize, - /// NormalizeAutodetect - Detect post-inc opportunities on new expressions, - /// update the given loop set, and normalize. - NormalizeAutodetect, - /// Denormalize - Perform the inverse transform on the expression with the - /// given loop set. - Denormalize -}; - -/// PostIncLoopSet - A set of loops. typedef SmallPtrSet<const Loop *, 2> PostIncLoopSet; -/// TransformForPostIncUse - Transform the given expression according to the -/// given transformation kind. -const SCEV *TransformForPostIncUse(TransformKind Kind, - const SCEV *S, - Instruction *User, - Value *OperandValToReplace, - PostIncLoopSet &Loops, - ScalarEvolution &SE, - DominatorTree &DT); +typedef function_ref<bool(const SCEVAddRecExpr *)> NormalizePredTy; + +/// Normalize \p S to be post-increment for all loops present in \p +/// Loops. +const SCEV *normalizeForPostIncUse(const SCEV *S, const PostIncLoopSet &Loops, + ScalarEvolution &SE); + +/// Normalize \p S for all add recurrence sub-expressions for which \p +/// Pred returns true. +const SCEV *normalizeForPostIncUseIf(const SCEV *S, NormalizePredTy Pred, + ScalarEvolution &SE); -} +/// Denormalize \p S to be post-increment for all loops present in \p +/// Loops. +const SCEV *denormalizeForPostIncUse(const SCEV *S, const PostIncLoopSet &Loops, + ScalarEvolution &SE); +} // namespace llvm #endif diff --git a/include/llvm/Analysis/TargetLibraryInfo.def b/include/llvm/Analysis/TargetLibraryInfo.def index 5d5e5b127e63..637fc7ed30dd 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.def +++ b/include/llvm/Analysis/TargetLibraryInfo.def @@ -20,7 +20,7 @@ // One of TLI_DEFINE_ENUM/STRING are defined. #if defined(TLI_DEFINE_ENUM) -#define TLI_DEFINE_ENUM_INTERNAL(enum_variant) enum_variant, +#define TLI_DEFINE_ENUM_INTERNAL(enum_variant) LibFunc_##enum_variant, #define TLI_DEFINE_STRING_INTERNAL(string_repr) #else #define TLI_DEFINE_ENUM_INTERNAL(enum_variant) diff --git a/include/llvm/Analysis/TargetLibraryInfo.h b/include/llvm/Analysis/TargetLibraryInfo.h index 8675882431d5..944250cfd6ac 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.h +++ b/include/llvm/Analysis/TargetLibraryInfo.h @@ -30,14 +30,12 @@ struct VecDesc { unsigned VectorizationFactor; }; - namespace LibFunc { - enum Func { + enum LibFunc { #define TLI_DEFINE_ENUM #include "llvm/Analysis/TargetLibraryInfo.def" - NumLibFuncs - }; - } + NumLibFuncs + }; /// Implementation of the target library information. /// @@ -48,9 +46,9 @@ struct VecDesc { class TargetLibraryInfoImpl { friend class TargetLibraryInfo; - unsigned char AvailableArray[(LibFunc::NumLibFuncs+3)/4]; + unsigned char AvailableArray[(NumLibFuncs+3)/4]; llvm::DenseMap<unsigned, std::string> CustomNames; - static StringRef const StandardNames[LibFunc::NumLibFuncs]; + static StringRef const StandardNames[NumLibFuncs]; bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param; enum AvailabilityState { @@ -58,11 +56,11 @@ class TargetLibraryInfoImpl { CustomName = 1, Unavailable = 0 // (memset to all zeros) }; - void setState(LibFunc::Func F, AvailabilityState State) { + void setState(LibFunc F, AvailabilityState State) { AvailableArray[F/4] &= ~(3 << 2*(F&3)); AvailableArray[F/4] |= State << 2*(F&3); } - AvailabilityState getState(LibFunc::Func F) const { + AvailabilityState getState(LibFunc F) const { return static_cast<AvailabilityState>((AvailableArray[F/4] >> 2*(F&3)) & 3); } @@ -74,7 +72,7 @@ class TargetLibraryInfoImpl { /// 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, + bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, const DataLayout *DL) const; public: @@ -104,28 +102,28 @@ public: /// /// 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; + bool getLibFunc(StringRef funcName, LibFunc &F) const; /// 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; + bool getLibFunc(const Function &FDecl, LibFunc &F) const; /// Forces a function to be marked as unavailable. - void setUnavailable(LibFunc::Func F) { + void setUnavailable(LibFunc F) { setState(F, Unavailable); } /// Forces a function to be marked as available. - void setAvailable(LibFunc::Func F) { + void setAvailable(LibFunc F) { setState(F, StandardName); } /// Forces a function to be marked as available and provide an alternate name /// that must be used. - void setAvailableWithName(LibFunc::Func F, StringRef Name) { + void setAvailableWithName(LibFunc F, StringRef Name) { if (StandardNames[F] != Name) { setState(F, CustomName); CustomNames[F] = Name; @@ -225,16 +223,16 @@ public: /// /// 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 { + bool getLibFunc(StringRef funcName, LibFunc &F) const { return Impl->getLibFunc(funcName, F); } - bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const { + bool getLibFunc(const Function &FDecl, LibFunc &F) const { return Impl->getLibFunc(FDecl, F); } /// Tests whether a library function is available. - bool has(LibFunc::Func F) const { + bool has(LibFunc F) const { return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable; } bool isFunctionVectorizable(StringRef F, unsigned VF) const { @@ -249,37 +247,37 @@ public: /// Tests if the function is both available and a candidate for optimized code /// generation. - bool hasOptimizedCodeGen(LibFunc::Func F) const { + bool hasOptimizedCodeGen(LibFunc F) const { if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable) return false; switch (F) { default: break; - case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl: - case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: - case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl: - case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl: - case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: - case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite: - case LibFunc::sqrtl_finite: - case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: - case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl: - case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: - case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: - case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: - case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: - case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: - case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: - case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l: - case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l: - case LibFunc::memcmp: case LibFunc::strcmp: case LibFunc::strcpy: - case LibFunc::stpcpy: case LibFunc::strlen: case LibFunc::strnlen: - case LibFunc::memchr: case LibFunc::mempcpy: + case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl: + case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl: + case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinl: + case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosl: + case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl: + case LibFunc_sqrt_finite: case LibFunc_sqrtf_finite: + case LibFunc_sqrtl_finite: + case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl: + case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl: + case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: + case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl: + case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill: + case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl: + case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl: + case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl: + case LibFunc_log2: case LibFunc_log2f: case LibFunc_log2l: + case LibFunc_exp2: case LibFunc_exp2f: case LibFunc_exp2l: + case LibFunc_memcmp: case LibFunc_strcmp: case LibFunc_strcpy: + case LibFunc_stpcpy: case LibFunc_strlen: case LibFunc_strnlen: + case LibFunc_memchr: case LibFunc_mempcpy: return true; } return false; } - StringRef getName(LibFunc::Func F) const { + StringRef getName(LibFunc F) const { auto State = Impl->getState(F); if (State == TargetLibraryInfoImpl::Unavailable) return StringRef(); diff --git a/include/llvm/Analysis/TargetTransformInfo.h b/include/llvm/Analysis/TargetTransformInfo.h index 209f05c279d0..67196687d556 100644 --- a/include/llvm/Analysis/TargetTransformInfo.h +++ b/include/llvm/Analysis/TargetTransformInfo.h @@ -44,23 +44,26 @@ class Value; /// \brief Information about a load/store intrinsic defined by the target. struct MemIntrinsicInfo { - MemIntrinsicInfo() - : ReadMem(false), WriteMem(false), IsSimple(false), MatchingId(0), - NumMemRefs(0), PtrVal(nullptr) {} - bool ReadMem; - bool WriteMem; - /// True only if this memory operation is non-volatile, non-atomic, and - /// unordered. (See LoadInst/StoreInst for details on each) - bool IsSimple; - // Same Id is set by the target for corresponding load/store intrinsics. - unsigned short MatchingId; - int NumMemRefs; - /// This is the pointer that the intrinsic is loading from or storing to. /// If this is non-null, then analysis/optimization passes can assume that /// this intrinsic is functionally equivalent to a load/store from this /// pointer. - Value *PtrVal; + Value *PtrVal = nullptr; + + // Ordering for atomic operations. + AtomicOrdering Ordering = AtomicOrdering::NotAtomic; + + // Same Id is set by the target for corresponding load/store intrinsics. + unsigned short MatchingId = 0; + + bool ReadMem = false; + bool WriteMem = false; + bool IsVolatile = false; + + bool isUnordered() const { + return (Ordering == AtomicOrdering::NotAtomic || + Ordering == AtomicOrdering::Unordered) && !IsVolatile; + } }; /// \brief This pass provides access to the codegen interfaces that are needed @@ -226,6 +229,24 @@ public: /// starting with the sources of divergence. bool isSourceOfDivergence(const Value *V) const; + /// Returns the address space ID for a target's 'flat' address space. Note + /// this is not necessarily the same as addrspace(0), which LLVM sometimes + /// refers to as the generic address space. The flat address space is a + /// generic address space that can be used access multiple segments of memory + /// with different address spaces. Access of a memory location through a + /// pointer with this address space is expected to be legal but slower + /// compared to the same memory location accessed through a pointer with a + /// different address space. + // + /// This is for for targets with different pointer representations which can + /// be converted with the addrspacecast instruction. If a pointer is converted + /// to this address space, optimizations should attempt to replace the access + /// with the source address space. + /// + /// \returns ~0u if the target does not have such a flat address space to + /// optimize away. + unsigned getFlatAddressSpace() const; + /// \brief Test whether calls to a function lower to actual program function /// calls. /// @@ -411,6 +432,16 @@ public: /// containing this constant value for the target. bool shouldBuildLookupTablesForConstant(Constant *C) const; + unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) const; + + unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args, + unsigned VF) const; + + /// If target has efficient vector element load/store instructions, it can + /// return true here so that insertion/extraction costs are not added to + /// the scalarization cost of a load/store. + bool supportsEfficientVectorElementLoadStore() const; + /// \brief Don't restrict interleaved unrolling to small loops. bool enableAggressiveInterleaving(bool LoopHasReductions) const; @@ -500,6 +531,12 @@ public: /// \return The width of the largest scalar or vector register type. unsigned getRegisterBitWidth(bool Vector) const; + /// \return True if it should be considered for address type promotion. + /// \p AllowPromotionWithoutCommonHeader Set true if promoting \p I is + /// profitable without finding other extensions fed by the same input. + bool shouldConsiderAddressTypePromotion( + const Instruction &I, bool &AllowPromotionWithoutCommonHeader) const; + /// \return The size of a cache line in bytes. unsigned getCacheLineSize() const; @@ -540,8 +577,10 @@ public: Type *SubTp = nullptr) const; /// \return The expected cost of cast instructions, such as bitcast, trunc, - /// zext, etc. - int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) const; + /// zext, etc. If there is an existing instruction that holds Opcode, it + /// may be passed in the 'I' parameter. + int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, + const Instruction *I = nullptr) 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. @@ -552,9 +591,11 @@ public: /// Phi, Ret, Br. int getCFInstrCost(unsigned Opcode) const; - /// \returns The expected cost of compare and select instructions. + /// \returns The expected cost of compare and select instructions. If there + /// is an existing instruction that holds Opcode, it may be passed in the + /// 'I' parameter. int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, - Type *CondTy = nullptr) const; + Type *CondTy = nullptr, const Instruction *I = nullptr) const; /// \return The expected cost of vector Insert and Extract. /// Use -1 to indicate that there is no information on the index value. @@ -562,7 +603,7 @@ public: /// \return The cost of Load and Store instructions. int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, - unsigned AddressSpace) const; + unsigned AddressSpace, const Instruction *I = nullptr) const; /// \return The cost of masked Load and Store instructions. int getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, @@ -605,13 +646,19 @@ public: /// ((v0+v2), (v1+v3), undef, undef) int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm) const; - /// \returns The cost of Intrinsic instructions. Types analysis only. + /// \returns The cost of Intrinsic instructions. Analyses the real arguments. + /// Three cases are handled: 1. scalar instruction 2. vector instruction + /// 3. scalar instruction which is to be vectorized with VF. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys, FastMathFlags FMF) const; + ArrayRef<Value *> Args, FastMathFlags FMF, + unsigned VF = 1) const; - /// \returns The cost of Intrinsic instructions. Analyses the real arguments. + /// \returns The cost of Intrinsic instructions. Types analysis only. + /// If ScalarizationCostPassed is UINT_MAX, the cost of scalarizing the + /// arguments and the return value will be computed based on types. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args, FastMathFlags FMF) const; + ArrayRef<Type *> Tys, FastMathFlags FMF, + unsigned ScalarizationCostPassed = UINT_MAX) const; /// \returns The cost of Call instructions. int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) const; @@ -720,6 +767,7 @@ public: virtual int getUserCost(const User *U) = 0; virtual bool hasBranchDivergence() = 0; virtual bool isSourceOfDivergence(const Value *V) = 0; + virtual unsigned getFlatAddressSpace() = 0; virtual bool isLoweredToCall(const Function *F) = 0; virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0; virtual bool isLegalAddImmediate(int64_t Imm) = 0; @@ -743,6 +791,11 @@ public: virtual unsigned getJumpBufSize() = 0; virtual bool shouldBuildLookupTables() = 0; virtual bool shouldBuildLookupTablesForConstant(Constant *C) = 0; + virtual unsigned + getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) = 0; + virtual unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args, + unsigned VF) = 0; + virtual bool supportsEfficientVectorElementLoadStore() = 0; virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0; virtual bool enableInterleavedAccessVectorization() = 0; virtual bool isFPVectorizationPotentiallyUnsafe() = 0; @@ -763,6 +816,8 @@ public: Type *Ty) = 0; virtual unsigned getNumberOfRegisters(bool Vector) = 0; virtual unsigned getRegisterBitWidth(bool Vector) = 0; + virtual bool shouldConsiderAddressTypePromotion( + const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0; virtual unsigned getCacheLineSize() = 0; virtual unsigned getPrefetchDistance() = 0; virtual unsigned getMinPrefetchStride() = 0; @@ -776,16 +831,17 @@ public: ArrayRef<const Value *> Args) = 0; virtual int getShuffleCost(ShuffleKind Kind, Type *Tp, int Index, Type *SubTp) = 0; - virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) = 0; + virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, + const Instruction *I) = 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; + Type *CondTy, const Instruction *I) = 0; virtual int getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) = 0; virtual int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, - unsigned AddressSpace) = 0; + unsigned AddressSpace, const Instruction *I) = 0; virtual int getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, unsigned AddressSpace) = 0; @@ -800,11 +856,10 @@ public: virtual int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys, - FastMathFlags FMF) = 0; + ArrayRef<Type *> Tys, FastMathFlags FMF, + unsigned ScalarizationCostPassed) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args, - FastMathFlags FMF) = 0; + ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) = 0; virtual int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) = 0; virtual unsigned getNumberOfParts(Type *Tp) = 0; @@ -879,6 +934,11 @@ public: bool isSourceOfDivergence(const Value *V) override { return Impl.isSourceOfDivergence(V); } + + unsigned getFlatAddressSpace() override { + return Impl.getFlatAddressSpace(); + } + bool isLoweredToCall(const Function *F) override { return Impl.isLoweredToCall(F); } @@ -933,6 +993,19 @@ public: bool shouldBuildLookupTablesForConstant(Constant *C) override { return Impl.shouldBuildLookupTablesForConstant(C); } + unsigned getScalarizationOverhead(Type *Ty, bool Insert, + bool Extract) override { + return Impl.getScalarizationOverhead(Ty, Insert, Extract); + } + unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args, + unsigned VF) override { + return Impl.getOperandsScalarizationOverhead(Args, VF); + } + + bool supportsEfficientVectorElementLoadStore() override { + return Impl.supportsEfficientVectorElementLoadStore(); + } + bool enableAggressiveInterleaving(bool LoopHasReductions) override { return Impl.enableAggressiveInterleaving(LoopHasReductions); } @@ -976,7 +1049,11 @@ public: unsigned getRegisterBitWidth(bool Vector) override { return Impl.getRegisterBitWidth(Vector); } - + bool shouldConsiderAddressTypePromotion( + const Instruction &I, bool &AllowPromotionWithoutCommonHeader) override { + return Impl.shouldConsiderAddressTypePromotion( + I, AllowPromotionWithoutCommonHeader); + } unsigned getCacheLineSize() override { return Impl.getCacheLineSize(); } @@ -1003,8 +1080,9 @@ public: Type *SubTp) override { return Impl.getShuffleCost(Kind, Tp, Index, SubTp); } - int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) override { - return Impl.getCastInstrCost(Opcode, Dst, Src); + int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, + const Instruction *I) override { + return Impl.getCastInstrCost(Opcode, Dst, Src, I); } int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, unsigned Index) override { @@ -1013,15 +1091,16 @@ public: int getCFInstrCost(unsigned Opcode) override { return Impl.getCFInstrCost(Opcode); } - int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) override { - return Impl.getCmpSelInstrCost(Opcode, ValTy, CondTy); + int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, + const Instruction *I) override { + return Impl.getCmpSelInstrCost(Opcode, ValTy, CondTy, I); } int getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) override { return Impl.getVectorInstrCost(Opcode, Val, Index); } int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, - unsigned AddressSpace) override { - return Impl.getMemoryOpCost(Opcode, Src, Alignment, AddressSpace); + unsigned AddressSpace, const Instruction *I) override { + return Impl.getMemoryOpCost(Opcode, Src, Alignment, AddressSpace, I); } int getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, unsigned AddressSpace) override { @@ -1044,13 +1123,13 @@ public: return Impl.getReductionCost(Opcode, Ty, IsPairwiseForm); } int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef<Type *> Tys, - FastMathFlags FMF) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF); + FastMathFlags FMF, unsigned ScalarizationCostPassed) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF, + ScalarizationCostPassed); } int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args, - FastMathFlags FMF) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF); + ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF, VF); } int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) override { diff --git a/include/llvm/Analysis/TargetTransformInfoImpl.h b/include/llvm/Analysis/TargetTransformInfoImpl.h index cafc40723c9d..9ab6b7445ab8 100644 --- a/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -171,6 +171,10 @@ public: bool isSourceOfDivergence(const Value *V) { return false; } + unsigned getFlatAddressSpace () { + return -1; + } + bool isLoweredToCall(const Function *F) { // FIXME: These should almost certainly not be handled here, and instead // handled with the help of TLI or the target itself. This was largely @@ -251,6 +255,15 @@ public: bool shouldBuildLookupTables() { return true; } bool shouldBuildLookupTablesForConstant(Constant *C) { return true; } + unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) { + return 0; + } + + unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args, + unsigned VF) { return 0; } + + bool supportsEfficientVectorElementLoadStore() { return false; } + bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; } bool enableInterleavedAccessVectorization() { return false; } @@ -292,6 +305,13 @@ public: unsigned getRegisterBitWidth(bool Vector) { return 32; } + bool + shouldConsiderAddressTypePromotion(const Instruction &I, + bool &AllowPromotionWithoutCommonHeader) { + AllowPromotionWithoutCommonHeader = false; + return false; + } + unsigned getCacheLineSize() { return 0; } unsigned getPrefetchDistance() { return 0; } @@ -316,7 +336,8 @@ public: return 1; } - unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { return 1; } + unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, + const Instruction *I) { return 1; } unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, unsigned Index) { @@ -325,7 +346,8 @@ public: unsigned getCFInstrCost(unsigned Opcode) { return 1; } - unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) { + unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, + const Instruction *I) { return 1; } @@ -334,7 +356,7 @@ public: } unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, - unsigned AddressSpace) { + unsigned AddressSpace, const Instruction *I) { return 1; } @@ -358,11 +380,12 @@ public: } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Type *> Tys, FastMathFlags FMF) { + ArrayRef<Type *> Tys, FastMathFlags FMF, + unsigned ScalarizationCostPassed) { return 1; } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef<Value *> Args, FastMathFlags FMF) { + ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) { return 1; } diff --git a/include/llvm/Analysis/TypeMetadataUtils.h b/include/llvm/Analysis/TypeMetadataUtils.h index c3f688f5d7f1..17906ba4e392 100644 --- a/include/llvm/Analysis/TypeMetadataUtils.h +++ b/include/llvm/Analysis/TypeMetadataUtils.h @@ -32,14 +32,15 @@ struct DevirtCallSite { /// call sites based on the call and return them in DevirtCalls. void findDevirtualizableCallsForTypeTest( SmallVectorImpl<DevirtCallSite> &DevirtCalls, - SmallVectorImpl<CallInst *> &Assumes, CallInst *CI); + SmallVectorImpl<CallInst *> &Assumes, const 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); + SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses, + const CallInst *CI); } #endif diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h index aaf6f888e06f..e3c2f3bed227 100644 --- a/include/llvm/Analysis/ValueTracking.h +++ b/include/llvm/Analysis/ValueTracking.h @@ -31,6 +31,7 @@ template <typename T> class ArrayRef; class Instruction; class Loop; class LoopInfo; + class OptimizationRemarkEmitter; class MDNode; class StringRef; class TargetLibraryInfo; @@ -52,7 +53,8 @@ template <typename T> class ArrayRef; const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, - const DominatorTree *DT = nullptr); + const DominatorTree *DT = nullptr, + OptimizationRemarkEmitter *ORE = nullptr); /// Compute known bits from the range metadata. /// \p KnownZero the set of bits that are known to be zero /// \p KnownOne the set of bits that are known to be one @@ -86,8 +88,10 @@ template <typename T> class ArrayRef; /// 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. + /// defined. For pointers, if the context instruction and dominator tree are + /// specified, perform context-sensitive analysis and return true if the + /// pointer couldn't possibly be null at the specified instruction. + /// Supports values with integer or pointer type and vectors of integers. bool isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, @@ -167,13 +171,25 @@ template <typename T> class ArrayRef; 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. - /// If \p IncludeNeg0 is false, -0.0 is considered less than 0.0. + /// Return true if we can prove that the specified FP value is either NaN or + /// never less than -0.0. + /// + /// NaN --> true + /// +0 --> true + /// -0 --> true + /// x > +0 --> true + /// x < -0 --> false + /// bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI); - /// \returns true if we can prove that the specified FP value has a 0 sign - /// bit. + /// Return true if we can prove that the specified FP value's sign bit is 0. + /// + /// NaN --> true/false (depending on the NaN's sign bit) + /// +0 --> true + /// -0 --> false + /// x > +0 --> true + /// x < -0 --> false + /// bool SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI); /// If the specified value can be set by repeating the same byte in memory, diff --git a/include/llvm/Analysis/VectorUtils.h b/include/llvm/Analysis/VectorUtils.h index eaa068b89c77..6315e8408f05 100644 --- a/include/llvm/Analysis/VectorUtils.h +++ b/include/llvm/Analysis/VectorUtils.h @@ -1,4 +1,4 @@ -//===- llvm/Transforms/Utils/VectorUtils.h - Vector utilities -*- C++ -*-=====// +//===- llvm/Analysis/VectorUtils.h - Vector utilities -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,11 +11,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TRANSFORMS_UTILS_VECTORUTILS_H -#define LLVM_TRANSFORMS_UTILS_VECTORUTILS_H +#ifndef LLVM_ANALYSIS_VECTORUTILS_H +#define LLVM_ANALYSIS_VECTORUTILS_H #include "llvm/ADT/MapVector.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/IRBuilder.h" namespace llvm { @@ -123,6 +124,58 @@ computeMinimumValueSizes(ArrayRef<BasicBlock*> Blocks, /// This function always sets a (possibly null) value for each K in Kinds. Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL); +/// \brief Create an interleave shuffle mask. +/// +/// This function creates a shuffle mask for interleaving \p NumVecs vectors of +/// vectorization factor \p VF into a single wide vector. The mask is of the +/// form: +/// +/// <0, VF, VF * 2, ..., VF * (NumVecs - 1), 1, VF + 1, VF * 2 + 1, ...> +/// +/// For example, the mask for VF = 4 and NumVecs = 2 is: +/// +/// <0, 4, 1, 5, 2, 6, 3, 7>. +Constant *createInterleaveMask(IRBuilder<> &Builder, unsigned VF, + unsigned NumVecs); + +/// \brief Create a stride shuffle mask. +/// +/// This function creates a shuffle mask whose elements begin at \p Start and +/// are incremented by \p Stride. The mask can be used to deinterleave an +/// interleaved vector into separate vectors of vectorization factor \p VF. The +/// mask is of the form: +/// +/// <Start, Start + Stride, ..., Start + Stride * (VF - 1)> +/// +/// For example, the mask for Start = 0, Stride = 2, and VF = 4 is: +/// +/// <0, 2, 4, 6> +Constant *createStrideMask(IRBuilder<> &Builder, unsigned Start, + unsigned Stride, unsigned VF); + +/// \brief Create a sequential shuffle mask. +/// +/// This function creates shuffle mask whose elements are sequential and begin +/// at \p Start. The mask contains \p NumInts integers and is padded with \p +/// NumUndefs undef values. The mask is of the form: +/// +/// <Start, Start + 1, ... Start + NumInts - 1, undef_1, ... undef_NumUndefs> +/// +/// For example, the mask for Start = 0, NumInsts = 4, and NumUndefs = 4 is: +/// +/// <0, 1, 2, 3, undef, undef, undef, undef> +Constant *createSequentialMask(IRBuilder<> &Builder, unsigned Start, + unsigned NumInts, unsigned NumUndefs); + +/// \brief Concatenate a list of vectors. +/// +/// This function generates code that concatenate the vectors in \p Vecs into a +/// single large vector. The number of vectors should be greater than one, and +/// their element types should be the same. The number of elements in the +/// vectors should also be the same; however, if the last vector has fewer +/// elements, it will be padded with undefs. +Value *concatenateVectors(IRBuilder<> &Builder, ArrayRef<Value *> Vecs); + } // llvm namespace #endif diff --git a/include/llvm/Bitcode/BitcodeWriter.h b/include/llvm/Bitcode/BitcodeWriter.h index 4f72f98bbf9c..271cb2d81bbb 100644 --- a/include/llvm/Bitcode/BitcodeWriter.h +++ b/include/llvm/Bitcode/BitcodeWriter.h @@ -43,9 +43,16 @@ namespace llvm { /// /// \p GenerateHash enables hashing the Module and including the hash in the /// bitcode (currently for use in ThinLTO incremental build). + /// + /// If \p ModHash is non-null, when GenerateHash is true, the resulting + /// hash is written into ModHash. When GenerateHash is false, that value + /// is used as the hash instead of computing from the generated bitcode. + /// Can be used to produce the same module hash for a minimized bitcode + /// used just for the thin link as in the regular full bitcode that will + /// be used in the backend. void writeModule(const Module *M, bool ShouldPreserveUseListOrder = false, const ModuleSummaryIndex *Index = nullptr, - bool GenerateHash = false); + bool GenerateHash = false, ModuleHash *ModHash = nullptr); }; /// \brief Write the specified module to the specified raw output stream. @@ -62,10 +69,18 @@ namespace llvm { /// /// \p GenerateHash enables hashing the Module and including the hash in the /// bitcode (currently for use in ThinLTO incremental build). + /// + /// If \p ModHash is non-null, when GenerateHash is true, the resulting + /// hash is written into ModHash. When GenerateHash is false, that value + /// is used as the hash instead of computing from the generated bitcode. + /// Can be used to produce the same module hash for a minimized bitcode + /// used just for the thin link as in the regular full bitcode that will + /// be used in the backend. void WriteBitcodeToFile(const Module *M, raw_ostream &Out, bool ShouldPreserveUseListOrder = false, const ModuleSummaryIndex *Index = nullptr, - bool GenerateHash = false); + bool GenerateHash = false, + ModuleHash *ModHash = nullptr); /// 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 diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index c996c38261c0..e2d2fbb0f449 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -92,9 +92,6 @@ enum ModuleCodes { // 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] @@ -213,8 +210,28 @@ enum GlobalValueSummarySymtabCodes { FS_COMBINED_ORIGINAL_NAME = 9, // VERSION of the summary, bumped when adding flags for instance. FS_VERSION = 10, - // The list of llvm.type.test type identifiers used by the following function. + // The list of llvm.type.test type identifiers used by the following function + // that are used other than by an llvm.assume. + // [n x typeid] FS_TYPE_TESTS = 11, + // The list of virtual calls made by this function using + // llvm.assume(llvm.type.test) intrinsics that do not have all constant + // integer arguments. + // [n x (typeid, offset)] + FS_TYPE_TEST_ASSUME_VCALLS = 12, + // The list of virtual calls made by this function using + // llvm.type.checked.load intrinsics that do not have all constant integer + // arguments. + // [n x (typeid, offset)] + FS_TYPE_CHECKED_LOAD_VCALLS = 13, + // Identifies a virtual call made by this function using an + // llvm.assume(llvm.type.test) intrinsic with all constant integer arguments. + // [typeid, offset, n x arg] + FS_TYPE_TEST_ASSUME_CONST_VCALL = 14, + // Identifies a virtual call made by this function using an + // llvm.type.checked.load intrinsic with all constant integer arguments. + // [typeid, offset, n x arg] + FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15, }; enum MetadataCodes { diff --git a/include/llvm/CMakeLists.txt b/include/llvm/CMakeLists.txt index ff805396eb0c..1d5ca3ba92b0 100644 --- a/include/llvm/CMakeLists.txt +++ b/include/llvm/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(IR) +add_subdirectory(Support) # If we're doing an out-of-tree build, copy a module map for generated # header files into the build area. diff --git a/include/llvm/CodeGen/Analysis.h b/include/llvm/CodeGen/Analysis.h index f20185c4499a..ba88f1f78fb8 100644 --- a/include/llvm/CodeGen/Analysis.h +++ b/include/llvm/CodeGen/Analysis.h @@ -123,13 +123,6 @@ bool returnTypeIsEligibleForTailCall(const Function *F, const Instruction *I, const ReturnInst *Ret, const TargetLoweringBase &TLI); -// True if GV can be left out of the object symbol table. This is the case -// for linkonce_odr values whose address is not significant. While legal, it is -// not normally profitable to omit them from the .o symbol table. Using this -// analysis makes sense when the information can be passed down to the linker -// or we are in LTO. -bool canBeOmittedFromSymbolTable(const GlobalValue *GV); - DenseMap<const MachineBasicBlock *, int> getFuncletMembership(const MachineFunction &MF); diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index 4daca0347b77..fb8c8408fc77 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework --------*- C++ -*-===// +//===- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,35 +17,43 @@ #define LLVM_CODEGEN_ASMPRINTER_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" +#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SourceMgr.h" +#include <cstdint> +#include <memory> +#include <utility> +#include <vector> namespace llvm { + class AsmPrinterHandler; class BlockAddress; -class ByteStreamer; -class GCStrategy; class Constant; class ConstantArray; +class DataLayout; class DIE; class DIEAbbrev; +class DwarfDebug; class GCMetadataPrinter; class GlobalIndirectSymbol; class GlobalValue; class GlobalVariable; +class GCStrategy; class MachineBasicBlock; +class MachineConstantPoolValue; class MachineFunction; class MachineInstr; -class MachineLocation; -class MachineLoopInfo; -class MachineLoop; -class MachineConstantPoolValue; class MachineJumpTableInfo; +class MachineLoopInfo; class MachineModuleInfo; +class MachineOptimizationRemarkEmitter; class MCAsmInfo; class MCCFIInstruction; class MCContext; @@ -57,10 +65,7 @@ class MCSubtargetInfo; class MCSymbol; class MCTargetOptions; class MDNode; -class DwarfDebug; -class Mangler; class TargetLoweringObjectFile; -class DataLayout; class TargetMachine; /// This class is intended to be used as a driving class for all asm writers. @@ -84,33 +89,39 @@ public: std::unique_ptr<MCStreamer> OutStreamer; /// The current machine function. - const MachineFunction *MF; + const MachineFunction *MF = nullptr; /// This is a pointer to the current MachineModuleInfo. - MachineModuleInfo *MMI; + MachineModuleInfo *MMI = nullptr; + + /// Optimization remark emitter. + MachineOptimizationRemarkEmitter *ORE; /// The symbol for the current function. This is recalculated at the beginning /// of each call to runOnMachineFunction(). /// - MCSymbol *CurrentFnSym; + MCSymbol *CurrentFnSym = nullptr; /// The symbol used to represent the start of the current function for the /// purpose of calculating its size (e.g. using the .size directive). By /// default, this is equal to CurrentFnSym. - MCSymbol *CurrentFnSymForSize; + MCSymbol *CurrentFnSymForSize = nullptr; /// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of /// its number of uses by other globals. typedef std::pair<const GlobalVariable *, unsigned> GOTEquivUsePair; MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs; + /// Enable print [latency:throughput] in output + bool EnablePrintSchedInfo = false; + private: - MCSymbol *CurrentFnBegin; - MCSymbol *CurrentFnEnd; - MCSymbol *CurExceptionSym; + MCSymbol *CurrentFnBegin = nullptr; + MCSymbol *CurrentFnEnd = nullptr; + MCSymbol *CurExceptionSym = nullptr; // The garbage collection metadata printer table. - void *GCMetadataPrinters; // Really a DenseMap. + void *GCMetadataPrinters = nullptr; // Really a DenseMap. /// Emit comments in assembly output if this is true. /// @@ -118,7 +129,7 @@ private: static char ID; /// If VerboseAsm is set, a pointer to the loop info for this function. - MachineLoopInfo *LI; + MachineLoopInfo *LI = nullptr; struct HandlerInfo { AsmPrinterHandler *Handler; @@ -126,6 +137,7 @@ private: const char *TimerDescription; const char *TimerGroupName; const char *TimerGroupDescription; + HandlerInfo(AsmPrinterHandler *Handler, const char *TimerName, const char *TimerDescription, const char *TimerGroupName, const char *TimerGroupDescription) @@ -137,11 +149,24 @@ private: /// maintains ownership of the emitters. SmallVector<HandlerInfo, 1> Handlers; +public: + struct SrcMgrDiagInfo { + SourceMgr SrcMgr; + std::vector<const MDNode *> LocInfos; + LLVMContext::InlineAsmDiagHandlerTy DiagHandler; + void *DiagContext; + }; + +private: + /// Structure for generating diagnostics for inline assembly. Only initialised + /// when necessary. + mutable std::unique_ptr<SrcMgrDiagInfo> DiagInfo; + /// If the target supports dwarf debug info, this pointer is non-null. - DwarfDebug *DD; + DwarfDebug *DD = nullptr; /// If the current module uses dwarf CFI annotations strictly for debugging. - bool isCFIMoveForDebugging; + bool isCFIMoveForDebugging = false; protected: explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer); @@ -200,6 +225,7 @@ public: FUNCTION_ENTER = 0, FUNCTION_EXIT = 1, TAIL_CALL = 2, + LOG_ARGS_ENTER = 3, }; // The table will contain these structs that point to the sled, the function @@ -381,7 +407,7 @@ public: //===------------------------------------------------------------------===// // Symbol Lowering Routines. //===------------------------------------------------------------------===// -public: + MCSymbol *createTempSymbol(const Twine &Name) const; /// Return the MCSymbol for a private symbol with global value name as its @@ -407,7 +433,7 @@ public: //===------------------------------------------------------------------===// // Emission Helper Routines. //===------------------------------------------------------------------===// -public: + /// This is just convenient handler for printing offsets. void printOffset(int64_t Offset, raw_ostream &OS) const; @@ -484,7 +510,7 @@ public: /// /// \p Value - The value to emit. /// \p Size - The size of the integer (in bytes) to emit. - virtual void EmitDebugValue(const MCExpr *Value, unsigned Size) const; + virtual void EmitDebugThreadLocal(const MCExpr *Value, unsigned Size) const; //===------------------------------------------------------------------===// // Dwarf Lowering Routines @@ -511,7 +537,7 @@ public: //===------------------------------------------------------------------===// // Inline Asm Support //===------------------------------------------------------------------===// -public: + // These are hooks that targets can override to implement inline asm // support. These should probably be moved out of AsmPrinter someday. @@ -555,9 +581,9 @@ public: private: /// Private state for PrintSpecial() // Assign a unique ID to this machine instruction. - mutable const MachineInstr *LastMI; - mutable unsigned LastFn; - mutable unsigned Counter; + mutable const MachineInstr *LastMI = nullptr; + mutable unsigned LastFn = 0; + mutable unsigned Counter = ~0U; /// This method emits the header for the current function. virtual void EmitFunctionHeader(); @@ -596,6 +622,7 @@ private: void emitGlobalIndirectSymbol(Module &M, const GlobalIndirectSymbol& GIS); }; -} -#endif +} // end namespace llvm + +#endif // LLVM_CODEGEN_ASMPRINTER_H diff --git a/include/llvm/CodeGen/BasicTTIImpl.h b/include/llvm/CodeGen/BasicTTIImpl.h index 7efdbcccdef5..e30e947f787f 100644 --- a/include/llvm/CodeGen/BasicTTIImpl.h +++ b/include/llvm/CodeGen/BasicTTIImpl.h @@ -42,24 +42,6 @@ private: typedef TargetTransformInfoImplCRTPBase<T> BaseT; typedef TargetTransformInfo TTI; - /// Estimate the overhead of scalarizing an instruction. Insert and Extract - /// are set if the result needs to be inserted and/or extracted from vectors. - unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) { - assert(Ty->isVectorTy() && "Can only scalarize vectors"); - unsigned Cost = 0; - - for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) { - if (Insert) - Cost += static_cast<T *>(this) - ->getVectorInstrCost(Instruction::InsertElement, Ty, i); - if (Extract) - Cost += static_cast<T *>(this) - ->getVectorInstrCost(Instruction::ExtractElement, Ty, i); - } - - return Cost; - } - /// Estimate a cost of shuffle as a sequence of extract and insert /// operations. unsigned getPermuteShuffleOverhead(Type *Ty) { @@ -111,6 +93,11 @@ public: bool isSourceOfDivergence(const Value *V) { return false; } + unsigned getFlatAddressSpace() { + // Return an invalid address space. + return -1; + } + bool isLegalAddImmediate(int64_t imm) { return getTLI()->isLegalAddImmediate(imm); } @@ -301,6 +288,67 @@ public: unsigned getRegisterBitWidth(bool Vector) { return 32; } + /// Estimate the overhead of scalarizing an instruction. Insert and Extract + /// are set if the result needs to be inserted and/or extracted from vectors. + unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) { + assert(Ty->isVectorTy() && "Can only scalarize vectors"); + unsigned Cost = 0; + + for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) { + if (Insert) + Cost += static_cast<T *>(this) + ->getVectorInstrCost(Instruction::InsertElement, Ty, i); + if (Extract) + Cost += static_cast<T *>(this) + ->getVectorInstrCost(Instruction::ExtractElement, Ty, i); + } + + return Cost; + } + + /// Estimate the overhead of scalarizing an instructions unique + /// non-constant operands. The types of the arguments are ordinarily + /// scalar, in which case the costs are multiplied with VF. + unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args, + unsigned VF) { + unsigned Cost = 0; + SmallPtrSet<const Value*, 4> UniqueOperands; + for (const Value *A : Args) { + if (!isa<Constant>(A) && UniqueOperands.insert(A).second) { + Type *VecTy = nullptr; + if (A->getType()->isVectorTy()) { + VecTy = A->getType(); + // If A is a vector operand, VF should be 1 or correspond to A. + assert ((VF == 1 || VF == VecTy->getVectorNumElements()) && + "Vector argument does not match VF"); + } + else + VecTy = VectorType::get(A->getType(), VF); + + Cost += getScalarizationOverhead(VecTy, false, true); + } + } + + return Cost; + } + + unsigned getScalarizationOverhead(Type *VecTy, ArrayRef<const Value *> Args) { + assert (VecTy->isVectorTy()); + + unsigned Cost = 0; + + Cost += getScalarizationOverhead(VecTy, true, false); + if (!Args.empty()) + Cost += getOperandsScalarizationOverhead(Args, + VecTy->getVectorNumElements()); + else + // When no information on arguments is provided, we add the cost + // associated with one argument as a heuristic. + Cost += getScalarizationOverhead(VecTy, false, true); + + return Cost; + } + unsigned getMaxInterleaveFactor(unsigned VF) { return 1; } unsigned getArithmeticInstrCost( @@ -341,10 +389,9 @@ public: unsigned Num = Ty->getVectorNumElements(); unsigned Cost = static_cast<T *>(this) ->getArithmeticInstrCost(Opcode, Ty->getScalarType()); - // return the cost of multiple scalar invocation plus the cost of - // inserting - // and extracting the values. - return getScalarizationOverhead(Ty, true, true) + Num * Cost; + // Return the cost of multiple scalar invocation plus the cost of + // inserting and extracting the values. + return getScalarizationOverhead(Ty, Args) + Num * Cost; } // We don't know anything about this scalar instruction. @@ -360,7 +407,8 @@ public: return 1; } - unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { + unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, + const Instruction *I = nullptr) { const TargetLoweringBase *TLI = getTLI(); int ISD = TLI->InstructionOpcodeToISD(Opcode); assert(ISD && "Invalid opcode"); @@ -389,6 +437,18 @@ public: Dst->getPointerAddressSpace())) return 0; + // If this is a zext/sext of a load, return 0 if the corresponding + // extending load exists on target. + if ((Opcode == Instruction::ZExt || Opcode == Instruction::SExt) && + I && isa<LoadInst>(I->getOperand(0))) { + EVT ExtVT = EVT::getEVT(Dst); + EVT LoadVT = EVT::getEVT(Src); + unsigned LType = + ((Opcode == Instruction::ZExt) ? ISD::ZEXTLOAD : ISD::SEXTLOAD); + if (TLI->isLoadExtLegal(LType, ExtVT, LoadVT)) + 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)) @@ -446,14 +506,14 @@ public: Src->getVectorNumElements() / 2); T *TTI = static_cast<T *>(this); return TTI->getVectorSplitCost() + - (2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc)); + (2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc, I)); } // 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()); + Opcode, Dst->getScalarType(), Src->getScalarType(), I); // Return the cost of multiple scalar invocation plus the cost of // inserting and extracting the values. @@ -487,7 +547,8 @@ public: return 0; } - unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) { + unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, + const Instruction *I) { const TargetLoweringBase *TLI = getTLI(); int ISD = TLI->InstructionOpcodeToISD(Opcode); assert(ISD && "Invalid opcode"); @@ -515,7 +576,7 @@ public: if (CondTy) CondTy = CondTy->getScalarType(); unsigned Cost = static_cast<T *>(this)->getCmpSelInstrCost( - Opcode, ValTy->getScalarType(), CondTy); + Opcode, ValTy->getScalarType(), CondTy, I); // Return the cost of multiple scalar invocation plus the cost of // inserting and extracting the values. @@ -534,7 +595,7 @@ public: } unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, - unsigned AddressSpace) { + unsigned AddressSpace, const Instruction *I = nullptr) { assert(!Src->isVoidTy() && "Invalid type"); std::pair<unsigned, MVT> LT = getTLI()->getTypeLegalizationCost(DL, Src); @@ -680,18 +741,42 @@ public: return Cost; } - /// Get intrinsic cost based on arguments + /// Get intrinsic cost based on arguments. unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef<Value *> Args, FastMathFlags FMF) { + ArrayRef<Value *> Args, FastMathFlags FMF, + unsigned VF = 1) { + unsigned RetVF = (RetTy->isVectorTy() ? RetTy->getVectorNumElements() : 1); + assert ((RetVF == 1 || VF == 1) && "VF > 1 and RetVF is a vector type"); + switch (IID) { default: { + // Assume that we need to scalarize this intrinsic. SmallVector<Type *, 4> Types; - for (Value *Op : Args) - Types.push_back(Op->getType()); - return static_cast<T *>(this)->getIntrinsicInstrCost(IID, RetTy, Types, - FMF); + for (Value *Op : Args) { + Type *OpTy = Op->getType(); + assert (VF == 1 || !OpTy->isVectorTy()); + Types.push_back(VF == 1 ? OpTy : VectorType::get(OpTy, VF)); + } + + if (VF > 1 && !RetTy->isVoidTy()) + RetTy = VectorType::get(RetTy, VF); + + // Compute the scalarization overhead based on Args for a vector + // intrinsic. A vectorizer will pass a scalar RetTy and VF > 1, while + // CostModel will pass a vector RetTy and VF is 1. + unsigned ScalarizationCost = UINT_MAX; + if (RetVF > 1 || VF > 1) { + ScalarizationCost = 0; + if (!RetTy->isVoidTy()) + ScalarizationCost += getScalarizationOverhead(RetTy, true, false); + ScalarizationCost += getOperandsScalarizationOverhead(Args, VF); + } + + return static_cast<T *>(this)-> + getIntrinsicInstrCost(IID, RetTy, Types, FMF, ScalarizationCost); } case Intrinsic::masked_scatter: { + assert (VF == 1 && "Can't vectorize types here."); Value *Mask = Args[3]; bool VarMask = !isa<Constant>(Mask); unsigned Alignment = cast<ConstantInt>(Args[2])->getZExtValue(); @@ -702,6 +787,7 @@ public: Alignment); } case Intrinsic::masked_gather: { + assert (VF == 1 && "Can't vectorize types here."); Value *Mask = Args[2]; bool VarMask = !isa<Constant>(Mask); unsigned Alignment = cast<ConstantInt>(Args[1])->getZExtValue(); @@ -713,19 +799,23 @@ public: } } - /// Get intrinsic cost based on argument types + /// Get intrinsic cost based on argument types. + /// If ScalarizationCostPassed is UINT_MAX, the cost of scalarizing the + /// arguments and the return value will be computed based on types. unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef<Type *> Tys, FastMathFlags FMF) { + ArrayRef<Type *> Tys, FastMathFlags FMF, + unsigned ScalarizationCostPassed = UINT_MAX) { SmallVector<unsigned, 2> ISDs; unsigned SingleCallCost = 10; // Library call cost. Make it expensive. switch (IID) { default: { // Assume that we need to scalarize this intrinsic. - unsigned ScalarizationCost = 0; + unsigned ScalarizationCost = ScalarizationCostPassed; unsigned ScalarCalls = 1; Type *ScalarRetTy = RetTy; if (RetTy->isVectorTy()) { - ScalarizationCost = getScalarizationOverhead(RetTy, true, false); + if (ScalarizationCostPassed == UINT_MAX) + ScalarizationCost = getScalarizationOverhead(RetTy, true, false); ScalarCalls = std::max(ScalarCalls, RetTy->getVectorNumElements()); ScalarRetTy = RetTy->getScalarType(); } @@ -733,7 +823,8 @@ public: for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) { Type *Ty = Tys[i]; if (Ty->isVectorTy()) { - ScalarizationCost += getScalarizationOverhead(Ty, false, true); + if (ScalarizationCostPassed == UINT_MAX) + ScalarizationCost += getScalarizationOverhead(Ty, false, true); ScalarCalls = std::max(ScalarCalls, Ty->getVectorNumElements()); Ty = Ty->getScalarType(); } @@ -881,7 +972,8 @@ public: // this will emit a costly libcall, adding call overhead and spills. Make it // very expensive. if (RetTy->isVectorTy()) { - unsigned ScalarizationCost = getScalarizationOverhead(RetTy, true, false); + unsigned ScalarizationCost = ((ScalarizationCostPassed != UINT_MAX) ? + ScalarizationCostPassed : getScalarizationOverhead(RetTy, true, false)); unsigned ScalarCalls = RetTy->getVectorNumElements(); SmallVector<Type *, 4> ScalarTys; for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) { @@ -894,7 +986,8 @@ public: 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); + if (ScalarizationCostPassed == UINT_MAX) + ScalarizationCost += getScalarizationOverhead(Tys[i], false, true); ScalarCalls = std::max(ScalarCalls, Tys[i]->getVectorNumElements()); } } diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index bfbd22823eb8..50e464ebb9b8 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -183,11 +183,6 @@ typedef bool CCCustomFn(unsigned &ValNo, MVT &ValVT, MVT &LocVT, CCValAssign::LocInfo &LocInfo, ISD::ArgFlagsTy &ArgFlags, CCState &State); -/// ParmContext - This enum tracks whether calling convention lowering is in -/// the context of prologue or call generation. Not all backends make use of -/// this information. -typedef enum { Unknown, Prologue, Call } ParmContext; - /// CCState - This class holds information needed while lowering arguments and /// return values. It captures which registers are already assigned and which /// stack slots are used. It provides accessors to allocate these values. @@ -256,9 +251,6 @@ private: // during argument analysis. unsigned InRegsParamsProcessed; -protected: - ParmContext CallOrPrologue; - public: CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, SmallVectorImpl<CCValAssign> &locs, LLVMContext &C); @@ -510,8 +502,6 @@ public: InRegsParamsProcessed = 0; } - ParmContext getCallOrPrologue() const { return CallOrPrologue; } - // Get list of pending assignments SmallVectorImpl<llvm::CCValAssign> &getPendingLocs() { return PendingLocs; diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h index aab522d00de7..317a5d3f54c8 100644 --- a/include/llvm/CodeGen/CommandFlags.h +++ b/include/llvm/CodeGen/CommandFlags.h @@ -119,11 +119,6 @@ FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), "Emit nothing, for performance testing"))); cl::opt<bool> -EnableFPMAD("enable-fp-mad", - cl::desc("Enable less precise MAD instructions to be generated"), - cl::init(false)); - -cl::opt<bool> DisableFPElim("disable-fp-elim", cl::desc("Disable frame pointer elimination optimization"), cl::init(false)); @@ -144,6 +139,12 @@ EnableNoNaNsFPMath("enable-no-nans-fp-math", cl::init(false)); cl::opt<bool> +EnableNoSignedZerosFPMath("enable-no-signed-zeros-fp-math", + cl::desc("Enable FP math optimizations that assume " + "the sign of 0 is insignificant"), + cl::init(false)); + +cl::opt<bool> EnableNoTrappingFPMath("enable-no-trapping-fp-math", cl::desc("Enable setting the FP exceptions build " "attribute not to use exceptions"), @@ -277,11 +278,11 @@ DebuggerTuningOpt("debugger-tune", // a TargetOptions object with CodeGen flags and returns it. static inline TargetOptions InitTargetOptionsFromCodeGenFlags() { TargetOptions Options; - Options.LessPreciseFPMADOption = EnableFPMAD; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.NoSignedZerosFPMath = EnableNoSignedZerosFPMath; Options.NoTrappingFPMath = EnableNoTrappingFPMath; Options.FPDenormalMode = DenormalMode; Options.HonorSignDependentRoundingFPMathOption = @@ -345,28 +346,28 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features, Module &M) { for (auto &F : M) { auto &Ctx = F.getContext(); - AttributeSet Attrs = F.getAttributes(), NewAttrs; + AttributeList Attrs = F.getAttributes(), NewAttrs; if (!CPU.empty()) - NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, "target-cpu", CPU); if (!Features.empty()) - NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, "target-features", Features); if (DisableFPElim.getNumOccurrences() > 0) - NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, "no-frame-pointer-elim", DisableFPElim ? "true" : "false"); if (DisableTailCalls.getNumOccurrences() > 0) - NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, "disable-tail-calls", toStringRef(DisableTailCalls)); if (StackRealign) - NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, "stackrealign"); if (TrapFuncName.getNumOccurrences() > 0) @@ -376,12 +377,12 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features, if (const auto *F = Call->getCalledFunction()) if (F->getIntrinsicID() == Intrinsic::debugtrap || F->getIntrinsicID() == Intrinsic::trap) - Call->addAttribute(llvm::AttributeSet::FunctionIndex, - Attribute::get(Ctx, "trap-func-name", - TrapFuncName)); + Call->addAttribute( + llvm::AttributeList::FunctionIndex, + Attribute::get(Ctx, "trap-func-name", TrapFuncName)); // Let NewAttrs override Attrs. - NewAttrs = Attrs.addAttributes(Ctx, AttributeSet::FunctionIndex, NewAttrs); + NewAttrs = Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs); F.setAttributes(NewAttrs); } } diff --git a/include/llvm/CodeGen/ExecutionDepsFix.h b/include/llvm/CodeGen/ExecutionDepsFix.h new file mode 100644 index 000000000000..1d5b9684e105 --- /dev/null +++ b/include/llvm/CodeGen/ExecutionDepsFix.h @@ -0,0 +1,220 @@ +//===- llvm/CodeGen/ExecutionDepsFix.h - Execution Dependency Fix -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file Execution Dependency Fix pass. +/// +/// Some X86 SSE instructions like mov, and, or, xor are available in different +/// variants for different operand types. These variant instructions are +/// equivalent, but on Nehalem and newer cpus there is extra latency +/// transferring data between integer and floating point domains. ARM cores +/// have similar issues when they are configured with both VFP and NEON +/// pipelines. +/// +/// This pass changes the variant instructions to minimize domain crossings. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CODEGEN_EXECUTIONDEPSFIX_H +#define LLVM_CODEGEN_EXECUTIONDEPSFIX_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/LivePhysRegs.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/RegisterClassInfo.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +namespace llvm { + +/// A DomainValue is a bit like LiveIntervals' ValNo, but it also keeps track +/// of execution domains. +/// +/// An open DomainValue represents a set of instructions that can still switch +/// execution domain. Multiple registers may refer to the same open +/// DomainValue - they will eventually be collapsed to the same execution +/// domain. +/// +/// A collapsed DomainValue represents a single register that has been forced +/// into one of more execution domains. There is a separate collapsed +/// DomainValue for each register, but it may contain multiple execution +/// domains. A register value is initially created in a single execution +/// domain, but if we were forced to pay the penalty of a domain crossing, we +/// keep track of the fact that the register is now available in multiple +/// domains. +struct DomainValue { + // Basic reference counting. + unsigned Refs; + + // Bitmask of available domains. For an open DomainValue, it is the still + // possible domains for collapsing. For a collapsed DomainValue it is the + // domains where the register is available for free. + unsigned AvailableDomains; + + // Pointer to the next DomainValue in a chain. When two DomainValues are + // merged, Victim.Next is set to point to Victor, so old DomainValue + // references can be updated by following the chain. + DomainValue *Next; + + // Twiddleable instructions using or defining these registers. + SmallVector<MachineInstr*, 8> Instrs; + + // A collapsed DomainValue has no instructions to twiddle - it simply keeps + // track of the domains where the registers are already available. + bool isCollapsed() const { return Instrs.empty(); } + + // Is domain available? + bool hasDomain(unsigned domain) const { + assert(domain < + static_cast<unsigned>(std::numeric_limits<unsigned>::digits) && + "undefined behavior"); + return AvailableDomains & (1u << domain); + } + + // Mark domain as available. + void addDomain(unsigned domain) { + AvailableDomains |= 1u << domain; + } + + // Restrict to a single domain available. + void setSingleDomain(unsigned domain) { + AvailableDomains = 1u << domain; + } + + // Return bitmask of domains that are available and in mask. + unsigned getCommonDomains(unsigned mask) const { + return AvailableDomains & mask; + } + + // First domain available. + unsigned getFirstDomain() const { + return countTrailingZeros(AvailableDomains); + } + + DomainValue() : Refs(0) { clear(); } + + // Clear this DomainValue and point to next which has all its data. + void clear() { + AvailableDomains = 0; + Next = nullptr; + Instrs.clear(); + } +}; + +/// Information about a live register. +struct LiveReg { + /// Value currently in this register, or NULL when no value is being tracked. + /// This counts as a DomainValue reference. + DomainValue *Value; + + /// Instruction that defined this register, relative to the beginning of the + /// current basic block. When a LiveReg is used to represent a live-out + /// register, this value is relative to the end of the basic block, so it + /// will be a negative number. + int Def; +}; + +class ExecutionDepsFix : public MachineFunctionPass { + SpecificBumpPtrAllocator<DomainValue> Allocator; + SmallVector<DomainValue*,16> Avail; + + const TargetRegisterClass *const RC; + MachineFunction *MF; + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + RegisterClassInfo RegClassInfo; + std::vector<SmallVector<int, 1>> AliasMap; + const unsigned NumRegs; + LiveReg *LiveRegs; + struct MBBInfo { + // Keeps clearance and domain information for all registers. Note that this + // is different from the usual definition notion of liveness. The CPU + // doesn't care whether or not we consider a register killed. + LiveReg *OutRegs; + + // Whether we have gotten to this block in primary processing yet. + bool PrimaryCompleted; + + // The number of predecessors for which primary processing has completed + unsigned IncomingProcessed; + + // The value of `IncomingProcessed` at the start of primary processing + unsigned PrimaryIncoming; + + // The number of predecessors for which all processing steps are done. + unsigned IncomingCompleted; + + MBBInfo() + : OutRegs(nullptr), PrimaryCompleted(false), IncomingProcessed(0), + PrimaryIncoming(0), IncomingCompleted(0) {} + }; + typedef DenseMap<MachineBasicBlock *, MBBInfo> MBBInfoMap; + MBBInfoMap MBBInfos; + + /// List of undefined register reads in this block in forward order. + std::vector<std::pair<MachineInstr*, unsigned> > UndefReads; + + /// Storage for register unit liveness. + LivePhysRegs LiveRegSet; + + /// Current instruction number. + /// The first instruction in each basic block is 0. + int CurInstr; +public: + ExecutionDepsFix(char &PassID, const TargetRegisterClass &RC) + : MachineFunctionPass(PassID), RC(&RC), NumRegs(RC.getNumRegs()) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::NoVRegs); + } + +private: + iterator_range<SmallVectorImpl<int>::const_iterator> + regIndices(unsigned Reg) const; + // DomainValue allocation. + DomainValue *alloc(int domain = -1); + DomainValue *retain(DomainValue *DV) { + if (DV) ++DV->Refs; + return DV; + } + void release(DomainValue*); + DomainValue *resolve(DomainValue*&); + + // LiveRegs manipulations. + void setLiveReg(int rx, DomainValue *DV); + void kill(int rx); + void force(int rx, unsigned domain); + void collapse(DomainValue *dv, unsigned domain); + bool merge(DomainValue *A, DomainValue *B); + + void enterBasicBlock(MachineBasicBlock*); + void leaveBasicBlock(MachineBasicBlock*); + bool isBlockDone(MachineBasicBlock *); + void processBasicBlock(MachineBasicBlock *MBB, bool PrimaryPass); + bool visitInstr(MachineInstr *); + void processDefs(MachineInstr *, bool breakDependency, bool Kill); + void visitSoftInstr(MachineInstr*, unsigned mask); + void visitHardInstr(MachineInstr*, unsigned domain); + bool pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx, + unsigned Pref); + bool shouldBreakDependence(MachineInstr*, unsigned OpIdx, unsigned Pref); + void processUndefReads(MachineBasicBlock*); +}; + +} // end namepsace llvm + +#endif diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index cdaea250c33b..2abe3bb11556 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -1,4 +1,4 @@ -//===-- FastISel.h - Definition of the FastISel class ---*- C++ -*---------===// +//===- FastISel.h - Definition of the FastISel class ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,10 +16,21 @@ #define LLVM_CODEGEN_FASTISEL_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/Target/TargetLowering.h" +#include <algorithm> +#include <cstdint> +#include <utility> +#include <vector> namespace llvm { @@ -30,57 +41,31 @@ class MachineConstantPool; /// quickly. class FastISel { public: - struct ArgListEntry { - Value *Val; - Type *Ty; - bool IsSExt : 1; - bool IsZExt : 1; - bool IsInReg : 1; - bool IsSRet : 1; - bool IsNest : 1; - 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), IsSwiftSelf(false), - IsSwiftError(false), Alignment(0) {} - - /// \brief Set CallLoweringInfo attribute flags based on a call instruction - /// and called function attributes. - void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx); - }; - typedef std::vector<ArgListEntry> ArgListTy; - + typedef TargetLoweringBase::ArgListEntry ArgListEntry; + typedef TargetLoweringBase::ArgListTy ArgListTy; struct CallLoweringInfo { - Type *RetTy; + Type *RetTy = nullptr; bool RetSExt : 1; bool RetZExt : 1; bool IsVarArg : 1; bool IsInReg : 1; bool DoesNotReturn : 1; bool IsReturnValueUsed : 1; + bool IsPatchPoint : 1; // \brief IsTailCall Should be modified by implementations of FastLowerCall // that perform tail call conversions. - bool IsTailCall; + bool IsTailCall = false; - unsigned NumFixedArgs; - CallingConv::ID CallConv; - const Value *Callee; - MCSymbol *Symbol; + unsigned NumFixedArgs = -1; + CallingConv::ID CallConv = CallingConv::C; + const Value *Callee = nullptr; + MCSymbol *Symbol = nullptr; ArgListTy Args; - ImmutableCallSite *CS; - MachineInstr *Call; - unsigned ResultReg; - unsigned NumResultRegs; - - bool IsPatchPoint; + ImmutableCallSite *CS = nullptr; + MachineInstr *Call = nullptr; + unsigned ResultReg = 0; + unsigned NumResultRegs = 0; SmallVector<Value *, 16> OutVals; SmallVector<ISD::ArgFlagsTy, 16> OutFlags; @@ -89,11 +74,8 @@ public: SmallVector<unsigned, 4> InRegs; CallLoweringInfo() - : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false), - IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), - IsTailCall(false), NumFixedArgs(-1), CallConv(CallingConv::C), - Callee(nullptr), Symbol(nullptr), CS(nullptr), Call(nullptr), - ResultReg(0), NumResultRegs(0), IsPatchPoint(false) {} + : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false), + DoesNotReturn(false), IsReturnValueUsed(true), IsPatchPoint(false) {} CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy, const Value *Target, ArgListTy &&ArgsList, @@ -101,12 +83,12 @@ public: RetTy = ResultTy; Callee = Target; - IsInReg = Call.paramHasAttr(0, Attribute::InReg); + IsInReg = Call.hasRetAttr(Attribute::InReg); DoesNotReturn = Call.doesNotReturn(); IsVarArg = FuncTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); - RetSExt = Call.paramHasAttr(0, Attribute::SExt); - RetZExt = Call.paramHasAttr(0, Attribute::ZExt); + RetSExt = Call.hasRetAttr(Attribute::SExt); + RetZExt = Call.hasRetAttr(Attribute::ZExt); CallConv = Call.getCallingConv(); Args = std::move(ArgsList); @@ -125,12 +107,12 @@ public: Callee = Call.getCalledValue(); Symbol = Target; - IsInReg = Call.paramHasAttr(0, Attribute::InReg); + IsInReg = Call.hasRetAttr(Attribute::InReg); DoesNotReturn = Call.doesNotReturn(); IsVarArg = FuncTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); - RetSExt = Call.paramHasAttr(0, Attribute::SExt); - RetZExt = Call.paramHasAttr(0, Attribute::ZExt); + RetSExt = Call.hasRetAttr(Attribute::SExt); + RetZExt = Call.hasRetAttr(Attribute::ZExt); CallConv = Call.getCallingConv(); Args = std::move(ArgsList); @@ -510,7 +492,6 @@ protected: } } - bool lowerCall(const CallInst *I); /// \brief Select and emit code for a binary operator instruction, which has /// an opcode which directly corresponds to the given ISD opcode. @@ -567,4 +548,4 @@ private: } // end namespace llvm -#endif +#endif // LLVM_CODEGEN_FASTISEL_H diff --git a/include/llvm/CodeGen/FaultMaps.h b/include/llvm/CodeGen/FaultMaps.h index 9b5a3e1ba050..0f0005b83c54 100644 --- a/include/llvm/CodeGen/FaultMaps.h +++ b/include/llvm/CodeGen/FaultMaps.h @@ -1,4 +1,4 @@ -//===------------------- FaultMaps.h - The "FaultMaps" section --*- C++ -*-===// +//===- FaultMaps.h - The "FaultMaps" section --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,26 +12,31 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Format.h" - -#include <vector> +#include <cassert> +#include <cstddef> +#include <cstdint> #include <map> +#include <vector> namespace llvm { class AsmPrinter; class MCExpr; -class MCSymbol; -class MCStreamer; +class raw_ostream; class FaultMaps { public: - enum FaultKind { FaultingLoad = 1, FaultKindMax }; - - static const char *faultTypeToString(FaultKind); + enum FaultKind { + FaultingLoad = 1, + FaultingLoadStore, + FaultingStore, + FaultKindMax + }; explicit FaultMaps(AsmPrinter &AP); + static const char *faultTypeToString(FaultKind); + void recordFaultingOp(FaultKind FaultTy, const MCSymbol *HandlerLabel); void serializeToFaultMapSection(); @@ -39,13 +44,11 @@ private: static const char *WFMP; struct FaultInfo { - FaultKind Kind; - const MCExpr *FaultingOffsetExpr; - const MCExpr *HandlerOffsetExpr; + FaultKind Kind = FaultKindMax; + const MCExpr *FaultingOffsetExpr = nullptr; + const MCExpr *HandlerOffsetExpr = nullptr; - FaultInfo() - : Kind(FaultKindMax), FaultingOffsetExpr(nullptr), - HandlerOffsetExpr(nullptr) {} + FaultInfo() = default; explicit FaultInfo(FaultMaps::FaultKind Kind, const MCExpr *FaultingOffset, const MCExpr *HandlerOffset) @@ -153,11 +156,11 @@ public: static const size_t FunctionInfoHeaderSize = FunctionFaultInfosOffset; - const uint8_t *P; - const uint8_t *E; + const uint8_t *P = nullptr; + const uint8_t *E = nullptr; public: - FunctionInfoAccessor() : P(nullptr), E(nullptr) {} + FunctionInfoAccessor() = default; explicit FunctionInfoAccessor(const uint8_t *P, const uint8_t *E) : P(P), E(E) {} @@ -214,6 +217,6 @@ raw_ostream &operator<<(raw_ostream &OS, raw_ostream &operator<<(raw_ostream &OS, const FaultMapParser &); -} // namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_FAULTMAPS_H diff --git a/include/llvm/CodeGen/GCStrategy.h b/include/llvm/CodeGen/GCStrategy.h index 3088a86a3260..5b1fafea25b5 100644 --- a/include/llvm/CodeGen/GCStrategy.h +++ b/include/llvm/CodeGen/GCStrategy.h @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/GCStrategy.h - Garbage collection ----------*- C++ -*-===// +//===- llvm/CodeGen/GCStrategy.h - Garbage collection -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -47,19 +47,20 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_IR_GCSTRATEGY_H -#define LLVM_IR_GCSTRATEGY_H +#ifndef LLVM_CODEGEN_GCSTRATEGY_H +#define LLVM_CODEGEN_GCSTRATEGY_H +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Registry.h" #include <string> namespace llvm { + +class Type; + namespace GC { + /// PointKind - Used to indicate whether the address of the call instruction /// or the address after the call instruction is listed in the stackmap. For /// most runtimes, PostCall safepoints are appropriate. @@ -68,7 +69,8 @@ enum PointKind { PreCall, ///< Instr is a call instruction. PostCall ///< Instr is the return address of a call. }; -} + +} // end namespace GC /// GCStrategy describes a garbage collector algorithm's code generation /// requirements, and provides overridable hooks for those needs which cannot @@ -77,24 +79,25 @@ enum PointKind { /// be immutable. class GCStrategy { private: - std::string Name; friend class GCModuleInfo; + std::string Name; + protected: - bool UseStatepoints; /// Uses gc.statepoints as opposed to gc.roots, - /// if set, none of the other options can be - /// anything but their default values. + bool UseStatepoints = false; /// Uses gc.statepoints as opposed to gc.roots, + /// if set, none of the other options can be + /// anything but their default values. - unsigned NeededSafePoints; ///< Bitmask of required safe points. - bool CustomReadBarriers; ///< Default is to insert loads. - bool CustomWriteBarriers; ///< Default is to insert stores. - bool CustomRoots; ///< Default is to pass through to backend. - bool InitRoots; ///< If set, roots are nulled during lowering. - bool UsesMetadata; ///< If set, backend must emit metadata tables. + unsigned NeededSafePoints = 0; ///< Bitmask of required safe points. + bool CustomReadBarriers = false; ///< Default is to insert loads. + bool CustomWriteBarriers = false; ///< Default is to insert stores. + bool CustomRoots = false; ///< Default is to pass through to backend. + bool InitRoots= true; ///< If set, roots are nulled during lowering. + bool UsesMetadata = false; ///< If set, backend must emit metadata tables. public: GCStrategy(); - virtual ~GCStrategy() {} + virtual ~GCStrategy() = default; /// Return the name of the GC strategy. This is the value of the collector /// name string specified on functions which use this strategy. @@ -172,6 +175,7 @@ public: /// register your GCMetadataPrinter subclass with the /// GCMetadataPrinterRegistery as well. typedef Registry<GCStrategy> GCRegistry; -} -#endif +} // end namespace llvm + +#endif // LLVM_CODEGEN_GCSTRATEGY_H diff --git a/include/llvm/CodeGen/GlobalISel/CallLowering.h b/include/llvm/CodeGen/GlobalISel/CallLowering.h index 0b157bf937a3..3e9a9d514cb8 100644 --- a/include/llvm/CodeGen/GlobalISel/CallLowering.h +++ b/include/llvm/CodeGen/GlobalISel/CallLowering.h @@ -35,9 +35,11 @@ public: unsigned Reg; Type *Ty; ISD::ArgFlagsTy Flags; + bool IsFixed; - ArgInfo(unsigned Reg, Type *Ty, ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy{}) - : Reg(Reg), Ty(Ty), Flags(Flags) {} + ArgInfo(unsigned Reg, Type *Ty, ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy{}, + bool IsFixed = true) + : Reg(Reg), Ty(Ty), Flags(Flags), IsFixed(IsFixed) {} }; /// Argument handling is mostly uniform between the four places that @@ -68,15 +70,34 @@ public: uint64_t Size, MachinePointerInfo &MPO, CCValAssign &VA) = 0; + /// Handle custom values, which may be passed into one or more of \p VAs. + /// \return The number of \p VAs that have been assigned after the first + /// one, and which should therefore be skipped from further + /// processing. + virtual unsigned assignCustomValue(const ArgInfo &Arg, + ArrayRef<CCValAssign> VAs) { + // This is not a pure virtual method because not all targets need to worry + // about custom values. + llvm_unreachable("Custom values not supported"); + } + unsigned extendRegister(unsigned ValReg, CCValAssign &VA); - ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI) - : MIRBuilder(MIRBuilder), MRI(MRI) {} + virtual bool assignArg(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, const ArgInfo &Info, + CCState &State) { + return AssignFn(ValNo, ValVT, LocVT, LocInfo, Info.Flags, State); + } + + ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, + CCAssignFn *AssignFn) + : MIRBuilder(MIRBuilder), MRI(MRI), AssignFn(AssignFn) {} virtual ~ValueHandler() {} MachineIRBuilder &MIRBuilder; MachineRegisterInfo &MRI; + CCAssignFn *AssignFn; }; protected: @@ -96,12 +117,12 @@ protected: void setArgFlags(ArgInfo &Arg, unsigned OpNum, const DataLayout &DL, const FuncInfoTy &FuncInfo) const; - /// Invoke the \p AssignFn on each of the given \p Args and then use + /// Invoke Handler::assignArg on each of the given \p Args and then use /// \p Callback to move them to the assigned locations. /// /// \return True if everything has succeeded, false otherwise. - bool handleAssignments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn, - ArrayRef<ArgInfo> Args, ValueHandler &Callback) const; + bool handleAssignments(MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args, + ValueHandler &Callback) const; public: CallLowering(const TargetLowering *TLI) : TLI(TLI) {} @@ -135,6 +156,8 @@ public: /// This hook must be implemented to lower the given call instruction, /// including argument and return value marshalling. /// + /// \p CallConv is the calling convention to be used for the call. + /// /// \p Callee is the destination of the call. It should be either a register, /// globaladdress, or externalsymbol. /// @@ -150,14 +173,16 @@ public: /// needs to be passed. /// /// \return true if the lowering succeeded, false otherwise. - virtual bool lowerCall(MachineIRBuilder &MIRBuilder, + virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv, const MachineOperand &Callee, const ArgInfo &OrigRet, ArrayRef<ArgInfo> OrigArgs) const { return false; } - /// This hook must be implemented to lower the given call instruction, - /// including argument and return value marshalling. + /// Lower the given call instruction, including argument and return value + /// marshalling. + /// + /// \p CI is the call/invoke instruction. /// /// \p ResReg is a register where the call's return value should be stored (or /// 0 if there is no return value). @@ -171,9 +196,9 @@ public: /// range of an immediate jump. /// /// \return true if the lowering succeeded, false otherwise. - virtual bool lowerCall(MachineIRBuilder &MIRBuilder, const CallInst &CI, - unsigned ResReg, ArrayRef<unsigned> ArgRegs, - std::function<unsigned()> GetCalleeReg) const; + bool lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS, + unsigned ResReg, ArrayRef<unsigned> ArgRegs, + std::function<unsigned()> GetCalleeReg) const; }; } // End namespace llvm. diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 26ba5c67beb5..31ffdc0e2e78 100644 --- a/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -34,6 +34,7 @@ class Instruction; class MachineBasicBlock; class MachineFunction; class MachineInstr; +class OptimizationRemarkEmitter; class MachineRegisterInfo; class TargetPassConfig; @@ -55,21 +56,20 @@ private: /// 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; // N.b. it's not completely obvious that this will be sufficient for every // LLVM IR construct (with "invoke" being the obvious candidate to mess up our // lives. DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB; + // One BasicBlock can be translated to multiple MachineBasicBlocks. For such + // BasicBlocks translated to multiple MachineBasicBlocks, MachinePreds retains + // a mapping between the edges arriving at the BasicBlock to the corresponding + // created MachineBasicBlocks. Some BasicBlocks that get translated to a + // single MachineBasicBlock may also end up in this Map. + typedef std::pair<const BasicBlock *, const BasicBlock *> CFGEdge; + DenseMap<CFGEdge, SmallVector<MachineBasicBlock *, 1>> MachinePreds; + // List of stubbed PHI instructions, for values and basic blocks to be filled // in once all MachineBasicBlocks have been created. SmallVector<std::pair<const PHINode *, MachineInstr *>, 4> PendingPHIs; @@ -122,7 +122,9 @@ private: /// Translate an LLVM store instruction into generic IR. bool translateStore(const User &U, MachineIRBuilder &MIRBuilder); - bool translateMemcpy(const CallInst &CI, MachineIRBuilder &MIRBuilder); + /// Translate an LLVM string intrinsic (memcpy, memset, ...). + bool translateMemfunc(const CallInst &CI, MachineIRBuilder &MIRBuilder, + unsigned Intrinsic); void getStackGuard(unsigned DstReg, MachineIRBuilder &MIRBuilder); @@ -132,6 +134,8 @@ private: bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder); + bool translateInlineAsm(const CallInst &CI, MachineIRBuilder &MIRBuilder); + /// Translate call instruction. /// \pre \p U is a call instruction. bool translateCall(const User &U, MachineIRBuilder &MIRBuilder); @@ -145,11 +149,6 @@ private: bool translateCast(unsigned Opcode, const User &U, MachineIRBuilder &MIRBuilder); - /// Translate static alloca instruction (i.e. one of constant size and in the - /// first basic block). - bool translateStaticAlloca(const AllocaInst &Inst, - MachineIRBuilder &MIRBuilder); - /// Translate a phi instruction. bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder); @@ -182,6 +181,8 @@ private: bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder); + bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder); + bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder); bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder); @@ -190,12 +191,16 @@ private: bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder); + bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder); + /// Translate return (ret) instruction. /// The target needs to implement CallLowering::lowerReturn for /// this to succeed. /// \pre \p U is a return instruction. bool translateRet(const User &U, MachineIRBuilder &MIRBuilder); + bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder); + bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder); } @@ -227,9 +232,6 @@ private: bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder); } - bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder) { - return translateStaticAlloca(cast<AllocaInst>(U), MIRBuilder); - } bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder); } @@ -281,9 +283,6 @@ private: bool translateFAdd(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FADD, U, MIRBuilder); } - bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder) { - return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder); - } bool translateFMul(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FMUL, U, MIRBuilder); } @@ -294,11 +293,16 @@ private: return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder); } + bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder); + + bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder); + + bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder); + + bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder); + // Stubs to keep the compiler happy while we implement the rest of the // translation. - bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) { return false; } @@ -335,18 +339,6 @@ private: bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) { return false; } - bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } - bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } - bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } - bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } /// @} @@ -371,6 +363,9 @@ private: /// Current target configuration. Controls how the pass handles errors. const TargetPassConfig *TPC; + /// Current optimization remark emitter. Used to report failures. + std::unique_ptr<OptimizationRemarkEmitter> ORE; + // * 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. @@ -390,10 +385,27 @@ private: /// the type being accessed (according to the Module's DataLayout). unsigned getMemOpAlignment(const Instruction &I); - /// Get the MachineBasicBlock that represents \p BB. - /// If such basic block does not exist, it is created. - MachineBasicBlock &getOrCreateBB(const BasicBlock &BB); + /// Get the MachineBasicBlock that represents \p BB. Specifically, the block + /// returned will be the head of the translated block (suitable for branch + /// destinations). + MachineBasicBlock &getMBB(const BasicBlock &BB); + + /// Record \p NewPred as a Machine predecessor to `Edge.second`, corresponding + /// to `Edge.first` at the IR level. This is used when IRTranslation creates + /// multiple MachineBasicBlocks for a given IR block and the CFG is no longer + /// represented simply by the IR-level CFG. + void addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred); + /// Returns the Machine IR predecessors for the given IR CFG edge. Usually + /// this is just the single MachineBasicBlock corresponding to the predecessor + /// in the IR. More complex lowering can result in multiple MachineBasicBlocks + /// preceding the original though (e.g. switch instructions). + SmallVector<MachineBasicBlock *, 1> getMachinePredBBs(CFGEdge Edge) { + auto RemappedEdge = MachinePreds.find(Edge); + if (RemappedEdge != MachinePreds.end()) + return RemappedEdge->second; + return SmallVector<MachineBasicBlock *, 4>(1, &getMBB(*Edge.first)); + } public: // Ctor, nothing fancy. @@ -407,13 +419,13 @@ public: // CallLowering = MF.subtarget.getCallLowering() // F = MF.getParent() // MIRBuilder.reset(MF) - // MIRBuilder.getOrCreateBB(F.getEntryBB()) + // getMBB(F.getEntryBB()) // CallLowering->translateArguments(MIRBuilder, F, ValToVReg) // for each bb in F - // MIRBuilder.getOrCreateBB(bb) + // getMBB(bb) // for each inst in bb // if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence)) - // report_fatal_error(“Don’t know how to translate input"); + // report_fatal_error("Don't know how to translate input"); // finalize() bool runOnMachineFunction(MachineFunction &MF) override; }; diff --git a/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index 63b4f7b9507f..d8096aeb215a 100644 --- a/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -16,8 +16,13 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H +#include "llvm/ADT/Optional.h" +#include <cstdint> + namespace llvm { class MachineInstr; +class MachineOperand; +class MachineRegisterInfo; class RegisterBankInfo; class TargetInstrInfo; class TargetRegisterInfo; @@ -56,6 +61,14 @@ protected: const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const; + + Optional<int64_t> getConstantVRegVal(unsigned VReg, + const MachineRegisterInfo &MRI) const; + + bool isOperandImmEqual(const MachineOperand &MO, int64_t Value, + const MachineRegisterInfo &MRI) const; + + bool isObviouslySafeToFold(MachineInstr &MI) const; }; } // End namespace llvm. diff --git a/include/llvm/CodeGen/GlobalISel/Legalizer.h b/include/llvm/CodeGen/GlobalISel/Legalizer.h index 8284ab6dac65..bed7230cc013 100644 --- a/include/llvm/CodeGen/GlobalISel/Legalizer.h +++ b/include/llvm/CodeGen/GlobalISel/Legalizer.h @@ -58,6 +58,9 @@ public: bool combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII); + bool combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, + const TargetInstrInfo &TII); + bool runOnMachineFunction(MachineFunction &MF) override; }; } // End namespace llvm. diff --git a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index 56c444ca46be..8fecafdc08d0 100644 --- a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -55,11 +55,7 @@ public: /// /// Considered as an opaque blob, the legal code will use and define the same /// registers as \p MI. - LegalizeResult legalizeInstrStep(MachineInstr &MI, - const LegalizerInfo &LegalizerInfo); - - LegalizeResult legalizeInstr(MachineInstr &MI, - const LegalizerInfo &LegalizerInfo); + LegalizeResult legalizeInstrStep(MachineInstr &MI); /// Legalize an instruction by emiting a runtime library call instead. LegalizeResult libcall(MachineInstr &MI); @@ -87,6 +83,10 @@ public: LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT WideTy); + /// Expose MIRBuilder so clients can set their own RecordInsertInstruction + /// functions + MachineIRBuilder MIRBuilder; + private: /// Helper function to split a wide generic register into bitwise blocks with @@ -95,8 +95,8 @@ private: void extractParts(unsigned Reg, LLT Ty, int NumParts, SmallVectorImpl<unsigned> &Ops); - MachineIRBuilder MIRBuilder; MachineRegisterInfo &MRI; + const LegalizerInfo &LI; }; } // End namespace llvm. diff --git a/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h index edf52daf3f8f..30d67eb49923 100644 --- a/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ b/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -25,6 +25,7 @@ namespace llvm { class LLVMContext; class MachineInstr; +class MachineIRBuilder; class MachineRegisterInfo; class Type; class VectorType; @@ -96,6 +97,7 @@ public: }; LegalizerInfo(); + virtual ~LegalizerInfo() = default; /// Compute any ancillary tables needed to quickly decide how an operation /// should be handled. This must be called after all "set*Action"methods but @@ -144,7 +146,7 @@ public: /// Iterate the given function (typically something like doubling the width) /// on Ty until we find a legal type for this operation. LLT findLegalType(const InstrAspect &Aspect, - std::function<LLT(LLT)> NextType) const { + function_ref<LLT(LLT)> NextType) const { LegalizeAction Action; const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx]; LLT Ty = Aspect.Type; @@ -186,6 +188,10 @@ public: bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const; + virtual bool legalizeCustom(MachineInstr &MI, + MachineRegisterInfo &MRI, + MachineIRBuilder &MIRBuilder) const; + private: static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START; static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index ecd3e5e1e138..472f50576d96 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -108,6 +108,9 @@ public: /// Set the debug location to \p DL for all the next build instructions. void setDebugLoc(const DebugLoc &DL) { this->DL = DL; } + /// Get the current instruction's debug location. + DebugLoc getDebugLoc() { return DL; } + /// Build and insert <empty> = \p Opcode <empty>. /// The insertion point is the one set by the last call of either /// setBasicBlock or setMI. @@ -127,6 +130,29 @@ public: /// Insert an existing instruction at the insertion point. MachineInstrBuilder insertInstr(MachineInstrBuilder MIB); + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in \p Reg (suitably modified by \p Expr). + MachineInstrBuilder buildDirectDbgValue(unsigned Reg, const MDNode *Variable, + const MDNode *Expr); + + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in memory at \p Reg + \p Offset (suitably + /// modified by \p Expr). + MachineInstrBuilder buildIndirectDbgValue(unsigned Reg, unsigned Offset, + const MDNode *Variable, + const MDNode *Expr); + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in the stack slot specified by \p FI + /// (suitably modified by \p Expr). + MachineInstrBuilder buildFIDbgValue(int FI, const MDNode *Variable, + const MDNode *Expr); + + /// Build and insert a DBG_VALUE instructions specifying that \p Variable is + /// given by \p C (suitably modified by \p Expr). + MachineInstrBuilder buildConstDbgValue(const Constant &C, unsigned Offset, + const MDNode *Variable, + const MDNode *Expr); + /// Build and insert \p Res<def> = G_FRAME_INDEX \p Idx /// /// G_FRAME_INDEX materializes the address of an alloca value or other @@ -203,6 +229,22 @@ public: MachineInstrBuilder buildGEP(unsigned Res, unsigned Op0, unsigned Op1); + /// Build and insert \p Res<def> = G_PTR_MASK \p Op0, \p NumBits + /// + /// G_PTR_MASK clears the low bits of a pointer operand without destroying its + /// pointer properties. This has the effect of rounding the address *down* to + /// a specified alignment in bits. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res and \p Op0 must be generic virtual registers with pointer + /// type. + /// \pre \p NumBits must be an integer representing the number of low bits to + /// be cleared in \p Op0. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildPtrMask(unsigned Res, unsigned Op0, + uint32_t NumBits); + /// Build and insert \p Res<def>, \p CarryOut<def> = G_UADDE \p Op0, /// \p Op1, \p CarryIn /// @@ -220,6 +262,19 @@ public: MachineInstrBuilder buildUAdde(unsigned Res, unsigned CarryOut, unsigned Op0, unsigned Op1, unsigned CarryIn); + /// Build and insert \p Res<def> = G_AND \p Op0, \p Op1 + /// + /// G_AND sets \p Res to the bitwise and of integer parameters \p Op0 and \p + /// Op1. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers + /// with the same (scalar or vector) type). + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildAnd(unsigned Res, unsigned Op0, + unsigned Op1); + /// Build and insert \p Res<def> = G_ANYEXT \p Op0 /// /// G_ANYEXT produces a register of the specified width, with bits 0 to @@ -273,6 +328,19 @@ public: /// \return The newly created instruction. MachineInstrBuilder buildSExtOrTrunc(unsigned Res, unsigned Op); + /// Build and insert \p Res<def> = G_ZEXT \p Op, \p Res = G_TRUNC \p Op, or + /// \p Res = COPY \p Op depending on the differing sizes of \p Res and \p Op. + /// /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res must be a generic virtual register with scalar or vector type. + /// \pre \p Op must be a generic virtual register with scalar or vector type. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildZExtOrTrunc(unsigned Res, unsigned Op); + + /// Build and insert an appropriate cast between two registers of equal size. + MachineInstrBuilder buildCast(unsigned Dst, unsigned Src); + /// Build and insert G_BR \p Dest /// /// G_BR is an unconditional branch to \p Dest. @@ -296,6 +364,16 @@ public: /// \return The newly created instruction. MachineInstrBuilder buildBrCond(unsigned Tst, MachineBasicBlock &BB); + /// Build and insert G_BRINDIRECT \p Tgt + /// + /// G_BRINDIRECT is an indirect branch to \p Tgt. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Tgt must be a generic virtual register with pointer type. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildBrIndirect(unsigned Tgt); + /// Build and insert \p Res = G_CONSTANT \p Val /// /// G_CONSTANT is an integer constant with the specified size and value. \p @@ -362,19 +440,16 @@ public: MachineInstrBuilder buildStore(unsigned Val, unsigned Addr, MachineMemOperand &MMO); - /// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0, ...`. - /// - /// If \p Res[i] has size N bits, G_EXTRACT sets \p Res[i] to bits `[Idxs[i], - /// Idxs[i] + N)` of \p Src. + /// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0`. /// /// \pre setBasicBlock or setMI must have been called. - /// \pre Indices must be in ascending order of bit position. - /// \pre Each member of \p Results and \p Src must be a generic - /// virtual register. + /// \pre \p Res and \p Src must be generic virtual registers. /// /// \return a MachineInstrBuilder for the newly created instruction. - MachineInstrBuilder buildExtract(ArrayRef<unsigned> Results, - ArrayRef<uint64_t> Indices, unsigned Src); + MachineInstrBuilder buildExtract(unsigned Res, unsigned Src, uint64_t Index); + + /// Build and insert \p Res = IMPLICIT_DEF. + MachineInstrBuilder buildUndef(unsigned Dst); /// Build and insert \p Res<def> = G_SEQUENCE \p Op0, \p Idx0... /// @@ -393,6 +468,31 @@ public: ArrayRef<unsigned> Ops, ArrayRef<uint64_t> Indices); + /// Build and insert \p Res<def> = G_MERGE_VALUES \p Op0, ... + /// + /// G_MERGE_VALUES combines the input elements contiguously into a larger + /// register. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The entire register \p Res (and no more) must be covered by the input + /// registers. + /// \pre The type of all \p Ops registers must be identical. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildMerge(unsigned Res, ArrayRef<unsigned> Ops); + + /// Build and insert \p Res0<def>, ... = G_UNMERGE_VALUES \p Op + /// + /// G_UNMERGE_VALUES splits contiguous bits of the input into multiple + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The entire register \p Res (and no more) must be covered by the input + /// registers. + /// \pre The type of all \p Res registers must be identical. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildUnmerge(ArrayRef<unsigned> Res, unsigned Op); + void addUsesWithIndices(MachineInstrBuilder MIB) {} template <typename... ArgTys> @@ -411,14 +511,8 @@ public: return MIB; } - template <typename... ArgTys> MachineInstrBuilder buildInsert(unsigned Res, unsigned Src, - unsigned Op, unsigned Index, ArgTys... Args) { - MachineInstrBuilder MIB = - buildInstr(TargetOpcode::G_INSERT).addDef(Res).addUse(Src); - addUsesWithIndices(MIB, Op, Index, Args...); - return MIB; - } + unsigned Op, unsigned Index); /// Build and insert either a G_INTRINSIC (if \p HasSideEffects is false) or /// G_INTRINSIC_W_SIDE_EFFECTS instruction. Its first operand will be the @@ -500,6 +594,30 @@ public: /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst, unsigned Op0, unsigned Op1); + + /// Build and insert \p Res<def> = G_INSERT_VECTOR_ELT \p Val, + /// \p Elt, \p Idx + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res and \p Val must be a generic virtual register + // with the same vector type. + /// \pre \p Elt and \p Idx must be a generic virtual register + /// with scalar type. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildInsertVectorElement(unsigned Res, unsigned Val, + unsigned Elt, unsigned Idx); + + /// Build and insert \p Res<def> = G_EXTRACT_VECTOR_ELT \p Val, \p Idx + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res must be a generic virtual register with scalar type. + /// \pre \p Val must be a generic virtual register with vector type. + /// \pre \p Idx must be a generic virtual register with scalar type. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildExtractVectorElement(unsigned Res, unsigned Val, + unsigned Idx); }; } // End namespace llvm. diff --git a/include/llvm/CodeGen/GlobalISel/RegBankSelect.h b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h index b331533cd7fb..daa8dcf2061b 100644 --- a/include/llvm/CodeGen/GlobalISel/RegBankSelect.h +++ b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h @@ -67,6 +67,7 @@ #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" namespace llvm { // Forward declarations. @@ -484,6 +485,9 @@ private: /// This is required for non-fast mode. MachineBranchProbabilityInfo *MBPI; + /// Current optimization remark emitter. Used to report failures. + std::unique_ptr<MachineOptimizationRemarkEmitter> MORE; + /// Helper class used for every code morphing. MachineIRBuilder MIRBuilder; diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBank.h b/include/llvm/CodeGen/GlobalISel/RegisterBank.h index b05bf9948243..5d758423f4e7 100644 --- a/include/llvm/CodeGen/GlobalISel/RegisterBank.h +++ b/include/llvm/CodeGen/GlobalISel/RegisterBank.h @@ -42,7 +42,7 @@ private: public: RegisterBank(unsigned ID, const char *Name, unsigned Size, - const uint32_t *ContainedRegClasses); + const uint32_t *ContainedRegClasses, unsigned NumRegClasses); /// Get the identifier of this register bank. unsigned getID() const { return ID; } diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h index 312dc9314d45..600733ac6a2d 100644 --- a/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h +++ b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h @@ -317,12 +317,18 @@ public: /// The final mapping of the instruction. const InstructionMapping &getInstrMapping() const { return InstrMapping; } + + /// The MachineRegisterInfo we used to realize the mapping. + MachineRegisterInfo &getMRI() const { return MRI; } /// @} /// 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. + /// The type of the new registers is a plain scalar of the right size. + /// The proper type is expected to be set when the mapping is applied to + /// the instruction(s) that realizes the mapping. /// /// \pre getMI().getOperand(OpIdx).isReg() /// @@ -372,15 +378,15 @@ protected: /// Keep dynamically allocated PartialMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap<unsigned, const PartialMapping *> MapOfPartialMappings; + mutable DenseMap<unsigned, std::unique_ptr<const PartialMapping>> MapOfPartialMappings; /// Keep dynamically allocated ValueMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap<unsigned, const ValueMapping *> MapOfValueMappings; + mutable DenseMap<unsigned, std::unique_ptr<const ValueMapping> > MapOfValueMappings; /// Keep dynamically allocated array of ValueMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap<unsigned, ValueMapping *> MapOfOperandsMappings; + mutable DenseMap<unsigned, std::unique_ptr<ValueMapping[]>> MapOfOperandsMappings; /// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks /// RegisterBank instances. @@ -487,6 +493,12 @@ protected: /// Basically, that means that \p OpdMapper.getMI() is left untouched /// aside from the reassignment of the register operand that have been /// remapped. + /// + /// The type of all the new registers that have been created by the + /// mapper are properly remapped to the type of the original registers + /// they replace. In other words, the semantic of the instruction does + /// not change, only the register banks. + /// /// If the mapping of one of the operand spans several registers, this /// method will abort as this is not like a default mapping anymore. /// @@ -500,7 +512,7 @@ protected: } public: - virtual ~RegisterBankInfo(); + virtual ~RegisterBankInfo() = default; /// Get the register bank identified by \p ID. const RegisterBank &getRegBank(unsigned ID) const { diff --git a/include/llvm/CodeGen/GlobalISel/Utils.h b/include/llvm/CodeGen/GlobalISel/Utils.h index f5d5f5cdf0cd..52bf965a3cb3 100644 --- a/include/llvm/CodeGen/GlobalISel/Utils.h +++ b/include/llvm/CodeGen/GlobalISel/Utils.h @@ -15,15 +15,21 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_UTILS_H #define LLVM_CODEGEN_GLOBALISEL_UTILS_H +#include "llvm/ADT/StringRef.h" + namespace llvm { class MachineFunction; class MachineInstr; +class MachineOptimizationRemarkEmitter; +class MachineOptimizationRemarkMissed; class MachineRegisterInfo; class MCInstrDesc; class RegisterBankInfo; class TargetInstrInfo; +class TargetPassConfig; class TargetRegisterInfo; +class Twine; /// Try to constrain Reg so that it is usable by argument OpIdx of the /// provided MCInstrDesc \p II. If this fails, create a new virtual @@ -39,5 +45,20 @@ unsigned constrainOperandRegClass(const MachineFunction &MF, MachineInstr &InsertPt, const MCInstrDesc &II, unsigned Reg, unsigned OpIdx); +/// Check whether an instruction \p MI is dead: it only defines dead virtual +/// registers, and doesn't have other side effects. +bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI); + +/// Report an ISel error as a missed optimization remark to the LLVMContext's +/// diagnostic stream. Set the FailedISel MachineFunction property. +void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC, + MachineOptimizationRemarkEmitter &MORE, + MachineOptimizationRemarkMissed &R); + +void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC, + MachineOptimizationRemarkEmitter &MORE, + const char *PassName, StringRef Msg, + const MachineInstr &MI); + } // End namespace llvm. #endif diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index df700bf0c53d..ee3fd0bdda2a 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -245,6 +245,12 @@ namespace ISD { /// Simple binary floating point operators. FADD, FSUB, FMUL, FDIV, FREM, + /// Constrained versions of the binary floating point operators. + /// These will be lowered to the simple operators before final selection. + /// They are used to limit optimizations while the DAG is being + /// optimized. + STRICT_FADD, STRICT_FSUB, STRICT_FMUL, STRICT_FDIV, STRICT_FREM, + /// FMA - Perform a * b + c with no intermediate rounding step. FMA, @@ -281,7 +287,8 @@ namespace ISD { /// EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR /// identified by the (potentially variable) element number IDX. If the /// return type is an integer type larger than the element type of the - /// vector, the result is extended to the width of the return type. + /// vector, the result is extended to the width of the return type. In + /// that case, the high bits are undefined. EXTRACT_VECTOR_ELT, /// CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of @@ -332,6 +339,12 @@ namespace ISD { /// Bitwise operators - logical and, logical or, logical xor. AND, OR, XOR, + /// ABS - Determine the unsigned absolute value of a signed integer value of + /// the same bitwidth. + /// Note: A value of INT_MIN will return INT_MIN, no saturation or overflow + /// is performed. + ABS, + /// Shift and rotation operations. After legalization, the type of the /// shift amount is known to be TLI.getShiftAmountTy(). Before legalization /// the shift amount can be any type, but care must be taken to ensure it is @@ -801,10 +814,11 @@ namespace ISD { PRE_INC, PRE_DEC, POST_INC, - POST_DEC, - LAST_INDEXED_MODE + POST_DEC }; + static const int LAST_INDEXED_MODE = POST_DEC + 1; + //===--------------------------------------------------------------------===// /// LoadExtType enum - This enum defines the three variants of LOADEXT /// (load with extension). @@ -819,10 +833,11 @@ namespace ISD { NON_EXTLOAD = 0, EXTLOAD, SEXTLOAD, - ZEXTLOAD, - LAST_LOADEXT_TYPE + ZEXTLOAD }; + static const int LAST_LOADEXT_TYPE = ZEXTLOAD + 1; + NodeType getExtForLoadExtType(bool IsFP, LoadExtType); //===--------------------------------------------------------------------===// diff --git a/include/llvm/CodeGen/LazyMachineBlockFrequencyInfo.h b/include/llvm/CodeGen/LazyMachineBlockFrequencyInfo.h new file mode 100644 index 000000000000..848ee1dc0dc6 --- /dev/null +++ b/include/llvm/CodeGen/LazyMachineBlockFrequencyInfo.h @@ -0,0 +1,76 @@ +///===- LazyMachineBlockFrequencyInfo.h - Lazy Block Frequency -*- 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 an alternative analysis pass to MachineBlockFrequencyInfo. The +/// difference is that with this pass the block frequencies are not computed +/// when the analysis pass is executed but rather when the BFI result is +/// explicitly requested by the analysis client. +/// +///===---------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LAZYMACHINEBLOCKFREQUENCYINFO_H +#define LLVM_ANALYSIS_LAZYMACHINEBLOCKFREQUENCYINFO_H + +#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineLoopInfo.h" + +namespace llvm { +/// \brief This is an alternative analysis pass to MachineBlockFrequencyInfo. +/// The difference is that with this pass, the block frequencies are not +/// computed when the analysis pass is executed but rather when the BFI result +/// is explicitly requested by the analysis client. +/// +/// This works by checking querying if MBFI is available and otherwise +/// generating MBFI on the fly. In this case the passes required for (LI, DT) +/// are also queried before being computed on the fly. +/// +/// 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 LazyMachineBlockFrequencyInfoPass : public MachineFunctionPass { +private: + /// If generated on the fly this own the instance. + mutable std::unique_ptr<MachineBlockFrequencyInfo> OwnedMBFI; + + /// If generated on the fly this own the instance. + mutable std::unique_ptr<MachineLoopInfo> OwnedMLI; + + /// If generated on the fly this own the instance. + mutable std::unique_ptr<MachineDominatorTree> OwnedMDT; + + /// The function. + MachineFunction *MF = nullptr; + + /// \brief Calculate MBFI and all other analyses that's not available and + /// required by BFI. + MachineBlockFrequencyInfo &calculateIfNotAvailable() const; + +public: + static char ID; + + LazyMachineBlockFrequencyInfoPass(); + + /// \brief Compute and return the block frequencies. + MachineBlockFrequencyInfo &getBFI() { return calculateIfNotAvailable(); } + + /// \brief Compute and return the block frequencies. + const MachineBlockFrequencyInfo &getBFI() const { + return calculateIfNotAvailable(); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + bool runOnMachineFunction(MachineFunction &F) override; + void releaseMemory() override; + void print(raw_ostream &OS, const Module *M) const override; +}; +} +#endif diff --git a/include/llvm/CodeGen/LexicalScopes.h b/include/llvm/CodeGen/LexicalScopes.h index 7d7e48af2a0f..6c35832f963c 100644 --- a/include/llvm/CodeGen/LexicalScopes.h +++ b/include/llvm/CodeGen/LexicalScopes.h @@ -1,4 +1,4 @@ -//===- LexicalScopes.cpp - Collecting lexical scope info -*- C++ -*--------===// +//===- LexicalScopes.cpp - Collecting lexical scope info --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,19 +19,18 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/IR/DebugLoc.h" #include "llvm/IR/DebugInfoMetadata.h" -#include "llvm/IR/ValueHandle.h" +#include <cassert> #include <unordered_map> #include <utility> + namespace llvm { -class MachineInstr; class MachineBasicBlock; class MachineFunction; +class MachineInstr; //===----------------------------------------------------------------------===// /// InsnRange - This is used to track range of instructions with identical @@ -43,13 +42,15 @@ typedef std::pair<const MachineInstr *, const MachineInstr *> InsnRange; /// LexicalScope - This class is used to track scope information. /// class LexicalScope { - public: LexicalScope(LexicalScope *P, const DILocalScope *D, const DILocation *I, bool A) - : Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(A), - LastInsn(nullptr), FirstInsn(nullptr), DFSIn(0), DFSOut(0) { - assert((!D || D->isResolved()) && "Expected resolved node"); + : Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(A) { + assert(D); + assert(D->getSubprogram()->getUnit()->getEmissionKind() != + DICompileUnit::NoDebug && + "Don't build lexical scopes for non-debug locations"); + assert(D->isResolved() && "Expected resolved node"); assert((!I || I->isResolved()) && "Expected resolved node"); if (Parent) Parent->addChild(this); @@ -127,10 +128,10 @@ private: // Contents not owned. SmallVector<InsnRange, 4> Ranges; - const MachineInstr *LastInsn; // Last instruction of this scope. - const MachineInstr *FirstInsn; // First instruction of this scope. - unsigned DFSIn, DFSOut; // In & Out Depth use to determine - // scope nesting. + const MachineInstr *LastInsn = nullptr; // Last instruction of this scope. + const MachineInstr *FirstInsn = nullptr; // First instruction of this scope. + unsigned DFSIn = 0; // In & Out Depth use to determine scope nesting. + unsigned DFSOut = 0; }; //===----------------------------------------------------------------------===// @@ -139,7 +140,7 @@ private: /// class LexicalScopes { public: - LexicalScopes() : MF(nullptr), CurrentFnLexicalScope(nullptr) {} + LexicalScopes() = default; /// initialize - Scan machine function and constuct lexical scope nest, resets /// the instance if necessary. @@ -225,8 +226,7 @@ private: assignInstructionRanges(SmallVectorImpl<InsnRange> &MIRanges, DenseMap<const MachineInstr *, LexicalScope *> &M); -private: - const MachineFunction *MF; + const MachineFunction *MF = nullptr; /// LexicalScopeMap - Tracks the scopes in the current function. // Use an unordered_map to ensure value pointer validity over insertion. @@ -249,9 +249,9 @@ private: /// CurrentFnLexicalScope - Top level scope for the current function. /// - LexicalScope *CurrentFnLexicalScope; + LexicalScope *CurrentFnLexicalScope = nullptr; }; -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_LEXICALSCOPES_H diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h index a86706223261..b792cba4b78a 100644 --- a/include/llvm/CodeGen/LiveInterval.h +++ b/include/llvm/CodeGen/LiveInterval.h @@ -227,15 +227,22 @@ namespace llvm { LiveRange(const LiveRange &Other, BumpPtrAllocator &Allocator) { assert(Other.segmentSet == nullptr && "Copying of LiveRanges with active SegmentSets is not supported"); + assign(Other, Allocator); + } + + /// Copies values numbers and live segments from \p Other into this range. + void assign(const LiveRange &Other, BumpPtrAllocator &Allocator) { + if (this == &Other) + return; + assert(Other.segmentSet == nullptr && + "Copying of LiveRanges with active SegmentSets is not supported"); // Duplicate valnos. - for (const VNInfo *VNI : Other.valnos) { + for (const VNInfo *VNI : Other.valnos) createValueCopy(VNI, Allocator); - } // Now we can copy segments and remap their valnos. - for (const Segment &S : Other.segments) { + for (const Segment &S : Other.segments) segments.push_back(Segment(S.start, S.end, valnos[S.valno->id])); - } } /// advanceTo - Advance the specified iterator to point to the Segment @@ -767,6 +774,19 @@ namespace llvm { const MachineRegisterInfo &MRI, const SlotIndexes &Indexes) const; + /// Refines the subranges to support \p LaneMask. This may only be called + /// for LI.hasSubrange()==true. Subregister ranges are split or created + /// until \p LaneMask can be matched exactly. \p Mod is executed on the + /// matching subranges. + /// + /// Example: + /// Given an interval with subranges with lanemasks L0F00, L00F0 and + /// L000F, refining for mask L0018. Will split the L00F0 lane into + /// L00E0 and L0010 and the L000F lane into L0007 and L0008. The Mod + /// function will be applied to the L0010 and L0008 subranges. + void refineSubRanges(BumpPtrAllocator &Allocator, LaneBitmask LaneMask, + std::function<void(LiveInterval::SubRange&)> Mod); + bool operator<(const LiveInterval& other) const { const SlotIndex &thisIndex = beginIndex(); const SlotIndex &otherIndex = other.beginIndex(); diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index f8dc52566dc0..f5b1f87720ad 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file implements the LiveInterval analysis pass. Given some numbering of -// each the machine instructions (in this implemention depth-first order) an -// interval [i, j) is said to be a live interval for register v if there is no -// instruction with number j' > j such that v is live at j' and there is no -// instruction with number i' < i such that v is live at i'. In this -// implementation intervals can have holes, i.e. an interval might look like -// [1,20), [50,65), [1000,1001). +/// \file This file implements the LiveInterval analysis pass. Given some +/// numbering of each the machine instructions (in this implemention depth-first +/// order) an interval [i, j) is said to be a live interval for register v if +/// there is no instruction with number j' > j such that v is live at j' and +/// there is no instruction with number i' < i such that v is live at i'. In +/// this implementation intervals can have holes, i.e. an interval might look +/// like [1,20), [50,65), [1000,1001). // //===----------------------------------------------------------------------===// @@ -60,20 +60,17 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; LiveRangeCalc *LRCalc; /// Special pool allocator for VNInfo's (LiveInterval val#). - /// VNInfo::Allocator VNInfoAllocator; /// Live interval pointers for all the virtual registers. IndexedMap<LiveInterval*, VirtReg2IndexFunctor> VirtRegIntervals; - /// RegMaskSlots - Sorted list of instructions with register mask operands. - /// Always use the 'r' slot, RegMasks are normal clobbers, not early - /// clobbers. + /// Sorted list of instructions with register mask operands. Always use the + /// 'r' slot, RegMasks are normal clobbers, not early clobbers. SmallVector<SlotIndex, 8> RegMaskSlots; - /// RegMaskBits - This vector is parallel to RegMaskSlots, it holds a - /// pointer to the corresponding register mask. This pointer can be - /// recomputed as: + /// This vector is parallel to RegMaskSlots, it holds a pointer to the + /// corresponding register mask. This pointer can be recomputed as: /// /// MI = Indexes->getInstructionFromIndex(RegMaskSlot[N]); /// unsigned OpNum = findRegMaskOperand(MI); @@ -97,11 +94,11 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; SmallVector<LiveRange*, 0> RegUnitRanges; public: - static char ID; // Pass identification, replacement for typeid + static char ID; LiveIntervals(); ~LiveIntervals() override; - // Calculate the spill weight to assign to a single instruction. + /// Calculate the spill weight to assign to a single instruction. static float getSpillWeight(bool isDef, bool isUse, const MachineBlockFrequencyInfo *MBFI, const MachineInstr &Instr); @@ -121,7 +118,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; return VirtRegIntervals.inBounds(Reg) && VirtRegIntervals[Reg]; } - // Interval creation. + /// Interval creation. LiveInterval &createEmptyInterval(unsigned Reg) { assert(!hasInterval(Reg) && "Interval already exists!"); VirtRegIntervals.grow(Reg); @@ -135,7 +132,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; return LI; } - // Interval removal. + /// Interval removal. void removeInterval(unsigned Reg) { delete VirtRegIntervals[Reg]; VirtRegIntervals[Reg] = nullptr; @@ -163,16 +160,16 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// LiveInterval::removeEmptySubranges() afterwards. void shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg); - /// Extend the live range @p LR to reach all points in @p Indices. The - /// points in the @p Indices array must be jointly dominated by the union - /// of the existing defs in @p LR and points in @p Undefs. + /// Extend the live range \p LR to reach all points in \p Indices. The + /// points in the \p Indices array must be jointly dominated by the union + /// of the existing defs in \p LR and points in \p Undefs. /// /// PHI-defs are added as needed to maintain SSA form. /// - /// If a SlotIndex in @p Indices is the end index of a basic block, @p LR + /// If a SlotIndex in \p Indices is the end index of a basic block, \p LR /// will be extended to be live out of the basic block. - /// If a SlotIndex in @p Indices is jointy dominated only by points in - /// @p Undefs, the live range will not be extended to that point. + /// If a SlotIndex in \p Indices is jointy dominated only by points in + /// \p Undefs, the live range will not be extended to that point. /// /// See also LiveRangeCalc::extend(). void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices, @@ -182,7 +179,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; extendToIndices(LR, Indices, /*Undefs=*/{}); } - /// If @p LR has a live value at @p Kill, prune its live range by removing + /// If \p LR has a live value at \p Kill, prune its live range by removing /// any liveness reachable from Kill. Add live range end points to /// EndPoints such that extendToIndices(LI, EndPoints) will reconstruct the /// value's live range. @@ -192,6 +189,16 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; void pruneValue(LiveRange &LR, SlotIndex Kill, SmallVectorImpl<SlotIndex> *EndPoints); + /// This function should be used. Its intend is to tell you that + /// you are doing something wrong if you call pruveValue directly on a + /// LiveInterval. Indeed, you are supposed to call pruneValue on the main + /// LiveRange and all the LiveRange of the subranges if any. + LLVM_ATTRIBUTE_UNUSED void pruneValue(LiveInterval &, SlotIndex, + SmallVectorImpl<SlotIndex> *) { + llvm_unreachable( + "Use pruneValue on the main LiveRange and on each subrange"); + } + SlotIndexes *getSlotIndexes() const { return Indexes; } @@ -200,8 +207,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; return AA; } - /// isNotInMIMap - returns true if the specified machine instr has been - /// removed or was never entered in the map. + /// Returns true if the specified machine instr has been removed or was + /// never entered in the map. bool isNotInMIMap(const MachineInstr &Instr) const { return !Indexes->hasIndex(Instr); } @@ -270,35 +277,32 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; void getAnalysisUsage(AnalysisUsage &AU) const override; void releaseMemory() override; - /// runOnMachineFunction - pass entry point + /// Pass entry point; Calculates LiveIntervals. bool runOnMachineFunction(MachineFunction&) override; - /// print - Implement the dump method. + /// Implement the dump method. void print(raw_ostream &O, const Module* = nullptr) const override; - /// intervalIsInOneMBB - If LI is confined to a single basic block, return - /// a pointer to that block. If LI is live in to or out of any block, - /// return NULL. + /// If LI is confined to a single basic block, return a pointer to that + /// block. If LI is live in to or out of any block, return NULL. MachineBasicBlock *intervalIsInOneMBB(const LiveInterval &LI) const; /// Returns true if VNI is killed by any PHI-def values in LI. /// This may conservatively return true to avoid expensive computations. bool hasPHIKill(const LiveInterval &LI, const VNInfo *VNI) const; - /// addKillFlags - Add kill flags to any instruction that kills a virtual - /// register. + /// Add kill flags to any instruction that kills a virtual register. void addKillFlags(const VirtRegMap*); - /// handleMove - call this method to notify LiveIntervals that - /// instruction 'mi' has been moved within a basic block. This will update - /// the live intervals for all operands of mi. Moves between basic blocks - /// are not supported. + /// Call this method to notify LiveIntervals that instruction \p MI has been + /// moved within a basic block. This will update the live intervals for all + /// operands of \p MI. Moves between basic blocks are not supported. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. void handleMove(MachineInstr &MI, bool UpdateFlags = false); - /// moveIntoBundle - Update intervals for operands of MI so that they - /// begin/end on the SlotIndex for BundleStart. + /// Update intervals for operands of \p MI so that they begin/end on the + /// SlotIndex for \p BundleStart. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. /// @@ -308,10 +312,9 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; void handleMoveIntoBundle(MachineInstr &MI, MachineInstr &BundleStart, bool UpdateFlags = false); - /// repairIntervalsInRange - Update live intervals for instructions in a - /// range of iterators. It is intended for use after target hooks that may - /// insert or remove instructions, and is only efficient for a small number - /// of instructions. + /// Update live intervals for instructions in a range of iterators. It is + /// intended for use after target hooks that may insert or remove + /// instructions, and is only efficient for a small number of instructions. /// /// OrigRegs is a vector of registers that were originally used by the /// instructions in the range between the two iterators. @@ -334,34 +337,33 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; // LiveIntervalAnalysis maintains a sorted list of instructions with // register mask operands. - /// getRegMaskSlots - Returns a sorted array of slot indices of all - /// instructions with register mask operands. + /// Returns a sorted array of slot indices of all instructions with + /// register mask operands. ArrayRef<SlotIndex> getRegMaskSlots() const { return RegMaskSlots; } - /// getRegMaskSlotsInBlock - Returns a sorted array of slot indices of all - /// instructions with register mask operands in the basic block numbered - /// MBBNum. + /// Returns a sorted array of slot indices of all instructions with register + /// mask operands in the basic block numbered \p MBBNum. ArrayRef<SlotIndex> getRegMaskSlotsInBlock(unsigned MBBNum) const { std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum]; return getRegMaskSlots().slice(P.first, P.second); } - /// getRegMaskBits() - Returns an array of register mask pointers - /// corresponding to getRegMaskSlots(). + /// Returns an array of register mask pointers corresponding to + /// getRegMaskSlots(). ArrayRef<const uint32_t*> getRegMaskBits() const { return RegMaskBits; } - /// getRegMaskBitsInBlock - Returns an array of mask pointers corresponding - /// to getRegMaskSlotsInBlock(MBBNum). + /// Returns an array of mask pointers corresponding to + /// getRegMaskSlotsInBlock(MBBNum). ArrayRef<const uint32_t*> getRegMaskBitsInBlock(unsigned MBBNum) const { std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum]; return getRegMaskBits().slice(P.first, P.second); } - /// checkRegMaskInterference - Test if LI is live across any register mask - /// instructions, and compute a bit mask of physical registers that are not - /// clobbered by any of them. + /// Test if \p LI is live across any register mask instructions, and + /// compute a bit mask of physical registers that are not clobbered by any + /// of them. /// - /// Returns false if LI doesn't cross any register mask instructions. In + /// Returns false if \p LI doesn't cross any register mask instructions. In /// that case, the bit vector is not filled in. bool checkRegMaskInterference(LiveInterval &LI, BitVector &UsableRegs); @@ -377,8 +379,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; // track liveness per register unit to handle aliasing registers more // efficiently. - /// getRegUnit - Return the live range for Unit. - /// It will be computed if it doesn't exist. + /// Return the live range for register unit \p Unit. It will be computed if + /// it doesn't exist. LiveRange &getRegUnit(unsigned Unit) { LiveRange *LR = RegUnitRanges[Unit]; if (!LR) { @@ -390,8 +392,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; return *LR; } - /// getCachedRegUnit - Return the live range for Unit if it has already - /// been computed, or NULL if it hasn't been computed yet. + /// Return the live range for register unit \p Unit if it has already been + /// computed, or nullptr if it hasn't been computed yet. LiveRange *getCachedRegUnit(unsigned Unit) { return RegUnitRanges[Unit]; } @@ -400,7 +402,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; return RegUnitRanges[Unit]; } - /// removeRegUnit - Remove computed live range for Unit. Subsequent uses + /// Remove computed live range for register unit \p Unit. Subsequent uses /// should rely on on-demand recomputation. void removeRegUnit(unsigned Unit) { delete RegUnitRanges[Unit]; @@ -408,12 +410,12 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; } /// Remove value numbers and related live segments starting at position - /// @p Pos that are part of any liverange of physical register @p Reg or one + /// \p Pos that are part of any liverange of physical register \p Reg or one /// of its subregisters. void removePhysRegDefAt(unsigned Reg, SlotIndex Pos); - /// Remove value number and related live segments of @p LI and its subranges - /// that start at position @p Pos. + /// Remove value number and related live segments of \p LI and its subranges + /// that start at position \p Pos. void removeVRegDefAt(LiveInterval &LI, SlotIndex Pos); /// Split separate components in LiveInterval \p LI into separate intervals. @@ -432,10 +434,10 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// Compute RegMaskSlots and RegMaskBits. void computeRegMasks(); - /// Walk the values in @p LI and check for dead values: + /// Walk the values in \p LI and check for dead values: /// - Dead PHIDef values are marked as unused. /// - Dead operands are marked as such. - /// - Completely dead machine instructions are added to the @p dead vector + /// - Completely dead machine instructions are added to the \p dead vector /// if it is not nullptr. /// Returns true if any PHI value numbers have been removed which may /// have separated the interval into multiple connected components. @@ -453,8 +455,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs; /// Helper function for repairIntervalsInRange(), walks backwards and - /// creates/modifies live segments in @p LR to match the operands found. - /// Only full operands or operands with subregisters matching @p LaneMask + /// creates/modifies live segments in \p LR to match the operands found. + /// Only full operands or operands with subregisters matching \p LaneMask /// are considered. void repairOldRegInRange(MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, diff --git a/include/llvm/CodeGen/LiveIntervalUnion.h b/include/llvm/CodeGen/LiveIntervalUnion.h index f0f1637dc92d..57e3deb038af 100644 --- a/include/llvm/CodeGen/LiveIntervalUnion.h +++ b/include/llvm/CodeGen/LiveIntervalUnion.h @@ -1,4 +1,4 @@ -//===-- LiveIntervalUnion.h - Live interval union data struct --*- C++ -*--===// +//===- LiveIntervalUnion.h - Live interval union data struct ---*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -18,7 +18,11 @@ #define LLVM_CODEGEN_LIVEINTERVALUNION_H #include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/LiveInterval.h" +#include "llvm/CodeGen/SlotIndexes.h" +#include <cassert> +#include <limits> namespace llvm { @@ -30,13 +34,6 @@ template <unsigned Element> class SparseBitVector; typedef SparseBitVector<128> LiveVirtRegBitSet; #endif -/// Compare a live virtual register segment to a LiveIntervalUnion segment. -inline bool -overlap(const LiveInterval::Segment &VRSeg, - const IntervalMap<SlotIndex, LiveInterval*>::const_iterator &LUSeg) { - return VRSeg.start < LUSeg.stop() && LUSeg.start() < VRSeg.end; -} - /// Union of live intervals that are strong candidates for coalescing into a /// single register (either physical or virtual depending on the context). We /// expect the constituent live intervals to be disjoint, although we may @@ -53,29 +50,34 @@ public: // to reach the current segment's containing virtual register. typedef LiveSegments::iterator SegmentIter; + /// Const version of SegmentIter. + typedef LiveSegments::const_iterator ConstSegmentIter; + // LiveIntervalUnions share an external allocator. typedef LiveSegments::Allocator Allocator; - class Query; - private: - unsigned Tag; // unique tag for current contents. + unsigned Tag = 0; // unique tag for current contents. LiveSegments Segments; // union of virtual reg segments public: - explicit LiveIntervalUnion(Allocator &a) : Tag(0), Segments(a) {} + explicit LiveIntervalUnion(Allocator &a) : Segments(a) {} // Iterate over all segments in the union of live virtual registers ordered // by their starting position. SegmentIter begin() { return Segments.begin(); } SegmentIter end() { return Segments.end(); } SegmentIter find(SlotIndex x) { return Segments.find(x); } + ConstSegmentIter begin() const { return Segments.begin(); } + ConstSegmentIter end() const { return Segments.end(); } + ConstSegmentIter find(SlotIndex x) const { return Segments.find(x); } + bool empty() const { return Segments.empty(); } SlotIndex startIndex() const { return Segments.start(); } // Provide public access to the underlying map to allow overlap iteration. typedef LiveSegments Map; - const Map &getMap() { return Segments; } + const Map &getMap() const { return Segments; } /// getTag - Return an opaque tag representing the current state of the union. unsigned getTag() const { return Tag; } @@ -85,15 +87,9 @@ public: // Add a live virtual register to this union and merge its segments. void unify(LiveInterval &VirtReg, const LiveRange &Range); - void unify(LiveInterval &VirtReg) { - unify(VirtReg, VirtReg); - } // Remove a live virtual register's segments from this union. void extract(LiveInterval &VirtReg, const LiveRange &Range); - void extract(LiveInterval &VirtReg) { - extract(VirtReg, VirtReg); - } // Remove all inserted virtual registers. void clear() { Segments.clear(); ++Tag; } @@ -109,52 +105,42 @@ public: /// Query interferences between a single live virtual register and a live /// interval union. class Query { - LiveIntervalUnion *LiveUnion; - LiveInterval *VirtReg; - LiveInterval::iterator VirtRegI; // current position in VirtReg - SegmentIter LiveUnionI; // current position in LiveUnion + const LiveIntervalUnion *LiveUnion = nullptr; + const LiveRange *LR = nullptr; + LiveRange::const_iterator LRI; ///< current position in LR + ConstSegmentIter LiveUnionI; ///< current position in LiveUnion SmallVector<LiveInterval*,4> InterferingVRegs; - bool CheckedFirstInterference; - bool SeenAllInterferences; - bool SeenUnspillableVReg; - unsigned Tag, UserTag; - - public: - Query(): LiveUnion(), VirtReg(), Tag(0), UserTag(0) {} - - Query(LiveInterval *VReg, LiveIntervalUnion *LIU): - LiveUnion(LIU), VirtReg(VReg), CheckedFirstInterference(false), - SeenAllInterferences(false), SeenUnspillableVReg(false) - {} - - void clear() { - LiveUnion = nullptr; - VirtReg = nullptr; + bool CheckedFirstInterference = false; + bool SeenAllInterferences = false; + unsigned Tag = 0; + unsigned UserTag = 0; + + void reset(unsigned NewUserTag, const LiveRange &NewLR, + const LiveIntervalUnion &NewLiveUnion) { + LiveUnion = &NewLiveUnion; + LR = &NewLR; InterferingVRegs.clear(); CheckedFirstInterference = false; SeenAllInterferences = false; - SeenUnspillableVReg = false; - Tag = 0; - UserTag = 0; + Tag = NewLiveUnion.getTag(); + UserTag = NewUserTag; } - void init(unsigned UTag, LiveInterval *VReg, LiveIntervalUnion *LIU) { - assert(VReg && LIU && "Invalid arguments"); - if (UserTag == UTag && VirtReg == VReg && - LiveUnion == LIU && !LIU->changedSince(Tag)) { + public: + Query() = default; + Query(const LiveRange &LR, const LiveIntervalUnion &LIU): + LiveUnion(&LIU), LR(&LR) {} + Query(const Query &) = delete; + Query &operator=(const Query &) = delete; + + void init(unsigned NewUserTag, const LiveRange &NewLR, + const LiveIntervalUnion &NewLiveUnion) { + if (UserTag == NewUserTag && LR == &NewLR && LiveUnion == &NewLiveUnion && + !NewLiveUnion.changedSince(Tag)) { // Retain cached results, e.g. firstInterference. return; } - clear(); - LiveUnion = LIU; - VirtReg = VReg; - Tag = LIU->getTag(); - UserTag = UTag; - } - - LiveInterval &virtReg() const { - assert(VirtReg && "uninitialized"); - return *VirtReg; + reset(NewUserTag, NewLR, NewLiveUnion); } // Does this live virtual register interfere with the union? @@ -162,7 +148,8 @@ public: // Count the virtual registers in this union that interfere with this // query's live virtual register, up to maxInterferingRegs. - unsigned collectInterferingVRegs(unsigned MaxInterferingRegs = UINT_MAX); + unsigned collectInterferingVRegs( + unsigned MaxInterferingRegs = std::numeric_limits<unsigned>::max()); // Was this virtual register visited during collectInterferingVRegs? bool isSeenInterference(LiveInterval *VReg) const; @@ -170,25 +157,19 @@ public: // Did collectInterferingVRegs collect all interferences? bool seenAllInterferences() const { return SeenAllInterferences; } - // Did collectInterferingVRegs encounter an unspillable vreg? - bool seenUnspillableVReg() const { return SeenUnspillableVReg; } - // Vector generated by collectInterferingVRegs. const SmallVectorImpl<LiveInterval*> &interferingVRegs() const { return InterferingVRegs; } - - private: - Query(const Query&) = delete; - void operator=(const Query&) = delete; }; // Array of LiveIntervalUnions. class Array { - unsigned Size; - LiveIntervalUnion *LIUs; + unsigned Size = 0; + LiveIntervalUnion *LIUs = nullptr; + public: - Array() : Size(0), LIUs(nullptr) {} + Array() = default; ~Array() { clear(); } // Initialize the array to have Size entries. @@ -213,4 +194,4 @@ public: } // end namespace llvm -#endif // !defined(LLVM_CODEGEN_LIVEINTERVALUNION_H) +#endif // LLVM_CODEGEN_LIVEINTERVALUNION_H diff --git a/include/llvm/CodeGen/LiveRegMatrix.h b/include/llvm/CodeGen/LiveRegMatrix.h index e169058ca563..fa6827f6b1f9 100644 --- a/include/llvm/CodeGen/LiveRegMatrix.h +++ b/include/llvm/CodeGen/LiveRegMatrix.h @@ -1,4 +1,4 @@ -//===-- LiveRegMatrix.h - Track register interference ---------*- C++ -*---===// +//===- LiveRegMatrix.h - Track register interference ----------*- C++ -*---===// // // The LLVM Compiler Infrastructure // @@ -27,11 +27,14 @@ #include "llvm/ADT/BitVector.h" #include "llvm/CodeGen/LiveIntervalUnion.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include <memory> namespace llvm { +class AnalysisUsage; class LiveInterval; -class LiveIntervalAnalysis; +class LiveIntervals; +class MachineFunction; class TargetRegisterInfo; class VirtRegMap; @@ -41,7 +44,7 @@ class LiveRegMatrix : public MachineFunctionPass { VirtRegMap *VRM; // UserTag changes whenever virtual registers have been modified. - unsigned UserTag; + unsigned UserTag = 0; // The matrix is represented as a LiveIntervalUnion per register unit. LiveIntervalUnion::Allocator LIUAlloc; @@ -51,16 +54,18 @@ class LiveRegMatrix : public MachineFunctionPass { std::unique_ptr<LiveIntervalUnion::Query[]> Queries; // Cached register mask interference info. - unsigned RegMaskTag; - unsigned RegMaskVirtReg; + unsigned RegMaskTag = 0; + unsigned RegMaskVirtReg = 0; BitVector RegMaskUsable; // MachineFunctionPass boilerplate. - void getAnalysisUsage(AnalysisUsage&) const override; - bool runOnMachineFunction(MachineFunction&) override; + void getAnalysisUsage(AnalysisUsage &) const override; + bool runOnMachineFunction(MachineFunction &) override; void releaseMemory() override; + public: static char ID; + LiveRegMatrix(); //===--------------------------------------------------------------------===// @@ -136,7 +141,7 @@ public: /// Use MCRegUnitIterator to enumerate all regunits in the desired PhysReg. /// This returns a reference to an internal Query data structure that is only /// valid until the next query() call. - LiveIntervalUnion::Query &query(LiveInterval &VirtReg, unsigned RegUnit); + LiveIntervalUnion::Query &query(const LiveRange &LR, unsigned RegUnit); /// Directly access the live interval unions per regunit. /// This returns an array indexed by the regunit number. diff --git a/include/llvm/CodeGen/LiveRegUnits.h b/include/llvm/CodeGen/LiveRegUnits.h new file mode 100644 index 000000000000..5de76c8b87bf --- /dev/null +++ b/include/llvm/CodeGen/LiveRegUnits.h @@ -0,0 +1,128 @@ +//===- llvm/CodeGen/LiveRegUnits.h - Register Unit Set ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// A set of register units. It is intended for register liveness tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_LIVEREGUNITS_H +#define LLVM_CODEGEN_LIVEREGUNITS_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/MC/LaneBitmask.h" +#include "llvm/MC/MCRegisterInfo.h" +#include <cstdint> + +namespace llvm { + +class MachineInstr; +class MachineBasicBlock; + +/// A set of register units used to track register liveness. +class LiveRegUnits { + const TargetRegisterInfo *TRI = nullptr; + BitVector Units; + +public: + /// Constructs a new empty LiveRegUnits set. + LiveRegUnits() = default; + + /// Constructs and initialize an empty LiveRegUnits set. + LiveRegUnits(const TargetRegisterInfo &TRI) { + init(TRI); + } + + /// Initialize and clear the set. + void init(const TargetRegisterInfo &TRI) { + this->TRI = &TRI; + Units.reset(); + Units.resize(TRI.getNumRegUnits()); + } + + /// Clears the set. + void clear() { Units.reset(); } + + /// Returns true if the set is empty. + bool empty() const { return Units.empty(); } + + /// Adds register units covered by physical register \p Reg. + void addReg(unsigned Reg) { + for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) + Units.set(*Unit); + } + + /// \brief Adds register units covered by physical register \p Reg that are + /// part of the lanemask \p Mask. + void addRegMasked(unsigned Reg, LaneBitmask Mask) { + for (MCRegUnitMaskIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) { + LaneBitmask UnitMask = (*Unit).second; + if (UnitMask.none() || (UnitMask & Mask).any()) + Units.set((*Unit).first); + } + } + + /// Removes all register units covered by physical register \p Reg. + void removeReg(unsigned Reg) { + for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) + Units.reset(*Unit); + } + + /// Removes register units not preserved by the regmask \p RegMask. + /// The regmask has the same format as the one in the RegMask machine operand. + void removeRegsNotPreserved(const uint32_t *RegMask); + + /// Adds register units not preserved by the regmask \p RegMask. + /// The regmask has the same format as the one in the RegMask machine operand. + void addRegsInMask(const uint32_t *RegMask); + + /// Returns true if no part of physical register \p Reg is live. + bool available(unsigned Reg) const { + for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) { + if (Units.test(*Unit)) + return false; + } + return true; + } + + /// Updates liveness when stepping backwards over the instruction \p MI. + void stepBackward(const MachineInstr &MI); + + /// Mark all register units live during instruction \p MI. + /// This can be used to accumulate live/unoccupied registers over a range of + /// instructions. + void accumulateBackward(const MachineInstr &MI); + + /// Adds registers living out of 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); + + /// Adds registers living into block \p MBB. + void addLiveIns(const MachineBasicBlock &MBB); + + /// Adds all register units marked in the bitvector \p RegUnits. + void addUnits(const BitVector &RegUnits) { + Units |= RegUnits; + } + /// Removes all register units marked in the bitvector \p RegUnits. + void removeUnits(const BitVector &RegUnits) { + Units.reset(RegUnits); + } + /// Return the internal bitvector representation of the set. + const BitVector &getBitVector() const { + return Units; + } +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_LIVEREGUNITS_H diff --git a/include/llvm/CodeGen/LowLevelType.h b/include/llvm/CodeGen/LowLevelType.h index b8885c3a95fd..a3c5c9329f53 100644 --- a/include/llvm/CodeGen/LowLevelType.h +++ b/include/llvm/CodeGen/LowLevelType.h @@ -1,4 +1,4 @@ -//== llvm/CodeGen/GlobalISel/LowLevelType.h -------------------- -*- C++ -*-==// +//== llvm/CodeGen/LowLevelType.h ------------------------------- -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -10,197 +10,23 @@ /// Implement a low-level type suitable for MachineInstr level instruction /// selection. /// -/// For a type attached to a MachineInstr, we only care about 2 details: total -/// size and the number of vector lanes (if any). Accordingly, there are 4 -/// possible valid type-kinds: -/// -/// * `sN` for scalars and aggregates -/// * `<N x sM>` for vectors, which must have at least 2 elements. -/// * `pN` for pointers -/// -/// Other information required for correct selection is expected to be carried -/// by the opcode, or non-type flags. For example the distinction between G_ADD -/// and G_FADD for int/float or fast-math flags. +/// This provides the CodeGen aspects of LowLevelType, such as Type conversion. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H -#define LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H +#ifndef LLVM_CODEGEN_LOWLEVELTYPE_H +#define LLVM_CODEGEN_LOWLEVELTYPE_H -#include <cassert> -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/LowLevelTypeImpl.h" namespace llvm { class DataLayout; -class LLVMContext; class Type; -class raw_ostream; - -class LLT { -public: - enum TypeKind : uint16_t { - Invalid, - Scalar, - Pointer, - Vector, - }; - - /// Get a low-level scalar or aggregate "bag of bits". - static LLT scalar(unsigned SizeInBits) { - assert(SizeInBits > 0 && "invalid scalar size"); - return LLT{Scalar, 1, SizeInBits}; - } - - /// Get a low-level pointer in the given address space (defaulting to 0). - static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) { - return LLT{Pointer, AddressSpace, SizeInBits}; - } - - /// Get a low-level vector of some number of elements and element width. - /// \p NumElements must be at least 2. - static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { - assert(NumElements > 1 && "invalid number of vector elements"); - return LLT{Vector, NumElements, ScalarSizeInBits}; - } - - /// Get a low-level vector of some number of elements and element type. - static LLT vector(uint16_t NumElements, LLT ScalarTy) { - assert(NumElements > 1 && "invalid number of vector elements"); - assert(ScalarTy.isScalar() && "invalid vector element type"); - return LLT{Vector, NumElements, ScalarTy.getSizeInBits()}; - } - - explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits) - : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) { - assert((Kind != Vector || ElementsOrAddrSpace > 1) && - "invalid number of vector elements"); - } - - explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {} - - /// Construct a low-level type based on an LLVM type. - explicit LLT(Type &Ty, const DataLayout &DL); - - explicit LLT(MVT VT); - - bool isValid() const { return Kind != Invalid; } - - bool isScalar() const { return Kind == Scalar; } - - bool isPointer() const { return Kind == Pointer; } - - bool isVector() const { return Kind == Vector; } - - /// Returns the number of elements in a vector LLT. Must only be called on - /// vector types. - uint16_t getNumElements() const { - assert(isVector() && "cannot get number of elements on scalar/aggregate"); - return ElementsOrAddrSpace; - } - - /// Returns the total size of the type. Must only be called on sized types. - unsigned getSizeInBits() const { - if (isPointer() || isScalar()) - return SizeInBits; - return SizeInBits * ElementsOrAddrSpace; - } - - unsigned getScalarSizeInBits() const { - return SizeInBits; - } - - unsigned getAddressSpace() const { - assert(isPointer() && "cannot get address space of non-pointer type"); - return ElementsOrAddrSpace; - } - - /// Returns the vector's element type. Only valid for vector types. - LLT getElementType() const { - assert(isVector() && "cannot get element type of scalar/aggregate"); - return scalar(SizeInBits); - } - - /// Get a low-level type with half the size of the original, by halving the - /// size of the scalar type involved. For example `s32` will become `s16`, - /// `<2 x s32>` will become `<2 x s16>`. - LLT halfScalarSize() const { - assert(!isPointer() && getScalarSizeInBits() > 1 && - getScalarSizeInBits() % 2 == 0 && "cannot half size of this type"); - return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2}; - } - - /// Get a low-level type with twice the size of the original, by doubling the - /// size of the scalar type involved. For example `s32` will become `s64`, - /// `<2 x s32>` will become `<2 x s64>`. - LLT doubleScalarSize() const { - assert(!isPointer() && "cannot change size of this type"); - return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2}; - } - - /// Get a low-level type with half the size of the original, by halving the - /// number of vector elements of the scalar type involved. The source must be - /// a vector type with an even number of elements. For example `<4 x s32>` - /// will become `<2 x s32>`, `<2 x s32>` will become `s32`. - LLT halfElements() const { - assert(isVector() && ElementsOrAddrSpace % 2 == 0 && - "cannot half odd vector"); - if (ElementsOrAddrSpace == 2) - return scalar(SizeInBits); - - return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2), - SizeInBits}; - } - - /// Get a low-level type with twice the size of the original, by doubling the - /// number of vector elements of the scalar type involved. The source must be - /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling - /// the number of elements in sN produces <2 x sN>. - LLT doubleElements() const { - assert(!isPointer() && "cannot double elements in pointer"); - return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2), - SizeInBits}; - } - - void print(raw_ostream &OS) const; - - bool operator==(const LLT &RHS) const { - return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits && - ElementsOrAddrSpace == RHS.ElementsOrAddrSpace; - } - - bool operator!=(const LLT &RHS) const { return !(*this == RHS); } - - friend struct DenseMapInfo<LLT>; -private: - unsigned SizeInBits; - uint16_t ElementsOrAddrSpace; - TypeKind Kind; -}; - -inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { - Ty.print(OS); - return OS; -} -template<> struct DenseMapInfo<LLT> { - static inline LLT getEmptyKey() { - return LLT{LLT::Invalid, 0, -1u}; - } - static inline LLT getTombstoneKey() { - return LLT{LLT::Invalid, 0, -2u}; - } - static inline unsigned getHashValue(const LLT &Ty) { - uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) | - ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind; - return DenseMapInfo<uint64_t>::getHashValue(Val); - } - static bool isEqual(const LLT &LHS, const LLT &RHS) { - return LHS == RHS; - } -}; +/// Construct a low-level type based on an LLVM type. +LLT getLLTForType(Type &Ty, const DataLayout &DL); } -#endif +#endif // LLVM_CODEGEN_LOWLEVELTYPE_H diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index 778f72c06e65..38cf8aa165a4 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -55,7 +55,7 @@ template <> struct ScalarTraits<StringValue> { struct FlowStringValue : StringValue { FlowStringValue() {} - FlowStringValue(std::string Value) : StringValue(Value) {} + FlowStringValue(std::string Value) : StringValue(std::move(Value)) {} }; template <> struct ScalarTraits<FlowStringValue> { @@ -381,6 +381,7 @@ struct MachineFunction { StringRef Name; unsigned Alignment = 0; bool ExposesReturnsTwice = false; + bool NoVRegs; // GISel MachineFunctionProperties. bool Legalized = false; bool RegBankSelected = false; @@ -405,6 +406,7 @@ template <> struct MappingTraits<MachineFunction> { YamlIO.mapRequired("name", MF.Name); YamlIO.mapOptional("alignment", MF.Alignment); YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice); + YamlIO.mapOptional("noVRegs", MF.NoVRegs); YamlIO.mapOptional("legalized", MF.Legalized); YamlIO.mapOptional("regBankSelected", MF.RegBankSelected); YamlIO.mapOptional("selected", MF.Selected); diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index f3f5e324d76a..18d40564856d 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -128,7 +128,7 @@ public: /// to an LLVM basic block. const BasicBlock *getBasicBlock() const { return BB; } - /// Return the name of the corresponding LLVM basic block, or "(null)". + /// Return the name of the corresponding LLVM basic block, or an empty string. StringRef getName() const; /// Return a formatted string to identify this block and its parent function. @@ -455,10 +455,19 @@ public: /// other block. bool isLayoutSuccessor(const MachineBasicBlock *MBB) const; - /// Return true if the block can implicitly transfer control to the block - /// after it by falling off the end of it. This should return false if it can - /// reach the block after it, but it uses an explicit branch to do so (e.g., a - /// table jump). True is a conservative answer. + + /// Return the fallthrough block if the block can implicitly + /// transfer control to the block after it by falling off the end of + /// it. This should return null if it can reach the block after + /// it, but it uses an explicit branch to do so (e.g., a table + /// jump). Non-null return is a conservative answer. + MachineBasicBlock *getFallThrough(); + + /// Return true if the block can implicitly transfer control to the + /// block after it by falling off the end of it. This should return + /// false if it can reach the block after it, but it uses an + /// explicit branch to do so (e.g., a table jump). True is a + /// conservative answer. bool canFallThrough(); /// Returns a pointer to the first instruction in this block that is not a @@ -664,6 +673,10 @@ public: return findDebugLoc(MBBI.getInstrIterator()); } + /// Find and return the merged DebugLoc of the branch instructions of the + /// block. Return UnknownLoc if there is none. + DebugLoc findBranchDebugLoc(); + /// Possible outcome of a register liveness query to computeRegisterLiveness() enum LivenessQueryResult { LQR_Live, ///< Register is known to be (at least partially) live. diff --git a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h index bfa5bf6c2845..cd1c204981ed 100644 --- a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h +++ b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h @@ -23,6 +23,7 @@ namespace llvm { class MachineBasicBlock; class MachineBranchProbabilityInfo; +class MachineLoopInfo; template <class BlockT> class BlockFrequencyInfoImpl; /// MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation @@ -42,6 +43,11 @@ public: bool runOnMachineFunction(MachineFunction &F) override; + /// calculate - compute block frequency info for the given function. + void calculate(const MachineFunction &F, + const MachineBranchProbabilityInfo &MBPI, + const MachineLoopInfo &MLI); + void releaseMemory() override; /// getblockFreq - Return block frequency. Return 0 if we don't have the @@ -56,7 +62,7 @@ public: const MachineFunction *getFunction() const; const MachineBranchProbabilityInfo *getMBPI() const; - void view() const; + void view(const Twine &Name, bool isSimple = true) const; // Print the block frequency Freq to OS using the current functions entry // frequency to convert freq into a relative decimal form. diff --git a/include/llvm/CodeGen/MachineDominators.h b/include/llvm/CodeGen/MachineDominators.h index 21ecef587aa5..30b6cfdd1c36 100644 --- a/include/llvm/CodeGen/MachineDominators.h +++ b/include/llvm/CodeGen/MachineDominators.h @@ -21,6 +21,7 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/Support/GenericDomTree.h" #include "llvm/Support/GenericDomTreeConstruction.h" +#include <memory> namespace llvm { @@ -60,7 +61,7 @@ class MachineDominatorTree : public MachineFunctionPass { mutable SmallSet<MachineBasicBlock *, 32> NewBBs; /// The DominatorTreeBase that is used to compute a normal dominator tree - DominatorTreeBase<MachineBasicBlock>* DT; + std::unique_ptr<DominatorTreeBase<MachineBasicBlock>> DT; /// \brief Apply all the recorded critical edges to the DT. /// This updates the underlying DT information in a way that uses @@ -74,9 +75,9 @@ public: MachineDominatorTree(); - ~MachineDominatorTree() override; - DominatorTreeBase<MachineBasicBlock> &getBase() { + if (!DT) + DT.reset(new DominatorTreeBase<MachineBasicBlock>(false)); applySplitCriticalEdges(); return *DT; } @@ -244,21 +245,6 @@ public: 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 diff --git a/include/llvm/CodeGen/MachineFrameInfo.h b/include/llvm/CodeGen/MachineFrameInfo.h index 4600c2c0f10c..5c9728b0a51e 100644 --- a/include/llvm/CodeGen/MachineFrameInfo.h +++ b/include/llvm/CodeGen/MachineFrameInfo.h @@ -559,8 +559,7 @@ public: return Objects[ObjectIdx+NumFixedObjects].isAliased; } - /// isImmutableObjectIndex - Returns true if the specified index corresponds - /// to an immutable object. + /// Returns true if the specified index corresponds to an immutable object. bool isImmutableObjectIndex(int ObjectIdx) const { // Tail calling functions can clobber their function arguments. if (HasTailCall) @@ -570,6 +569,13 @@ public: return Objects[ObjectIdx+NumFixedObjects].isImmutable; } + /// Marks the immutability of an object. + void setIsImmutableObjectIndex(int ObjectIdx, bool Immutable) { + assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && + "Invalid Object Idx!"); + Objects[ObjectIdx+NumFixedObjects].isImmutable = Immutable; + } + /// Returns true if the specified index corresponds to a spill slot. bool isSpillSlotObjectIndex(int ObjectIdx) const { assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() && diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 0c21b3254631..5859a4e61fdd 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -475,9 +475,8 @@ public: /// getBlockNumbered - MachineBasicBlocks are automatically numbered when they /// are inserted into the machine function. The block number for a machine - /// basic block can be found by using the MBB::getBlockNumber method, this - /// method provides the inverse mapping. - /// + /// basic block can be found by using the MBB::getNumber method, this method + /// provides the inverse mapping. MachineBasicBlock *getBlockNumbered(unsigned N) const { assert(N < MBBNumbering.size() && "Illegal block number"); assert(MBBNumbering[N] && "Block was removed from the machine function!"); diff --git a/include/llvm/CodeGen/MachineFunctionInitializer.h b/include/llvm/CodeGen/MachineFunctionInitializer.h index ff4c29cc014d..c644c9783e2f 100644 --- a/include/llvm/CodeGen/MachineFunctionInitializer.h +++ b/include/llvm/CodeGen/MachineFunctionInitializer.h @@ -1,4 +1,4 @@ -//===- MachineFunctionInitalizer.h - machine function initializer ---------===// +//===- MachineFunctionInitializer.h - machine function initializer ---------===// // // The LLVM Compiler Infrastructure // diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h index bac93e5d3a4c..e7e728c1be28 100644 --- a/include/llvm/CodeGen/MachineInstr.h +++ b/include/llvm/CodeGen/MachineInstr.h @@ -1108,6 +1108,18 @@ public: /// the instruction's location and its intended destination. bool isSafeToMove(AliasAnalysis *AA, bool &SawStore) const; + /// Returns true if this instruction's memory access aliases the memory + /// access of Other. + // + /// Assumes any physical registers used to compute addresses + /// have the same value for both instructions. Returns false if neither + /// instruction writes to memory. + /// + /// @param AA Optional alias analysis, used to compare memory operands. + /// @param Other MachineInstr to check aliasing against. + /// @param UseTBAA Whether to pass TBAA information to alias analysis. + bool mayAlias(AliasAnalysis *AA, MachineInstr &Other, bool UseTBAA); + /// Return true if this instruction may have an ordered /// or volatile memory reference, or if the information describing the memory /// reference is not available. Return false if it is known to have no @@ -1146,14 +1158,21 @@ public: /// instruction to this instruction. void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI); - // - // Debugging support - // - void print(raw_ostream &OS, bool SkipOpers = false, + /// Debugging support + /// @{ + /// Print this MI to \p OS. + /// Only print the defs and the opcode if \p SkipOpers is true. + /// Otherwise, also print operands if \p SkipDebugLoc is true. + /// Otherwise, also print the debug loc, with a terminating newline. + /// \p TII is used to print the opcode name. If it's not present, but the + /// MI is in a function, the opcode will be printed using the function's TII. + void print(raw_ostream &OS, bool SkipOpers = false, bool SkipDebugLoc = false, const TargetInstrInfo *TII = nullptr) const; void print(raw_ostream &OS, ModuleSlotTracker &MST, bool SkipOpers = false, + bool SkipDebugLoc = false, const TargetInstrInfo *TII = nullptr) const; - void dump(const TargetInstrInfo *TII = nullptr) const; + void dump() const; + /// @} //===--------------------------------------------------------------------===// // Accessors used to build up machine instructions. diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 3c8a3626f364..ef4226d30fe3 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -1,4 +1,4 @@ -//===-- CodeGen/MachineInstBuilder.h - Simplify creation of MIs -*- C++ -*-===// +//===- CodeGen/MachineInstrBuilder.h - Simplify creation of MIs --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,9 +19,18 @@ #ifndef LLVM_CODEGEN_MACHINEINSTRBUILDER_H #define LLVM_CODEGEN_MACHINEINSTRBUILDER_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBundle.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstdint> +#include <utility> namespace llvm { @@ -29,6 +38,7 @@ class MCInstrDesc; class MDNode; namespace RegState { + enum { Define = 0x2, Implicit = 0x4, @@ -42,13 +52,15 @@ namespace RegState { ImplicitDefine = Implicit | Define, ImplicitKill = Implicit | Kill }; -} + +} // end namespace RegState class MachineInstrBuilder { - MachineFunction *MF; - MachineInstr *MI; + MachineFunction *MF = nullptr; + MachineInstr *MI = nullptr; + public: - MachineInstrBuilder() : MF(nullptr), MI(nullptr) {} + MachineInstrBuilder() = default; /// Create a MachineInstrBuilder for manipulating an existing instruction. /// F must be the machine function that was used to allocate I. @@ -187,11 +199,18 @@ public: return *this; } - const MachineInstrBuilder &addOperand(const MachineOperand &MO) const { + const MachineInstrBuilder &add(const MachineOperand &MO) const { MI->addOperand(*MF, MO); return *this; } + const MachineInstrBuilder &add(ArrayRef<MachineOperand> MOs) const { + for (const MachineOperand &MO : MOs) { + MI->addOperand(*MF, MO); + } + return *this; + } + const MachineInstrBuilder &addMetadata(const MDNode *MD) const { MI->addOperand(*MF, MachineOperand::CreateMetadata(MD)); assert((MI->isDebugValue() ? static_cast<bool>(MI->getDebugVariable()) @@ -511,6 +530,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_MACHINEINSTRBUILDER_H diff --git a/include/llvm/CodeGen/MachineLoopInfo.h b/include/llvm/CodeGen/MachineLoopInfo.h index dc72ae1810ee..5c814f22f99b 100644 --- a/include/llvm/CodeGen/MachineLoopInfo.h +++ b/include/llvm/CodeGen/MachineLoopInfo.h @@ -60,6 +60,13 @@ public: /// multiple exiting blocks are present. MachineBasicBlock *findLoopControlBlock(); + /// Return the debug location of the start of this loop. + /// This looks for a BB terminating instruction with a known debug + /// 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; + void dump() const; private: diff --git a/include/llvm/CodeGen/MachineModuleInfoImpls.h b/include/llvm/CodeGen/MachineModuleInfoImpls.h index f9fa6999073f..f28a79c5b5cc 100644 --- a/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ b/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -15,7 +15,9 @@ #ifndef LLVM_CODEGEN_MACHINEMODULEINFOIMPLS_H #define LLVM_CODEGEN_MACHINEMODULEINFOIMPLS_H +#include "llvm/CodeGen/ValueTypes.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/Support/Wasm.h" namespace llvm { class MCSymbol; @@ -75,6 +77,33 @@ public: SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } }; +/// MachineModuleInfoWasm - This is a MachineModuleInfoImpl implementation +/// for Wasm targets. +class MachineModuleInfoWasm : public MachineModuleInfoImpl { + /// WebAssembly global variables defined by CodeGen. + std::vector<wasm::Global> Globals; + + /// The WebAssembly global variable which is the stack pointer. + unsigned StackPointerGlobal; + + virtual void anchor(); // Out of line virtual method. +public: + MachineModuleInfoWasm(const MachineModuleInfo &) + : StackPointerGlobal(-1U) {} + + void addGlobal(const wasm::Global &G) { Globals.push_back(G); } + const std::vector<wasm::Global> &getGlobals() const { return Globals; } + + bool hasStackPointerGlobal() const { + return StackPointerGlobal != -1U; + } + unsigned getStackPointerGlobal() const { + assert(hasStackPointerGlobal() && "Stack ptr global hasn't been set"); + return StackPointerGlobal; + } + void setStackPointerGlobal(unsigned Global) { StackPointerGlobal = Global; } +}; + } // end namespace llvm #endif diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index 5df99a6c807e..81b43126adeb 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -65,6 +65,7 @@ public: MO_CFIIndex, ///< MCCFIInstruction index. MO_IntrinsicID, ///< Intrinsic ID for ISel MO_Predicate, ///< Generic predicate for ISel + MO_Placeholder, ///< Placeholder for GlobalISel ComplexPattern result. }; private: @@ -229,7 +230,7 @@ public: void print(raw_ostream &os, ModuleSlotTracker &MST, const TargetRegisterInfo *TRI = nullptr, const TargetIntrinsicInfo *IntrinsicInfo = nullptr) const; - LLVM_DUMP_METHOD void dump() const; + void dump() const; //===--------------------------------------------------------------------===// // Accessors that tell you what kind of MachineOperand you're looking at. @@ -355,7 +356,7 @@ public: void setReg(unsigned Reg); void setSubReg(unsigned subReg) { - assert(isReg() && "Wrong MachineOperand accessor"); + assert(isReg() && "Wrong MachineOperand mutator"); SubReg_TargetFlags = subReg; assert(SubReg_TargetFlags == subReg && "SubReg out of range"); } @@ -378,38 +379,38 @@ public: void setIsDef(bool Val = true); void setImplicit(bool Val = true) { - assert(isReg() && "Wrong MachineOperand accessor"); + assert(isReg() && "Wrong MachineOperand mutator"); IsImp = Val; } void setIsKill(bool Val = true) { - assert(isReg() && !IsDef && "Wrong MachineOperand accessor"); + assert(isReg() && !IsDef && "Wrong MachineOperand mutator"); assert((!Val || !isDebug()) && "Marking a debug operation as kill"); IsKill = Val; } void setIsDead(bool Val = true) { - assert(isReg() && IsDef && "Wrong MachineOperand accessor"); + assert(isReg() && IsDef && "Wrong MachineOperand mutator"); IsDead = Val; } void setIsUndef(bool Val = true) { - assert(isReg() && "Wrong MachineOperand accessor"); + assert(isReg() && "Wrong MachineOperand mutator"); IsUndef = Val; } void setIsInternalRead(bool Val = true) { - assert(isReg() && "Wrong MachineOperand accessor"); + assert(isReg() && "Wrong MachineOperand mutator"); IsInternalRead = Val; } void setIsEarlyClobber(bool Val = true) { - assert(isReg() && IsDef && "Wrong MachineOperand accessor"); + assert(isReg() && IsDef && "Wrong MachineOperand mutator"); IsEarlyClobber = Val; } void setIsDebug(bool Val = true) { - assert(isReg() && !IsDef && "Wrong MachineOperand accessor"); + assert(isReg() && !IsDef && "Wrong MachineOperand mutator"); IsDebug = Val; } @@ -538,19 +539,19 @@ public: void setOffset(int64_t Offset) { assert((isGlobal() || isSymbol() || isMCSymbol() || isCPI() || isTargetIndex() || isBlockAddress()) && - "Wrong MachineOperand accessor"); + "Wrong MachineOperand mutator"); SmallContents.OffsetLo = unsigned(Offset); Contents.OffsetedInfo.OffsetHi = int(Offset >> 32); } void setIndex(int Idx) { assert((isFI() || isCPI() || isTargetIndex() || isJTI()) && - "Wrong MachineOperand accessor"); + "Wrong MachineOperand mutator"); Contents.OffsetedInfo.Val.Index = Idx; } void setMBB(MachineBasicBlock *MBB) { - assert(isMBB() && "Wrong MachineOperand accessor"); + assert(isMBB() && "Wrong MachineOperand mutator"); Contents.MBB = MBB; } @@ -767,6 +768,11 @@ public: return Op; } + static MachineOperand CreatePlaceholder() { + MachineOperand Op(MachineOperand::MO_Placeholder); + return Op; + } + friend class MachineInstr; friend class MachineRegisterInfo; private: diff --git a/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h b/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h new file mode 100644 index 000000000000..da8fdcdf5a33 --- /dev/null +++ b/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h @@ -0,0 +1,203 @@ +///===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*----===// +/// +/// The LLVM Compiler Infrastructure +/// +/// This file is distributed under the University of Illinois Open Source +/// License. See LICENSE.TXT for details. +/// +///===---------------------------------------------------------------------===// +/// \file +/// Optimization diagnostic interfaces for machine passes. It's packaged as an +/// analysis pass so that by using this service passes become dependent on MBFI +/// as well. MBFI is used to compute the "hotness" of the diagnostic message. +/// +///===---------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H +#define LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H + +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { +class MachineBasicBlock; +class MachineBlockFrequencyInfo; +class MachineInstr; + +/// \brief Common features for diagnostics dealing with optimization remarks +/// that are used by machine passes. +class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase { +public: + DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName, + StringRef RemarkName, + const DiagnosticLocation &Loc, + const MachineBasicBlock *MBB) + : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName, + *MBB->getParent()->getFunction(), Loc), + MBB(MBB) {} + + /// MI-specific kinds of diagnostic Arguments. + struct MachineArgument : public DiagnosticInfoOptimizationBase::Argument { + /// Print an entire MachineInstr. + MachineArgument(StringRef Key, const MachineInstr &MI); + }; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() >= DK_FirstMachineRemark && + DI->getKind() <= DK_LastMachineRemark; + } + + const MachineBasicBlock *getBlock() const { return MBB; } + +private: + const MachineBasicBlock *MBB; +}; + +/// Diagnostic information for applied optimization remarks. +class MachineOptimizationRemark : public DiagnosticInfoMIROptimization { +public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass=, then the diagnostic will + /// be emitted. \p RemarkName is a textual identifier for the remark. \p + /// Loc is the debug location and \p MBB is the block that the optimization + /// operates in. + MachineOptimizationRemark(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const MachineBasicBlock *MBB) + : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName, + RemarkName, Loc, MBB) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_MachineOptimizationRemark; + } + + /// \see DiagnosticInfoOptimizationBase::isEnabled. + bool isEnabled() const override { + return OptimizationRemark::isEnabled(getPassName()); + } +}; + +/// Diagnostic information for missed-optimization remarks. +class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization { +public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass-missed=, then the + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark. \p Loc is the debug location and \p MBB is the block that the + /// optimization operates in. + MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const MachineBasicBlock *MBB) + : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed, + PassName, RemarkName, Loc, MBB) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_MachineOptimizationRemarkMissed; + } + + /// \see DiagnosticInfoOptimizationBase::isEnabled. + bool isEnabled() const override { + return OptimizationRemarkMissed::isEnabled(getPassName()); + } +}; + +/// Diagnostic information for optimization analysis remarks. +class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization { +public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass-analysis=, then the + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark. \p Loc is the debug location and \p MBB is the block that the + /// optimization operates in. + MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const MachineBasicBlock *MBB) + : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, + PassName, RemarkName, Loc, MBB) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_MachineOptimizationRemarkAnalysis; + } + + /// \see DiagnosticInfoOptimizationBase::isEnabled. + bool isEnabled() const override { + return OptimizationRemarkAnalysis::isEnabled(getPassName()); + } +}; + +/// Extend llvm::ore:: with MI-specific helper names. +namespace ore { +using MNV = DiagnosticInfoMIROptimization::MachineArgument; +} + +/// The optimization diagnostic interface. +/// +/// It allows reporting when optimizations are performed and when they are not +/// along with the reasons for it. Hotness information of the corresponding +/// code region can be included in the remark if DiagnosticHotnessRequested is +/// enabled in the LLVM context. +class MachineOptimizationRemarkEmitter { +public: + MachineOptimizationRemarkEmitter(MachineFunction &MF, + MachineBlockFrequencyInfo *MBFI) + : MF(MF), MBFI(MBFI) {} + + /// Emit an optimization remark. + void emit(DiagnosticInfoOptimizationBase &OptDiag); + + /// \brief Whether we allow for extra compile-time budget to perform more + /// analysis to be more informative. + /// + /// This is useful to enable additional missed optimizations to be reported + /// that are normally too noisy. In this mode, we can use the extra analysis + /// (1) to filter trivial false positives or (2) to provide more context so + /// that non-trivial false positives can be quickly detected by the user. + bool allowExtraAnalysis() const { + // For now, only allow this with -fsave-optimization-record since the -Rpass + // options are handled in the front-end. + return MF.getFunction()->getContext().getDiagnosticsOutputFile(); + } + +private: + MachineFunction &MF; + + /// MBFI is only set if hotness is requested. + MachineBlockFrequencyInfo *MBFI; + + /// Compute hotness from IR value (currently assumed to be a block) if PGO is + /// available. + Optional<uint64_t> computeHotness(const MachineBasicBlock &MBB); + + /// Similar but use value from \p OptDiag and update hotness there. + void computeHotness(DiagnosticInfoMIROptimization &Remark); + + /// \brief Only allow verbose messages if we know we're filtering by hotness + /// (BFI is only set in this case). + bool shouldEmitVerbose() { return MBFI != nullptr; } +}; + +/// The analysis pass +/// +/// Note that this pass shouldn't generally be marked as preserved by other +/// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI +/// could be freed. +class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass { + std::unique_ptr<MachineOptimizationRemarkEmitter> ORE; + +public: + MachineOptimizationRemarkEmitterPass(); + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + MachineOptimizationRemarkEmitter &getORE() { + assert(ORE && "pass not run yet"); + return *ORE; + } + + static char ID; +}; +} + +#endif diff --git a/include/llvm/CodeGen/MachineRegisterInfo.h b/include/llvm/CodeGen/MachineRegisterInfo.h index c599caf7535d..6e5c6473ff4a 100644 --- a/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/include/llvm/CodeGen/MachineRegisterInfo.h @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/MachineRegisterInfo.h ----------------------*- C++ -*-===// +//===- llvm/CodeGen/MachineRegisterInfo.h -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,19 +15,29 @@ #define LLVM_CODEGEN_MACHINEREGISTERINFO_H #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.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/ADT/PointerUnion.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/LowLevelType.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBundle.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/LaneBitmask.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include <vector> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <memory> +#include <utility> namespace llvm { + class PSetIterator; /// Convenient type to represent either a register class or a register bank. @@ -41,15 +51,16 @@ class MachineRegisterInfo { public: class Delegate { virtual void anchor(); + public: - virtual void MRI_NoteNewVirtualRegister(unsigned Reg) = 0; + virtual ~Delegate() = default; - virtual ~Delegate() {} + virtual void MRI_NoteNewVirtualRegister(unsigned Reg) = 0; }; private: MachineFunction *MF; - Delegate *TheDelegate; + Delegate *TheDelegate = nullptr; /// True if subregister liveness is tracked. const bool TracksSubRegLiveness; @@ -62,6 +73,15 @@ private: VirtReg2IndexFunctor> VRegInfo; + /// The flag is true upon \p UpdatedCSRs initialization + /// and false otherwise. + bool IsUpdatedCSRsInitialized; + + /// Contains the updated callee saved register list. + /// As opposed to the static list defined in register info, + /// all registers that were disabled are removed from the list. + SmallVector<MCPhysReg, 16> UpdatedCSRs; + /// RegAllocHints - This vector records register allocation hints for virtual /// registers. For each virtual register, it keeps a register and hint type /// pair making up the allocation hint. Hint type is target specific except @@ -113,12 +133,12 @@ private: /// Live in values are typically arguments in registers. LiveIn values are /// allowed to have virtual registers associated with them, stored in the /// second element. - std::vector<std::pair<unsigned, unsigned> > LiveIns; + std::vector<std::pair<unsigned, unsigned>> LiveIns; - MachineRegisterInfo(const MachineRegisterInfo&) = delete; - void operator=(const MachineRegisterInfo&) = delete; public: explicit MachineRegisterInfo(MachineFunction *MF); + MachineRegisterInfo(const MachineRegisterInfo &) = delete; + MachineRegisterInfo &operator=(const MachineRegisterInfo &) = delete; const TargetRegisterInfo *getTargetRegisterInfo() const { return MF->getSubtarget().getRegisterInfo(); @@ -196,6 +216,23 @@ public: // Register Info //===--------------------------------------------------------------------===// + /// Returns true if the updated CSR list was initialized and false otherwise. + bool isUpdatedCSRsInitialized() const { return IsUpdatedCSRsInitialized; } + + /// Disables the register from the list of CSRs. + /// I.e. the register will not appear as part of the CSR mask. + /// \see UpdatedCalleeSavedRegs. + void disableCalleeSavedRegister(unsigned Reg); + + /// Returns list of callee saved registers. + /// The function returns the updated CSR list (after taking into account + /// registers that are disabled from the CSR list). + const MCPhysReg *getCalleeSavedRegs() const; + + /// Sets the updated Callee Saved Registers list. + /// Notice that it will override ant previously disabled/saved CSRs. + void setCalleeSavedRegs(ArrayRef<MCPhysReg> CSRs); + // Strictly for use by MachineInstr.cpp. void addRegOperandToUseList(MachineOperand *MO); @@ -227,8 +264,6 @@ public: template<bool, bool, bool, bool, bool, bool> friend class defusechain_instr_iterator; - - /// reg_iterator/reg_begin/reg_end - Walk all defs and uses of the specified /// register. typedef defusechain_iterator<true,true,false,true,false,false> @@ -727,8 +762,6 @@ public: const BitVector &getUsedPhysRegsMask() const { return UsedPhysRegMask; } - void setUsedPhysRegMask(BitVector &Mask) { UsedPhysRegMask = Mask; } - //===--------------------------------------------------------------------===// // Reserved Register Info //===--------------------------------------------------------------------===// @@ -800,7 +833,7 @@ public: // Iteration support for the live-ins set. It's kept in sorted order // by register number. - typedef std::vector<std::pair<unsigned,unsigned> >::const_iterator + typedef std::vector<std::pair<unsigned,unsigned>>::const_iterator livein_iterator; livein_iterator livein_begin() const { return LiveIns.begin(); } livein_iterator livein_end() const { return LiveIns.end(); } @@ -836,7 +869,10 @@ public: bool ByOperand, bool ByInstr, bool ByBundle> class defusechain_iterator : public std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t> { - MachineOperand *Op; + friend class MachineRegisterInfo; + + MachineOperand *Op = nullptr; + explicit defusechain_iterator(MachineOperand *op) : Op(op) { // If the first node isn't one we're interested in, advance to one that // we are interested in. @@ -847,7 +883,6 @@ public: advance(); } } - friend class MachineRegisterInfo; void advance() { assert(Op && "Cannot increment end iterator!"); @@ -868,13 +903,14 @@ public: Op = getNextOperandForReg(Op); } } + public: typedef std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t>::reference reference; typedef std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t>::pointer pointer; - defusechain_iterator() : Op(nullptr) {} + defusechain_iterator() = default; bool operator==(const defusechain_iterator &x) const { return Op == x.Op; @@ -939,7 +975,10 @@ public: bool ByOperand, bool ByInstr, bool ByBundle> class defusechain_instr_iterator : public std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t> { - MachineOperand *Op; + friend class MachineRegisterInfo; + + MachineOperand *Op = nullptr; + explicit defusechain_instr_iterator(MachineOperand *op) : Op(op) { // If the first node isn't one we're interested in, advance to one that // we are interested in. @@ -950,7 +989,6 @@ public: advance(); } } - friend class MachineRegisterInfo; void advance() { assert(Op && "Cannot increment end iterator!"); @@ -971,13 +1009,14 @@ public: Op = getNextOperandForReg(Op); } } + public: typedef std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t>::reference reference; typedef std::iterator<std::forward_iterator_tag, MachineInstr, ptrdiff_t>::pointer pointer; - defusechain_instr_iterator() : Op(nullptr) {} + defusechain_instr_iterator() = default; bool operator==(const defusechain_instr_iterator &x) const { return Op == x.Op; @@ -1029,10 +1068,12 @@ public: /// register. If Reg is physical, it must be a register unit (from /// MCRegUnitIterator). class PSetIterator { - const int *PSet; - unsigned Weight; + const int *PSet = nullptr; + unsigned Weight = 0; + public: - PSetIterator(): PSet(nullptr), Weight(0) {} + PSetIterator() = default; + PSetIterator(unsigned RegUnit, const MachineRegisterInfo *MRI) { const TargetRegisterInfo *TRI = MRI->getTargetRegisterInfo(); if (TargetRegisterInfo::isVirtualRegister(RegUnit)) { @@ -1047,6 +1088,7 @@ public: if (*PSet == -1) PSet = nullptr; } + bool isValid() const { return PSet; } unsigned getWeight() const { return Weight; } @@ -1066,6 +1108,6 @@ getPressureSets(unsigned RegUnit) const { return PSetIterator(RegUnit, this); } -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_MACHINEREGISTERINFO_H diff --git a/include/llvm/CodeGen/MachineScheduler.h b/include/llvm/CodeGen/MachineScheduler.h index 81b8741fea27..6b2a16e1d36e 100644 --- a/include/llvm/CodeGen/MachineScheduler.h +++ b/include/llvm/CodeGen/MachineScheduler.h @@ -1,4 +1,4 @@ -//==- MachineScheduler.h - MachineInstr Scheduling Pass ----------*- C++ -*-==// +//===- MachineScheduler.h - MachineInstr Scheduling Pass --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -112,12 +112,12 @@ class ScheduleHazardRecognizer; /// MachineSchedContext provides enough context from the MachineScheduler pass /// for the target to instantiate a scheduler. struct MachineSchedContext { - MachineFunction *MF; - const MachineLoopInfo *MLI; - const MachineDominatorTree *MDT; - const TargetPassConfig *PassConfig; - AliasAnalysis *AA; - LiveIntervals *LIS; + MachineFunction *MF = nullptr; + const MachineLoopInfo *MLI = nullptr; + const MachineDominatorTree *MDT = nullptr; + const TargetPassConfig *PassConfig = nullptr; + AliasAnalysis *AA = nullptr; + LiveIntervals *LIS = nullptr; RegisterClassInfo *RegClassInfo; @@ -165,22 +165,21 @@ class ScheduleDAGMI; /// before building the DAG. struct MachineSchedPolicy { // Allow the scheduler to disable register pressure tracking. - bool ShouldTrackPressure; + bool ShouldTrackPressure = false; /// Track LaneMasks to allow reordering of independent subregister writes /// of the same vreg. \sa MachineSchedStrategy::shouldTrackLaneMasks() - bool ShouldTrackLaneMasks; + bool ShouldTrackLaneMasks = false; // Allow the scheduler to force top-down or bottom-up scheduling. If neither // is true, the scheduler runs in both directions and converges. - bool OnlyTopDown; - bool OnlyBottomUp; + bool OnlyTopDown = false; + bool OnlyBottomUp = false; // Disable heuristic that tries to fetch nodes from long dependency chains // first. - bool DisableLatencyHeuristic; + bool DisableLatencyHeuristic = false; - MachineSchedPolicy(): ShouldTrackPressure(false), ShouldTrackLaneMasks(false), - OnlyTopDown(false), OnlyBottomUp(false), DisableLatencyHeuristic(false) {} + MachineSchedPolicy() = default; }; /// MachineSchedStrategy - Interface to the scheduling algorithm used by @@ -232,6 +231,7 @@ public: /// When all predecessor dependencies have been resolved, free this node for /// top-down scheduling. virtual void releaseTopNode(SUnit *SU) = 0; + /// When all successor dependencies have been resolved, free this node for /// bottom-up scheduling. virtual void releaseBottomNode(SUnit *SU) = 0; @@ -261,24 +261,20 @@ protected: MachineBasicBlock::iterator CurrentBottom; /// Record the next node in a scheduled cluster. - const SUnit *NextClusterPred; - const SUnit *NextClusterSucc; + const SUnit *NextClusterPred = nullptr; + const SUnit *NextClusterSucc = nullptr; #ifndef NDEBUG /// The number of instructions scheduled so far. Used to cut off the /// scheduler at the point determined by misched-cutoff. - unsigned NumInstrsScheduled; + unsigned NumInstrsScheduled = 0; #endif + public: ScheduleDAGMI(MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S, bool RemoveKillFlags) : ScheduleDAGInstrs(*C->MF, C->MLI, RemoveKillFlags), AA(C->AA), - LIS(C->LIS), SchedImpl(std::move(S)), Topo(SUnits, &ExitSU), - NextClusterPred(nullptr), NextClusterSucc(nullptr) { -#ifndef NDEBUG - NumInstrsScheduled = 0; -#endif - } + LIS(C->LIS), SchedImpl(std::move(S)), Topo(SUnits, &ExitSU) {} // Provide a vtable anchor ~ScheduleDAGMI() override; @@ -375,7 +371,7 @@ protected: /// Information about DAG subtrees. If DFSResult is NULL, then SchedulerTrees /// will be empty. - SchedDFSResult *DFSResult; + SchedDFSResult *DFSResult = nullptr; BitVector ScheduledTrees; MachineBasicBlock::iterator LiveRegionEnd; @@ -389,8 +385,8 @@ protected: PressureDiffs SUPressureDiffs; /// Register pressure in this region computed by initRegPressure. - bool ShouldTrackPressure; - bool ShouldTrackLaneMasks; + bool ShouldTrackPressure = false; + bool ShouldTrackLaneMasks = false; IntervalPressure RegPressure; RegPressureTracker RPTracker; @@ -409,16 +405,14 @@ protected: /// True if disconnected subregister components are already renamed. /// The renaming is only done on demand if lane masks are tracked. - bool DisconnectedComponentsRenamed; + bool DisconnectedComponentsRenamed = false; public: ScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S) : ScheduleDAGMI(C, std::move(S), /*RemoveKillFlags=*/false), - RegClassInfo(C->RegClassInfo), DFSResult(nullptr), - ShouldTrackPressure(false), ShouldTrackLaneMasks(false), - RPTracker(RegPressure), TopRPTracker(TopPressure), - BotRPTracker(BotPressure), DisconnectedComponentsRenamed(false) {} + RegClassInfo(C->RegClassInfo), RPTracker(RegPressure), + TopRPTracker(TopPressure), BotRPTracker(BotPressure) {} ~ScheduleDAGMILive() override; @@ -573,6 +567,8 @@ struct SchedRemainder { // Unscheduled resources SmallVector<unsigned, 16> RemainingCounts; + SchedRemainder() { reset(); } + void reset() { CriticalPath = 0; CyclicCritPath = 0; @@ -581,8 +577,6 @@ struct SchedRemainder { RemainingCounts.clear(); } - SchedRemainder() { reset(); } - void init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel); }; @@ -598,14 +592,14 @@ public: LogMaxQID = 2 }; - ScheduleDAGMI *DAG; - const TargetSchedModel *SchedModel; - SchedRemainder *Rem; + ScheduleDAGMI *DAG = nullptr; + const TargetSchedModel *SchedModel = nullptr; + SchedRemainder *Rem = nullptr; ReadyQueue Available; ReadyQueue Pending; - ScheduleHazardRecognizer *HazardRec; + ScheduleHazardRecognizer *HazardRec = nullptr; private: /// True if the pending Q should be checked/updated before scheduling another @@ -665,9 +659,7 @@ public: /// Pending queues extend the ready queues with the same ID and the /// PendingFlag set. SchedBoundary(unsigned ID, const Twine &Name): - DAG(nullptr), SchedModel(nullptr), Rem(nullptr), Available(ID, Name+".A"), - Pending(ID << LogMaxQID, Name+".P"), - HazardRec(nullptr) { + Available(ID, Name+".A"), Pending(ID << LogMaxQID, Name+".P") { reset(); } @@ -781,11 +773,11 @@ public: /// Policy for scheduling the next instruction in the candidate's zone. struct CandPolicy { - bool ReduceLatency; - unsigned ReduceResIdx; - unsigned DemandResIdx; + bool ReduceLatency = false; + unsigned ReduceResIdx = 0; + unsigned DemandResIdx = 0; - CandPolicy(): ReduceLatency(false), ReduceResIdx(0), DemandResIdx(0) {} + CandPolicy() = default; bool operator==(const CandPolicy &RHS) const { return ReduceLatency == RHS.ReduceLatency && @@ -800,12 +792,12 @@ public: /// Status of an instruction's critical resource consumption. struct SchedResourceDelta { // Count critical resources in the scheduled region required by SU. - unsigned CritResources; + unsigned CritResources = 0; // Count critical resources from another region consumed by SU. - unsigned DemandedResources; + unsigned DemandedResources = 0; - SchedResourceDelta(): CritResources(0), DemandedResources(0) {} + SchedResourceDelta() = default; bool operator==(const SchedResourceDelta &RHS) const { return CritResources == RHS.CritResources @@ -866,13 +858,12 @@ public: protected: const MachineSchedContext *Context; - const TargetSchedModel *SchedModel; - const TargetRegisterInfo *TRI; + const TargetSchedModel *SchedModel = nullptr; + const TargetRegisterInfo *TRI = nullptr; SchedRemainder Rem; - GenericSchedulerBase(const MachineSchedContext *C): - Context(C), SchedModel(nullptr), TRI(nullptr) {} + GenericSchedulerBase(const MachineSchedContext *C) : Context(C) {} void setPolicy(CandPolicy &Policy, bool IsPostRA, SchedBoundary &CurrZone, SchedBoundary *OtherZone); @@ -887,7 +878,7 @@ protected: class GenericScheduler : public GenericSchedulerBase { public: GenericScheduler(const MachineSchedContext *C): - GenericSchedulerBase(C), DAG(nullptr), Top(SchedBoundary::TopQID, "TopQ"), + GenericSchedulerBase(C), Top(SchedBoundary::TopQID, "TopQ"), Bot(SchedBoundary::BotQID, "BotQ") {} void initPolicy(MachineBasicBlock::iterator Begin, @@ -929,7 +920,7 @@ public: void registerRoots() override; protected: - ScheduleDAGMILive *DAG; + ScheduleDAGMILive *DAG = nullptr; MachineSchedPolicy RegionPolicy; @@ -1033,9 +1024,6 @@ createStoreClusterDAGMutation(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI); std::unique_ptr<ScheduleDAGMutation> -createMacroFusionDAGMutation(const TargetInstrInfo *TII); - -std::unique_ptr<ScheduleDAGMutation> createCopyConstrainDAGMutation(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI); diff --git a/include/llvm/CodeGen/MachineTraceMetrics.h b/include/llvm/CodeGen/MachineTraceMetrics.h index 06db17abaed9..284f8c197607 100644 --- a/include/llvm/CodeGen/MachineTraceMetrics.h +++ b/include/llvm/CodeGen/MachineTraceMetrics.h @@ -49,54 +49,59 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/TargetSchedule.h" namespace llvm { -class InstrItineraryData; +class AnalysisUsage; class MachineBasicBlock; +class MachineFunction; class MachineInstr; class MachineLoop; class MachineLoopInfo; class MachineRegisterInfo; +struct MCSchedClassDesc; +class raw_ostream; class TargetInstrInfo; class TargetRegisterInfo; -class raw_ostream; class MachineTraceMetrics : public MachineFunctionPass { - const MachineFunction *MF; - const TargetInstrInfo *TII; - const TargetRegisterInfo *TRI; - const MachineRegisterInfo *MRI; - const MachineLoopInfo *Loops; + const MachineFunction *MF = nullptr; + const TargetInstrInfo *TII = nullptr; + const TargetRegisterInfo *TRI = nullptr; + const MachineRegisterInfo *MRI = nullptr; + const MachineLoopInfo *Loops = nullptr; TargetSchedModel SchedModel; public: + friend class Ensemble; + friend class Trace; + class Ensemble; - class Trace; + static char ID; + MachineTraceMetrics(); + void getAnalysisUsage(AnalysisUsage&) const override; bool runOnMachineFunction(MachineFunction&) override; void releaseMemory() override; void verifyAnalysis() const override; - friend class Ensemble; - friend class Trace; - /// Per-basic block information that doesn't depend on the trace through the /// block. struct FixedBlockInfo { /// The number of non-trivial instructions in the block. /// Doesn't count PHI and COPY instructions that are likely to be removed. - unsigned InstrCount; + unsigned InstrCount = ~0u; /// True when the block contains calls. - bool HasCalls; + bool HasCalls = false; - FixedBlockInfo() : InstrCount(~0u), HasCalls(false) {} + FixedBlockInfo() = default; /// Returns true when resource information for this block has been computed. bool hasResources() const { return InstrCount != ~0u; } @@ -134,11 +139,11 @@ public: struct TraceBlockInfo { /// Trace predecessor, or NULL for the first block in the trace. /// Valid when hasValidDepth(). - const MachineBasicBlock *Pred; + const MachineBasicBlock *Pred = nullptr; /// Trace successor, or NULL for the last block in the trace. /// Valid when hasValidHeight(). - const MachineBasicBlock *Succ; + const MachineBasicBlock *Succ = nullptr; /// The block number of the head of the trace. (When hasValidDepth()). unsigned Head; @@ -148,16 +153,13 @@ public: /// Accumulated number of instructions in the trace above this block. /// Does not include instructions in this block. - unsigned InstrDepth; + unsigned InstrDepth = ~0u; /// Accumulated number of instructions in the trace below this block. /// Includes instructions in this block. - unsigned InstrHeight; + unsigned InstrHeight = ~0u; - TraceBlockInfo() : - Pred(nullptr), Succ(nullptr), - InstrDepth(~0u), InstrHeight(~0u), - HasValidInstrDepths(false), HasValidInstrHeights(false) {} + TraceBlockInfo() = default; /// Returns true if the depth resources have been computed from the trace /// above this block. @@ -199,10 +201,10 @@ public: // itinerary data. /// Instruction depths have been computed. This implies hasValidDepth(). - bool HasValidInstrDepths; + bool HasValidInstrDepths = false; /// Instruction heights have been computed. This implies hasValidHeight(). - bool HasValidInstrHeights; + bool HasValidInstrHeights = false; /// Critical path length. This is the number of cycles in the longest data /// dependency chain through the trace. This is only valid when both @@ -242,6 +244,7 @@ public: public: explicit Trace(Ensemble &te, TraceBlockInfo &tbi) : TE(te), TBI(tbi) {} + void print(raw_ostream&) const; /// Compute the total number of instructions in the trace. @@ -300,11 +303,12 @@ public: /// strategy, for example 'minimum resource height'. There is one trace for /// every block in the function. class Ensemble { + friend class Trace; + SmallVector<TraceBlockInfo, 4> BlockInfo; DenseMap<const MachineInstr*, InstrCycles> Cycles; SmallVector<unsigned, 0> ProcResourceDepths; SmallVector<unsigned, 0> ProcResourceHeights; - friend class Trace; void computeTrace(const MachineBasicBlock*); void computeDepthResources(const MachineBasicBlock*); @@ -317,9 +321,11 @@ public: protected: MachineTraceMetrics &MTM; + + explicit Ensemble(MachineTraceMetrics*); + virtual const MachineBasicBlock *pickTracePred(const MachineBasicBlock*) =0; virtual const MachineBasicBlock *pickTraceSucc(const MachineBasicBlock*) =0; - explicit Ensemble(MachineTraceMetrics*); const MachineLoop *getLoopFor(const MachineBasicBlock*) const; const TraceBlockInfo *getDepthResources(const MachineBasicBlock*) const; const TraceBlockInfo *getHeightResources(const MachineBasicBlock*) const; @@ -328,7 +334,8 @@ public: public: virtual ~Ensemble(); - virtual const char *getName() const =0; + + virtual const char *getName() const = 0; void print(raw_ostream&) const; void invalidate(const MachineBasicBlock *MBB); void verify() const; @@ -394,6 +401,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, En.print(OS); return OS; } + } // end namespace llvm -#endif +#endif // LLVM_CODEGEN_MACHINETRACEMETRICS_H diff --git a/include/llvm/CodeGen/MachineValueType.h b/include/llvm/CodeGen/MachineValueType.h index de7064f07c3e..e4744fd5e260 100644 --- a/include/llvm/CodeGen/MachineValueType.h +++ b/include/llvm/CodeGen/MachineValueType.h @@ -23,14 +23,13 @@ namespace llvm { class Type; - /// MVT - Machine Value Type. Every type that is supported natively by some + /// Machine Value Type. Every type that is supported natively by some /// processor targeted by LLVM occurs here. This means that any legal value /// type can be represented by an MVT. class MVT { public: enum SimpleValueType : int8_t { - // INVALID_SIMPLE_VALUE_TYPE - Simple value types less than zero are - // considered extended value types. + // Simple value types less than zero are considered extended value types. INVALID_SIMPLE_VALUE_TYPE = -1, // If you change this numbering, you must change the values in @@ -141,37 +140,37 @@ class MVT { // This value must be a multiple of 32. MAX_ALLOWED_VALUETYPE = 96, - // Token - A value of type llvm::TokenTy + // A value of type llvm::TokenTy token = 120, - // Metadata - This is MDNode or MDString. + // This is MDNode or MDString. Metadata = 121, - // iPTRAny - An int value the size of the pointer of the current + // 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 = 122, - // vAny - A vector with any length and element size. This is used + // 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 = 123, - // fAny - Any floating-point or vector floating-point value. This is used + // 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 = 124, - // iAny - An integer or vector integer value of any bit width. This is + // 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 = 125, - // iPTR - An int value the size of the pointer of the current + // An int value the size of the pointer of the current // target. This should only be used internal to tblgen! iPTR = 126, - // Any - Any type. This is used for intrinsics that have overloadings. + // Any type. This is used for intrinsics that have overloadings. // This is only for tblgen's consumption! Any = 127 }; @@ -188,13 +187,13 @@ class MVT { bool operator>=(const MVT& S) const { return SimpleTy >= S.SimpleTy; } bool operator<=(const MVT& S) const { return SimpleTy <= S.SimpleTy; } - /// isValid - Return true if this is a valid simple valuetype. + /// Return true if this is a valid simple valuetype. bool isValid() const { return (SimpleTy >= MVT::FIRST_VALUETYPE && SimpleTy < MVT::LAST_VALUETYPE); } - /// isFloatingPoint - Return true if this is a FP, or a vector FP type. + /// Return true if this is a FP or a vector FP type. bool isFloatingPoint() const { return ((SimpleTy >= MVT::FIRST_FP_VALUETYPE && SimpleTy <= MVT::LAST_FP_VALUETYPE) || @@ -202,7 +201,7 @@ class MVT { SimpleTy <= MVT::LAST_FP_VECTOR_VALUETYPE)); } - /// isInteger - Return true if this is an integer, or a vector integer type. + /// Return true if this is an integer or a vector integer type. bool isInteger() const { return ((SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE && SimpleTy <= MVT::LAST_INTEGER_VALUETYPE) || @@ -210,41 +209,40 @@ class MVT { SimpleTy <= MVT::LAST_INTEGER_VECTOR_VALUETYPE)); } - /// isScalarInteger - Return true if this is an integer, not including - /// vectors. + /// 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. + /// Return true if this is a vector value type. bool isVector() const { return (SimpleTy >= MVT::FIRST_VECTOR_VALUETYPE && SimpleTy <= MVT::LAST_VECTOR_VALUETYPE); } - /// is16BitVector - Return true if this is a 16-bit vector type. + /// Return true if this is a 16-bit vector type. bool is16BitVector() const { return (SimpleTy == MVT::v2i8 || SimpleTy == MVT::v1i16 || SimpleTy == MVT::v16i1); } - /// is32BitVector - Return true if this is a 32-bit vector type. + /// Return true if this is a 32-bit vector type. bool is32BitVector() const { - return (SimpleTy == MVT::v4i8 || SimpleTy == MVT::v2i16 || - SimpleTy == MVT::v1i32 || SimpleTy == MVT::v2f16 || - SimpleTy == MVT::v1f32); + return (SimpleTy == MVT::v32i1 || SimpleTy == MVT::v4i8 || + SimpleTy == MVT::v2i16 || SimpleTy == MVT::v1i32 || + SimpleTy == MVT::v2f16 || SimpleTy == MVT::v1f32); } - /// is64BitVector - Return true if this is a 64-bit vector type. + /// Return true if this is a 64-bit vector type. bool is64BitVector() const { - return (SimpleTy == MVT::v8i8 || SimpleTy == MVT::v4i16 || - SimpleTy == MVT::v2i32 || SimpleTy == MVT::v1i64 || - SimpleTy == MVT::v4f16 || SimpleTy == MVT::v2f32 || - SimpleTy == MVT::v1f64); + return (SimpleTy == MVT::v64i1 || SimpleTy == MVT::v8i8 || + SimpleTy == MVT::v4i16 || SimpleTy == MVT::v2i32 || + SimpleTy == MVT::v1i64 || SimpleTy == MVT::v4f16 || + SimpleTy == MVT::v2f32 || SimpleTy == MVT::v1f64); } - /// is128BitVector - Return true if this is a 128-bit vector type. + /// Return true if this is a 128-bit vector type. bool is128BitVector() const { return (SimpleTy == MVT::v16i8 || SimpleTy == MVT::v8i16 || SimpleTy == MVT::v4i32 || SimpleTy == MVT::v2i64 || @@ -252,14 +250,14 @@ class MVT { SimpleTy == MVT::v4f32 || SimpleTy == MVT::v2f64); } - /// is256BitVector - Return true if this is a 256-bit vector type. + /// Return true if this is a 256-bit vector type. bool is256BitVector() const { return (SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 || SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 || SimpleTy == MVT::v8i32 || SimpleTy == MVT::v4i64); } - /// is512BitVector - Return true if this is a 512-bit vector type. + /// Return true if this is a 512-bit vector type. bool is512BitVector() const { return (SimpleTy == MVT::v16f32 || SimpleTy == MVT::v8f64 || SimpleTy == MVT::v512i1 || SimpleTy == MVT::v64i8 || @@ -267,34 +265,34 @@ class MVT { SimpleTy == MVT::v8i64); } - /// is1024BitVector - Return true if this is a 1024-bit vector type. + /// Return true if this is a 1024-bit vector type. bool is1024BitVector() const { return (SimpleTy == MVT::v1024i1 || SimpleTy == MVT::v128i8 || SimpleTy == MVT::v64i16 || SimpleTy == MVT::v32i32 || SimpleTy == MVT::v16i64); } - /// is2048BitVector - Return true if this is a 1024-bit vector type. + /// Return true if this is a 1024-bit vector type. bool is2048BitVector() const { return (SimpleTy == MVT::v256i8 || SimpleTy == MVT::v128i16 || SimpleTy == MVT::v64i32 || SimpleTy == MVT::v32i64); } - /// isOverloaded - Return true if this is an overloaded type for TableGen. + /// Return true if this is an overloaded type for TableGen. bool isOverloaded() const { return (SimpleTy==MVT::Any || SimpleTy==MVT::iAny || SimpleTy==MVT::fAny || SimpleTy==MVT::vAny || SimpleTy==MVT::iPTRAny); } - /// isPow2VectorType - Returns true if the given vector is a power of 2. + /// Returns true if the given vector is a power of 2. bool isPow2VectorType() const { unsigned NElts = getVectorNumElements(); return !(NElts & (NElts - 1)); } - /// getPow2VectorType - Widens the length of the given vector MVT up to - /// the nearest power of 2 and returns that type. + /// Widens the length of the given vector MVT up to the nearest power of 2 + /// and returns that type. MVT getPow2VectorType() const { if (isPow2VectorType()) return *this; @@ -304,8 +302,7 @@ class MVT { return MVT::getVectorVT(getVectorElementType(), Pow2NElts); } - /// getScalarType - If this is a vector type, return the element type, - /// otherwise return this. + /// If this is a vector, return the element type, otherwise return this. MVT getScalarType() const { return isVector() ? getVectorElementType() : *this; } @@ -516,14 +513,14 @@ class MVT { return getScalarType().getSizeInBits(); } - /// getStoreSize - Return the number of bytes overwritten by a store - /// of the specified value type. + /// Return the number of bytes overwritten by a store of the specified value + /// type. unsigned getStoreSize() const { return (getSizeInBits() + 7) / 8; } - /// getStoreSizeInBits - Return the number of bits overwritten by a store - /// of the specified value type. + /// Return the number of bits overwritten by a store of the specified value + /// type. unsigned getStoreSizeInBits() const { return getStoreSize() * 8; } diff --git a/include/llvm/CodeGen/PBQP/Solution.h b/include/llvm/CodeGen/PBQP/Solution.h index bd74805a2397..d96b5eac4520 100644 --- a/include/llvm/CodeGen/PBQP/Solution.h +++ b/include/llvm/CodeGen/PBQP/Solution.h @@ -1,4 +1,4 @@ -//===-- Solution.h ------- PBQP Solution ------------------------*- C++ -*-===// +//===- Solution.h - PBQP Solution -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,8 +14,8 @@ #ifndef LLVM_CODEGEN_PBQP_SOLUTION_H #define LLVM_CODEGEN_PBQP_SOLUTION_H -#include "Graph.h" -#include "Math.h" +#include "llvm/CodeGen/PBQP/Graph.h" +#include <cassert> #include <map> namespace llvm { @@ -26,17 +26,17 @@ namespace PBQP { /// To get the selection for each node in the problem use the getSelection method. class Solution { private: - typedef std::map<GraphBase::NodeId, unsigned> SelectionsMap; SelectionsMap selections; - unsigned r0Reductions, r1Reductions, r2Reductions, rNReductions; + unsigned r0Reductions = 0; + unsigned r1Reductions = 0; + unsigned r2Reductions = 0; + unsigned rNReductions = 0; public: - /// \brief Initialise an empty solution. - Solution() - : r0Reductions(0), r1Reductions(0), r2Reductions(0), rNReductions(0) {} + Solution() = default; /// \brief Set the selection for a given node. /// @param nodeId Node id. @@ -53,10 +53,9 @@ namespace PBQP { assert(sItr != selections.end() && "No selection for node."); return sItr->second; } - }; -} // namespace PBQP -} // namespace llvm +} // end namespace PBQP +} // end namespace llvm #endif // LLVM_CODEGEN_PBQP_SOLUTION_H diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index a9fd301691d6..42299b529410 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -60,7 +60,9 @@ namespace llvm { /// as if it was just created. /// If EmitFallbackDiag is true, the pass will emit a /// DiagnosticInfoISelFallback for every MachineFunction it resets. - MachineFunctionPass *createResetMachineFunctionPass(bool EmitFallbackDiag); + /// If AbortOnFailedISel is true, abort compilation instead of resetting. + MachineFunctionPass *createResetMachineFunctionPass(bool EmitFallbackDiag, + bool AbortOnFailedISel); /// createCodeGenPreparePass - Transform the code to expose more pattern /// matching during instruction selection. @@ -79,6 +81,9 @@ namespace llvm { /// MachineDominanaceFrontier - This pass is a machine dominators analysis pass. extern char &MachineDominanceFrontierID; + /// MachineRegionInfo - This pass computes SESE regions for machine functions. + extern char &MachineRegionInfoPassID; + /// EdgeBundles analysis - Bundle machine CFG edges. extern char &EdgeBundlesID; @@ -284,6 +289,9 @@ namespace llvm { /// the target platform. extern char &XRayInstrumentationID; + /// This pass inserts FEntry calls + extern char &FEntryInserterID; + /// \brief This pass implements the "patchable-function" attribute. extern char &PatchableFunctionID; @@ -318,14 +326,6 @@ namespace llvm { /// ExpandISelPseudos - This pass expands pseudo-instructions. extern char &ExpandISelPseudosID; - /// createExecutionDependencyFixPass - This pass fixes execution time - /// problems with dependent instructions, such as switching execution - /// domains to match. - /// - /// The pass will examine instructions using and defining registers in RC. - /// - FunctionPass *createExecutionDependencyFixPass(const TargetRegisterClass *RC); - /// UnpackMachineBundles - This pass unpack machine instruction bundles. extern char &UnpackMachineBundlesID; @@ -397,6 +397,14 @@ namespace llvm { /// This pass frees the memory occupied by the MachineFunction. FunctionPass *createFreeMachineFunctionPass(); + + /// This pass combine basic blocks guarded by the same branch. + extern char &BranchCoalescingID; + + /// This pass performs outlining on machine instructions directly before + /// printing assembly. + ModulePass *createMachineOutlinerPass(); + } // End llvm namespace /// Target machine pass initializer for passes with dependencies. Use with @@ -413,7 +421,7 @@ namespace llvm { Registry.registerPass(*PI, true); \ return PI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + static llvm::once_flag Initialize##passName##PassFlag; \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ llvm::call_once(Initialize##passName##PassFlag, \ initialize##passName##PassOnce, std::ref(Registry)); \ diff --git a/include/llvm/CodeGen/RegAllocPBQP.h b/include/llvm/CodeGen/RegAllocPBQP.h index 2cad90bbb703..8872a5dc54a1 100644 --- a/include/llvm/CodeGen/RegAllocPBQP.h +++ b/include/llvm/CodeGen/RegAllocPBQP.h @@ -1,4 +1,4 @@ -//===-- RegAllocPBQP.h ------------------------------------------*- C++ -*-===// +//===- RegAllocPBQP.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,15 +16,28 @@ #ifndef LLVM_CODEGEN_REGALLOCPBQP_H #define LLVM_CODEGEN_REGALLOCPBQP_H -#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" #include "llvm/CodeGen/PBQP/CostAllocator.h" +#include "llvm/CodeGen/PBQP/Graph.h" +#include "llvm/CodeGen/PBQP/Math.h" #include "llvm/CodeGen/PBQP/ReductionRules.h" -#include "llvm/CodeGen/PBQPRAConstraint.h" +#include "llvm/CodeGen/PBQP/Solution.h" #include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <limits> +#include <memory> #include <set> +#include <vector> namespace llvm { +class FunctionPass; +class LiveIntervals; +class MachineBlockFrequencyInfo; +class MachineFunction; class raw_ostream; namespace PBQP { @@ -37,15 +50,10 @@ inline unsigned getSpillOptionIdx() { return 0; } /// /// Keeps track of the number of infinities in each row and column. class MatrixMetadata { -private: - MatrixMetadata(const MatrixMetadata&); - void operator=(const MatrixMetadata&); public: MatrixMetadata(const Matrix& M) - : WorstRow(0), WorstCol(0), - UnsafeRows(new bool[M.getRows() - 1]()), + : UnsafeRows(new bool[M.getRows() - 1]()), UnsafeCols(new bool[M.getCols() - 1]()) { - unsigned* ColCounts = new unsigned[M.getCols() - 1](); for (unsigned i = 1; i < M.getRows(); ++i) { @@ -66,13 +74,17 @@ public: delete[] ColCounts; } + MatrixMetadata(const MatrixMetadata &) = delete; + MatrixMetadata &operator=(const MatrixMetadata &) = delete; + unsigned getWorstRow() const { return WorstRow; } unsigned getWorstCol() const { return WorstCol; } const bool* getUnsafeRows() const { return UnsafeRows.get(); } const bool* getUnsafeCols() const { return UnsafeCols.get(); } private: - unsigned WorstRow, WorstCol; + unsigned WorstRow = 0; + unsigned WorstCol = 0; std::unique_ptr<bool[]> UnsafeRows; std::unique_ptr<bool[]> UnsafeCols; }; @@ -80,17 +92,16 @@ private: /// \brief Holds a vector of the allowed physical regs for a vreg. class AllowedRegVector { friend hash_code hash_value(const AllowedRegVector &); -public: - AllowedRegVector() : NumOpts(0), Opts(nullptr) {} +public: + AllowedRegVector() = default; + AllowedRegVector(AllowedRegVector &&) = default; AllowedRegVector(const std::vector<unsigned> &OptVec) : NumOpts(OptVec.size()), Opts(new unsigned[NumOpts]) { std::copy(OptVec.begin(), OptVec.end(), Opts.get()); } - AllowedRegVector(AllowedRegVector &&) = default; - unsigned size() const { return NumOpts; } unsigned operator[](size_t I) const { return Opts[I]; } @@ -105,7 +116,7 @@ public: } private: - unsigned NumOpts; + unsigned NumOpts = 0; std::unique_ptr<unsigned[]> Opts; }; @@ -120,8 +131,8 @@ inline hash_code hash_value(const AllowedRegVector &OptRegs) { class GraphMetadata { private: typedef ValuePool<AllowedRegVector> AllowedRegVecPool; -public: +public: typedef AllowedRegVecPool::PoolRef AllowedRegVecRef; GraphMetadata(MachineFunction &MF, @@ -168,13 +179,7 @@ public: OptimallyReducible } ReductionState; - NodeMetadata() - : RS(Unprocessed), NumOpts(0), DeniedOpts(0), OptUnsafeEdges(nullptr), - VReg(0) -#ifndef NDEBUG - , everConservativelyAllocatable(false) -#endif - {} + NodeMetadata() = default; NodeMetadata(const NodeMetadata &Other) : RS(Other.RS), NumOpts(Other.NumOpts), DeniedOpts(Other.DeniedOpts), @@ -190,9 +195,8 @@ public: } } - NodeMetadata(NodeMetadata &&Other) = default; - - NodeMetadata& operator=(NodeMetadata &&Other) = default; + NodeMetadata(NodeMetadata &&) = default; + NodeMetadata& operator=(NodeMetadata &&) = default; void setVReg(unsigned VReg) { this->VReg = VReg; } unsigned getVReg() const { return VReg; } @@ -249,21 +253,22 @@ public: #endif private: - ReductionState RS; - unsigned NumOpts; - unsigned DeniedOpts; + ReductionState RS = Unprocessed; + unsigned NumOpts = 0; + unsigned DeniedOpts = 0; std::unique_ptr<unsigned[]> OptUnsafeEdges; - unsigned VReg; + unsigned VReg = 0; GraphMetadata::AllowedRegVecRef AllowedRegs; #ifndef NDEBUG - bool everConservativelyAllocatable; + bool everConservativelyAllocatable = false; #endif }; class RegAllocSolverImpl { private: typedef MDMatrix<MatrixMetadata> RAMatrix; + public: typedef PBQP::Vector RawVector; typedef PBQP::Matrix RawMatrix; @@ -296,6 +301,7 @@ public: "PBQP Graph should not contain single or zero-option nodes"); G.getNodeMetadata(NId).setup(G.getNodeCosts(NId)); } + void handleRemoveNode(NodeId NId) {} void handleSetNodeCosts(NodeId NId, const Vector& newCosts) {} @@ -342,7 +348,6 @@ public: } private: - void promote(NodeId NId, NodeMetadata& NMd) { if (G.getNodeDegree(NId) == 3) { // This node is becoming optimally reducible. @@ -474,6 +479,7 @@ private: class SpillCostComparator { public: SpillCostComparator(const Graph& G) : G(G) {} + bool operator()(NodeId N1Id, NodeId N2Id) { PBQPNum N1SC = G.getNodeCosts(N1Id)[0]; PBQPNum N2SC = G.getNodeCosts(N2Id)[0]; @@ -481,6 +487,7 @@ private: return G.getNodeDegree(N1Id) < G.getNodeDegree(N2Id); return N1SC < N2SC; } + private: const Graph& G; }; @@ -495,8 +502,9 @@ private: class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> { private: typedef PBQP::Graph<RegAllocSolverImpl> BaseT; + public: - PBQPRAGraph(GraphMetadata Metadata) : BaseT(Metadata) {} + PBQPRAGraph(GraphMetadata Metadata) : BaseT(std::move(Metadata)) {} /// @brief Dump this graph to dbgs(). void dump() const; @@ -517,13 +525,13 @@ inline Solution solve(PBQPRAGraph& G) { return RegAllocSolver.solve(); } -} // namespace RegAlloc -} // namespace PBQP +} // end namespace RegAlloc +} // end namespace PBQP /// @brief Create a PBQP register allocator instance. FunctionPass * createPBQPRegisterAllocator(char *customPassID = nullptr); -} // namespace llvm +} // end namespace llvm -#endif /* LLVM_CODEGEN_REGALLOCPBQP_H */ +#endif // LLVM_CODEGEN_REGALLOCPBQP_H diff --git a/include/llvm/CodeGen/RegisterClassInfo.h b/include/llvm/CodeGen/RegisterClassInfo.h index d784dfbda7ec..355c9f9b2f1e 100644 --- a/include/llvm/CodeGen/RegisterClassInfo.h +++ b/include/llvm/CodeGen/RegisterClassInfo.h @@ -1,4 +1,4 @@ -//===-- RegisterClassInfo.h - Dynamic Register Class Info -*- C++ -*-------===// +//===- RegisterClassInfo.h - Dynamic Register Class Info --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,22 +19,25 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Target/TargetRegisterInfo.h" +#include <cassert> +#include <cstdint> +#include <memory> namespace llvm { class RegisterClassInfo { struct RCInfo { - unsigned Tag; - unsigned NumRegs; - bool ProperSubClass; - uint8_t MinCost; - uint16_t LastCostChange; + unsigned Tag = 0; + unsigned NumRegs = 0; + bool ProperSubClass = false; + uint8_t MinCost = 0; + uint16_t LastCostChange = 0; std::unique_ptr<MCPhysReg[]> Order; - RCInfo() - : Tag(0), NumRegs(0), ProperSubClass(false), MinCost(0), - LastCostChange(0) {} + RCInfo() = default; operator ArrayRef<MCPhysReg>() const { return makeArrayRef(Order.get(), NumRegs); @@ -46,17 +49,18 @@ class RegisterClassInfo { // Tag changes whenever cached information needs to be recomputed. An RCInfo // entry is valid when its tag matches. - unsigned Tag; + unsigned Tag = 0; - const MachineFunction *MF; - const TargetRegisterInfo *TRI; + const MachineFunction *MF = nullptr; + const TargetRegisterInfo *TRI = nullptr; // Callee saved registers of last MF. Assumed to be valid until the next // runOnFunction() call. - const MCPhysReg *CalleeSaved; + // Used only to determine if an update was made to CalleeSavedAliases. + const MCPhysReg *CalleeSavedRegs = nullptr; - // Map register number to CalleeSaved index + 1; - SmallVector<uint8_t, 4> CSRNum; + // Map register alias to the callee saved Register. + SmallVector<MCPhysReg, 4> CalleeSavedAliases; // Reserved registers in the current MF. BitVector Reserved; @@ -105,11 +109,11 @@ public: } /// getLastCalleeSavedAlias - Returns the last callee saved register that - /// overlaps PhysReg, or 0 if Reg doesn't overlap a CSR. + /// overlaps PhysReg, or 0 if Reg doesn't overlap a CalleeSavedAliases. unsigned getLastCalleeSavedAlias(unsigned PhysReg) const { assert(TargetRegisterInfo::isPhysicalRegister(PhysReg)); - if (unsigned N = CSRNum[PhysReg]) - return CalleeSaved[N-1]; + if (PhysReg < CalleeSavedAliases.size()) + return CalleeSavedAliases[PhysReg]; return 0; } @@ -140,6 +144,7 @@ public: protected: unsigned computePSetLimit(unsigned Idx) const; }; + } // end namespace llvm -#endif +#endif // LLVM_CODEGEN_REGISTERCLASSINFO_H diff --git a/include/llvm/CodeGen/RegisterPressure.h b/include/llvm/CodeGen/RegisterPressure.h index 313be355e7d7..a3ea41d5236e 100644 --- a/include/llvm/CodeGen/RegisterPressure.h +++ b/include/llvm/CodeGen/RegisterPressure.h @@ -1,4 +1,4 @@ -//===-- RegisterPressure.h - Dynamic Register Pressure -*- C++ -*-------===// +//===- RegisterPressure.h - Dynamic Register Pressure -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,16 +15,25 @@ #ifndef LLVM_CODEGEN_REGISTERPRESSURE_H #define LLVM_CODEGEN_REGISTERPRESSURE_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseSet.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/SlotIndexes.h" +#include "llvm/MC/LaneBitmask.h" #include "llvm/Target/TargetRegisterInfo.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <limits> +#include <vector> namespace llvm { class LiveIntervals; -class LiveRange; -class RegisterClassInfo; class MachineInstr; +class RegisterClassInfo; struct RegisterMaskPair { unsigned RegUnit; ///< Virtual register or register unit. @@ -91,12 +100,13 @@ struct RegionPressure : RegisterPressure { /// higher level assert that pressure is consistent within a region. We also /// effectively ignore dead defs which don't affect heuristics much. class PressureChange { - uint16_t PSetID; // ID+1. 0=Invalid. - int16_t UnitInc; + uint16_t PSetID = 0; // ID+1. 0=Invalid. + int16_t UnitInc = 0; + public: - PressureChange(): PSetID(0), UnitInc(0) {} - PressureChange(unsigned id): PSetID(id+1), UnitInc(0) { - assert(id < UINT16_MAX && "PSetID overflow."); + PressureChange() = default; + PressureChange(unsigned id): PSetID(id + 1) { + assert(id < std::numeric_limits<uint16_t>::max() && "PSetID overflow."); } bool isValid() const { return PSetID > 0; } @@ -105,8 +115,11 @@ public: assert(isValid() && "invalid PressureChange"); return PSetID - 1; } + // If PSetID is invalid, return UINT16_MAX to give it lowest priority. - unsigned getPSetOrMax() const { return (PSetID - 1) & UINT16_MAX; } + unsigned getPSetOrMax() const { + return (PSetID - 1) & std::numeric_limits<uint16_t>::max(); + } int getUnitInc() const { return UnitInc; } @@ -146,7 +159,7 @@ public: void addPressureChange(unsigned RegUnit, bool IsDec, const MachineRegisterInfo *MRI); - LLVM_DUMP_METHOD void dump(const TargetRegisterInfo &TRI) const; + void dump(const TargetRegisterInfo &TRI) const; }; /// List of registers defined and used by a machine instruction. @@ -182,11 +195,12 @@ public: /// Array of PressureDiffs. class PressureDiffs { - PressureDiff *PDiffArray; - unsigned Size; - unsigned Max; + PressureDiff *PDiffArray = nullptr; + unsigned Size = 0; + unsigned Max = 0; + public: - PressureDiffs(): PDiffArray(nullptr), Size(0), Max(0) {} + PressureDiffs() = default; ~PressureDiffs() { free(PDiffArray); } void clear() { Size = 0; } @@ -200,6 +214,7 @@ public: const PressureDiff &operator[](unsigned Idx) const { return const_cast<PressureDiffs*>(this)->operator[](Idx); } + /// \brief Record pressure difference induced by the given operand list to /// node with index \p Idx. void addInstruction(unsigned Idx, const RegisterOperands &RegOpers, @@ -225,7 +240,7 @@ struct RegPressureDelta { PressureChange CriticalMax; PressureChange CurrentMax; - RegPressureDelta() {} + RegPressureDelta() = default; bool operator==(const RegPressureDelta &RHS) const { return Excess == RHS.Excess && CriticalMax == RHS.CriticalMax @@ -264,6 +279,7 @@ private: assert(Reg < NumRegUnits); return Reg; } + unsigned getRegFromSparseIndex(unsigned SparseIndex) const { if (SparseIndex >= NumRegUnits) return TargetRegisterInfo::index2VirtReg(SparseIndex-NumRegUnits); @@ -338,14 +354,14 @@ public: /// tracking. Changing direction has the side effect of closing region, and /// traversing past TopIdx or BottomIdx reopens it. class RegPressureTracker { - const MachineFunction *MF; - const TargetRegisterInfo *TRI; - const RegisterClassInfo *RCI; + const MachineFunction *MF = nullptr; + const TargetRegisterInfo *TRI = nullptr; + const RegisterClassInfo *RCI = nullptr; const MachineRegisterInfo *MRI; - const LiveIntervals *LIS; + const LiveIntervals *LIS = nullptr; /// We currently only allow pressure tracking within a block. - const MachineBasicBlock *MBB; + const MachineBasicBlock *MBB = nullptr; /// Track the max pressure within the region traversed so far. RegisterPressure &P; @@ -355,10 +371,10 @@ class RegPressureTracker { bool RequireIntervals; /// True if UntiedDefs will be populated. - bool TrackUntiedDefs; + bool TrackUntiedDefs = false; /// True if lanemasks should be tracked. - bool TrackLaneMasks; + bool TrackLaneMasks = false; /// Register pressure corresponds to liveness before this instruction /// iterator. It may point to the end of the block or a DebugValue rather than @@ -377,13 +393,8 @@ class RegPressureTracker { std::vector<unsigned> LiveThruPressure; public: - RegPressureTracker(IntervalPressure &rp) : - MF(nullptr), TRI(nullptr), RCI(nullptr), LIS(nullptr), MBB(nullptr), P(rp), - 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), TrackLaneMasks(false) {} + RegPressureTracker(IntervalPressure &rp) : P(rp), RequireIntervals(true) {} + RegPressureTracker(RegionPressure &rp) : P(rp), RequireIntervals(false) {} void reset(); @@ -555,6 +566,7 @@ protected: void dumpRegSetPressure(ArrayRef<unsigned> SetPressure, const TargetRegisterInfo *TRI); + } // end namespace llvm -#endif +#endif // LLVM_CODEGEN_REGISTERPRESSURE_H diff --git a/include/llvm/CodeGen/RegisterScavenging.h b/include/llvm/CodeGen/RegisterScavenging.h index 1b9232b90193..1f939e72e139 100644 --- a/include/llvm/CodeGen/RegisterScavenging.h +++ b/include/llvm/CodeGen/RegisterScavenging.h @@ -1,4 +1,4 @@ -//===-- RegisterScavenging.h - Machine register scavenging ------*- C++ -*-===// +//===- RegisterScavenging.h - Machine register scavenging -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,49 +19,49 @@ #define LLVM_CODEGEN_REGISTERSCAVENGING_H #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/LiveRegUnits.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/MC/LaneBitmask.h" namespace llvm { -class MachineRegisterInfo; -class TargetRegisterInfo; +class MachineInstr; class TargetInstrInfo; class TargetRegisterClass; +class TargetRegisterInfo; class RegScavenger { const TargetRegisterInfo *TRI; const TargetInstrInfo *TII; MachineRegisterInfo* MRI; - MachineBasicBlock *MBB; + MachineBasicBlock *MBB = nullptr; MachineBasicBlock::iterator MBBI; - unsigned NumRegUnits; + unsigned NumRegUnits = 0; /// True if RegScavenger is currently tracking the liveness of registers. - bool Tracking; + bool Tracking = false; /// Information on scavenged registers (held in a spill slot). struct ScavengedInfo { - ScavengedInfo(int FI = -1) : FrameIndex(FI), Reg(0), Restore(nullptr) {} + ScavengedInfo(int FI = -1) : FrameIndex(FI) {} /// A spill slot used for scavenging a register post register allocation. int FrameIndex; /// If non-zero, the specific register is currently being /// scavenged. That is, it is spilled to this scavenging stack slot. - unsigned Reg; + unsigned Reg = 0; /// The instruction that restores the scavenged register from stack. - const MachineInstr *Restore; + const MachineInstr *Restore = nullptr; }; /// A vector of information on scavenged registers. SmallVector<ScavengedInfo, 2> Scavenged; - /// The current state of each reg unit immediately before MBBI. - /// One bit per register unit. If bit is not set it means any - /// register containing that register unit is currently being used. - BitVector RegUnitsAvailable; + LiveRegUnits LiveUnits; // These BitVectors are only used internally to forward(). They are members // to avoid frequent reallocations. @@ -69,8 +69,7 @@ class RegScavenger { BitVector TmpRegUnits; public: - RegScavenger() - : MBB(nullptr), NumRegUnits(0), Tracking(false) {} + RegScavenger() = default; /// Start tracking liveness from the begin of basic block \p MBB. void enterBasicBlock(MachineBasicBlock &MBB); @@ -165,17 +164,18 @@ public: /// Tell the scavenger a register is used. void setRegUsed(unsigned Reg, LaneBitmask LaneMask = LaneBitmask::getAll()); + private: /// Returns true if a register is reserved. It is never "unused". bool isReserved(unsigned Reg) const { return MRI->isReserved(Reg); } /// setUsed / setUnused - Mark the state of one or a number of register units. /// - void setUsed(BitVector &RegUnits) { - RegUnitsAvailable.reset(RegUnits); + void setUsed(const BitVector &RegUnits) { + LiveUnits.addUnits(RegUnits); } - void setUnused(BitVector &RegUnits) { - RegUnitsAvailable |= RegUnits; + void setUnused(const BitVector &RegUnits) { + LiveUnits.removeUnits(RegUnits); } /// Processes the current instruction and fill the KillRegUnits and @@ -204,6 +204,6 @@ private: void setLiveInsUsed(const MachineBasicBlock &MBB); }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_REGISTERSCAVENGING_H diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h index ed4e0bc8a4a1..99afd8c5c9ab 100644 --- a/include/llvm/CodeGen/ScheduleDAG.h +++ b/include/llvm/CodeGen/ScheduleDAG.h @@ -1,4 +1,4 @@ -//===------- llvm/CodeGen/ScheduleDAG.h - Common Base Class------*- C++ -*-===// +//===- llvm/CodeGen/ScheduleDAG.h - Common Base Class -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// // -// This file implements the ScheduleDAG class, which is used as the common -// base class for instruction schedulers. This encapsulates the scheduling DAG, -// which is shared between SelectionDAG and MachineInstr scheduling. +/// \file Implements the ScheduleDAG class, which is used as the common base +/// class for instruction schedulers. This encapsulates the scheduling DAG, +/// which is shared between SelectionDAG and MachineInstr scheduling. // //===----------------------------------------------------------------------===// @@ -18,33 +18,38 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/iterator.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetLowering.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <string> +#include <vector> namespace llvm { - class SUnit; - class MachineConstantPool; - class MachineFunction; - class MachineRegisterInfo; - class MachineInstr; - struct MCSchedClassDesc; - class TargetRegisterInfo; - class ScheduleDAG; - class SDNode; - class TargetInstrInfo; - class MCInstrDesc; - class TargetMachine; - class TargetRegisterClass; - template<class Graph> class GraphWriter; - - /// SDep - Scheduling dependency. This represents one direction of an - /// edge in the scheduling DAG. + +template<class Graph> class GraphWriter; +class MachineFunction; +class MachineRegisterInfo; +class MCInstrDesc; +struct MCSchedClassDesc; +class ScheduleDAG; +class SDNode; +class SUnit; +class TargetInstrInfo; +class TargetMachine; +class TargetRegisterClass; +class TargetRegisterInfo; + + /// Scheduling dependency. This represents one direction of an edge in the + /// scheduling DAG. class SDep { public: - /// Kind - These are the different kinds of scheduling dependencies. + /// These are the different kinds of scheduling dependencies. enum Kind { Data, ///< Regular data dependence (aka true-dependence). Anti, ///< A register anti-dependedence (aka WAR). @@ -71,33 +76,32 @@ namespace llvm { }; private: - /// Dep - A pointer to the depending/depended-on SUnit, and an enum + /// \brief A pointer to the depending/depended-on SUnit, and an enum /// indicating the kind of the dependency. PointerIntPair<SUnit *, 2, Kind> Dep; - /// Contents - A union discriminated by the dependence kind. + /// A union discriminated by the dependence kind. union { - /// Reg - For Data, Anti, and Output dependencies, the associated - /// register. For Data dependencies that don't currently have a register - /// assigned, this is set to zero. + /// For Data, Anti, and Output dependencies, the associated register. For + /// Data dependencies that don't currently have a register/ assigned, this + /// is set to zero. unsigned Reg; - /// Order - Additional information about Order dependencies. + /// Additional information about Order dependencies. unsigned OrdKind; // enum OrderKind } Contents; - /// Latency - The time associated with this edge. Often this is just - /// the value of the Latency field of the predecessor, however advanced - /// models may provide additional information about specific edges. + /// The time associated with this edge. Often this is just the value of the + /// Latency field of the predecessor, however advanced models may provide + /// additional information about specific edges. unsigned Latency; public: - /// SDep - Construct a null SDep. This is only for use by container - /// classes which require default constructors. SUnits may not - /// have null SDep edges. + /// Constructs a null SDep. This is only for use by container classes which + /// require default constructors. SUnits may not/ have null SDep edges. SDep() : Dep(nullptr, Data) {} - /// SDep - Construct an SDep with the specified values. + /// Constructs an SDep with the specified values. SDep(SUnit *S, Kind kind, unsigned Reg) : Dep(S, kind), Contents() { switch (kind) { @@ -116,12 +120,13 @@ namespace llvm { break; } } + SDep(SUnit *S, OrderKind kind) : Dep(S, Order), Contents(), Latency(0) { Contents.OrdKind = kind; } - /// Return true if the specified SDep is equivalent except for latency. + /// Returns true if the specified SDep is equivalent except for latency. bool overlaps(const SDep &Other) const; bool operator==(const SDep &Other) const { @@ -132,100 +137,95 @@ namespace llvm { return !operator==(Other); } - /// getLatency - Return the latency value for this edge, which roughly - /// means the minimum number of cycles that must elapse between the - /// predecessor and the successor, given that they have this edge - /// between them. + /// \brief Returns the latency value for this edge, which roughly means the + /// minimum number of cycles that must elapse between the predecessor and + /// the successor, given that they have this edge between them. unsigned getLatency() const { return Latency; } - /// setLatency - Set the latency for this edge. + /// Sets the latency for this edge. void setLatency(unsigned Lat) { Latency = Lat; } - //// getSUnit - Return the SUnit to which this edge points. + //// Returns the SUnit to which this edge points. SUnit *getSUnit() const; - //// setSUnit - Assign the SUnit to which this edge points. + //// Assigns the SUnit to which this edge points. void setSUnit(SUnit *SU); - /// getKind - Return an enum value representing the kind of the dependence. + /// Returns an enum value representing the kind of the dependence. Kind getKind() const; - /// isCtrl - Shorthand for getKind() != SDep::Data. + /// Shorthand for getKind() != SDep::Data. bool isCtrl() const { return getKind() != Data; } - /// isNormalMemory - Test if this is an Order dependence between two - /// memory accesses where both sides of the dependence access memory - /// in non-volatile and fully modeled ways. + /// \brief Tests if this is an Order dependence between two memory accesses + /// where both sides of the dependence access memory in non-volatile and + /// fully modeled ways. bool isNormalMemory() const { return getKind() == Order && (Contents.OrdKind == MayAliasMem || Contents.OrdKind == MustAliasMem); } - /// isBarrier - Test if this is an Order dependence that is marked - /// as a barrier. + /// Tests if this is an Order dependence that is marked as a barrier. bool isBarrier() const { return getKind() == Order && Contents.OrdKind == Barrier; } - /// isNormalMemoryOrBarrier - Test if this is could be any kind of memory - /// dependence. + /// Tests if this is could be any kind of memory dependence. bool isNormalMemoryOrBarrier() const { return (isNormalMemory() || isBarrier()); } - /// isMustAlias - Test if this is an Order dependence that is marked - /// as "must alias", meaning that the SUnits at either end of the edge - /// have a memory dependence on a known memory location. + /// \brief Tests if this is an Order dependence that is marked as + /// "must alias", meaning that the SUnits at either end of the edge have a + /// memory dependence on a known memory location. bool isMustAlias() const { return getKind() == Order && Contents.OrdKind == MustAliasMem; } - /// isWeak - Test if this a weak dependence. Weak dependencies are - /// considered DAG edges for height computation and other heuristics, but do - /// not force ordering. Breaking a weak edge may require the scheduler to - /// compensate, for example by inserting a copy. + /// Tests if this a weak dependence. Weak dependencies are considered DAG + /// edges for height computation and other heuristics, but do not force + /// ordering. Breaking a weak edge may require the scheduler to compensate, + /// for example by inserting a copy. bool isWeak() const { return getKind() == Order && Contents.OrdKind >= Weak; } - /// isArtificial - Test if this is an Order dependence that is marked - /// as "artificial", meaning it isn't necessary for correctness. + /// \brief Tests if this is an Order dependence that is marked as + /// "artificial", meaning it isn't necessary for correctness. bool isArtificial() const { return getKind() == Order && Contents.OrdKind == Artificial; } - /// isCluster - Test if this is an Order dependence that is marked - /// as "cluster", meaning it is artificial and wants to be adjacent. + /// \brief Tests if this is an Order dependence that is marked as "cluster", + /// meaning it is artificial and wants to be adjacent. bool isCluster() const { return getKind() == Order && Contents.OrdKind == Cluster; } - /// isAssignedRegDep - Test if this is a Data dependence that is - /// associated with a register. + /// Tests if this is a Data dependence that is associated with a register. bool isAssignedRegDep() const { return getKind() == Data && Contents.Reg != 0; } - /// getReg - Return the register associated with this edge. This is - /// only valid on Data, Anti, and Output edges. On Data edges, this - /// value may be zero, meaning there is no associated register. + /// Returns the register associated with this edge. This is only valid on + /// Data, Anti, and Output edges. On Data edges, this value may be zero, + /// meaning there is no associated register. unsigned getReg() const { assert((getKind() == Data || getKind() == Anti || getKind() == Output) && "getReg called on non-register dependence edge!"); return Contents.Reg; } - /// setReg - Assign the associated register for this edge. This is - /// only valid on Data, Anti, and Output edges. On Anti and Output - /// edges, this value must not be zero. On Data edges, the value may - /// be zero, which would mean that no specific register is associated - /// with this edge. + /// Assigns the associated register for this edge. This is only valid on + /// Data, Anti, and Output edges. On Anti and Output edges, this value must + /// not be zero. On Data edges, the value may be zero, which would mean that + /// no specific register is associated with this edge. void setReg(unsigned Reg) { assert((getKind() == Data || getKind() == Anti || getKind() == Output) && "setReg called on non-register dependence edge!"); @@ -240,115 +240,101 @@ namespace llvm { template <> struct isPodLike<SDep> { static const bool value = true; }; - /// SUnit - Scheduling unit. This is a node in the scheduling DAG. + /// Scheduling unit. This is a node in the scheduling DAG. class SUnit { private: enum : unsigned { BoundaryID = ~0u }; - SDNode *Node; // Representative node. - MachineInstr *Instr; // Alternatively, a MachineInstr. + SDNode *Node = nullptr; ///< Representative node. + MachineInstr *Instr = nullptr; ///< Alternatively, a MachineInstr. + public: - SUnit *OrigNode; // If not this, the node from which - // this node was cloned. - // (SD scheduling only) + SUnit *OrigNode = nullptr; ///< If not this, the node from which this node + /// was cloned. (SD scheduling only) - const MCSchedClassDesc *SchedClass; // NULL or resolved SchedClass. + const MCSchedClassDesc *SchedClass = + nullptr; ///< nullptr or resolved SchedClass. - // Preds/Succs - The SUnits before/after us in the graph. - SmallVector<SDep, 4> Preds; // All sunit predecessors. - SmallVector<SDep, 4> Succs; // All sunit successors. + SmallVector<SDep, 4> Preds; ///< All sunit predecessors. + SmallVector<SDep, 4> Succs; ///< All sunit successors. typedef SmallVectorImpl<SDep>::iterator pred_iterator; typedef SmallVectorImpl<SDep>::iterator succ_iterator; typedef SmallVectorImpl<SDep>::const_iterator const_pred_iterator; typedef SmallVectorImpl<SDep>::const_iterator const_succ_iterator; - unsigned NodeNum; // Entry # of node in the node vector. - unsigned NodeQueueId; // Queue id of node. - unsigned NumPreds; // # of SDep::Data preds. - unsigned NumSuccs; // # of SDep::Data sucss. - unsigned NumPredsLeft; // # of preds not scheduled. - unsigned NumSuccsLeft; // # of succs not scheduled. - unsigned WeakPredsLeft; // # of weak preds not scheduled. - unsigned WeakSuccsLeft; // # of weak succs not scheduled. - unsigned short NumRegDefsLeft; // # of reg defs with no scheduled use. - unsigned short Latency; // Node latency. - bool isVRegCycle : 1; // May use and def the same vreg. - bool isCall : 1; // Is a function call. - bool isCallOp : 1; // Is a function call operand. - bool isTwoAddress : 1; // Is a two-address instruction. - bool isCommutable : 1; // Is a commutable instruction. - bool hasPhysRegUses : 1; // Has physreg uses. - bool hasPhysRegDefs : 1; // Has physreg defs that are being used. - bool hasPhysRegClobbers : 1; // Has any physreg defs, used or not. - bool isPending : 1; // True once pending. - bool isAvailable : 1; // True once available. - bool isScheduled : 1; // True once scheduled. - bool isScheduleHigh : 1; // True if preferable to schedule high. - bool isScheduleLow : 1; // True if preferable to schedule low. - bool isCloned : 1; // True if this node has been cloned. - bool isUnbuffered : 1; // Uses an unbuffered resource. - bool hasReservedResource : 1; // Uses a reserved resource. - Sched::Preference SchedulingPref; // Scheduling preference. + unsigned NodeNum = BoundaryID; ///< Entry # of node in the node vector. + unsigned NodeQueueId = 0; ///< Queue id of node. + unsigned NumPreds = 0; ///< # of SDep::Data preds. + unsigned NumSuccs = 0; ///< # of SDep::Data sucss. + unsigned NumPredsLeft = 0; ///< # of preds not scheduled. + unsigned NumSuccsLeft = 0; ///< # of succs not scheduled. + unsigned WeakPredsLeft = 0; ///< # of weak preds not scheduled. + unsigned WeakSuccsLeft = 0; ///< # of weak succs not scheduled. + unsigned short NumRegDefsLeft = 0; ///< # of reg defs with no scheduled use. + unsigned short Latency = 0; ///< Node latency. + bool isVRegCycle : 1; ///< May use and def the same vreg. + bool isCall : 1; ///< Is a function call. + bool isCallOp : 1; ///< Is a function call operand. + bool isTwoAddress : 1; ///< Is a two-address instruction. + bool isCommutable : 1; ///< Is a commutable instruction. + bool hasPhysRegUses : 1; ///< Has physreg uses. + bool hasPhysRegDefs : 1; ///< Has physreg defs that are being used. + bool hasPhysRegClobbers : 1; ///< Has any physreg defs, used or not. + bool isPending : 1; ///< True once pending. + bool isAvailable : 1; ///< True once available. + bool isScheduled : 1; ///< True once scheduled. + bool isScheduleHigh : 1; ///< True if preferable to schedule high. + bool isScheduleLow : 1; ///< True if preferable to schedule low. + bool isCloned : 1; ///< True if this node has been cloned. + bool isUnbuffered : 1; ///< Uses an unbuffered resource. + bool hasReservedResource : 1; ///< Uses a reserved resource. + Sched::Preference SchedulingPref = Sched::None; ///< Scheduling preference. private: - bool isDepthCurrent : 1; // True if Depth is current. - bool isHeightCurrent : 1; // True if Height is current. - unsigned Depth; // Node depth. - unsigned Height; // Node height. + bool isDepthCurrent : 1; ///< True if Depth is current. + bool isHeightCurrent : 1; ///< True if Height is current. + unsigned Depth = 0; ///< Node depth. + unsigned Height = 0; ///< Node height. + public: - unsigned TopReadyCycle; // Cycle relative to start when node is ready. - unsigned BotReadyCycle; // Cycle relative to end when node is ready. + unsigned TopReadyCycle = 0; ///< Cycle relative to start when node is ready. + unsigned BotReadyCycle = 0; ///< Cycle relative to end when node is ready. - const TargetRegisterClass *CopyDstRC; // Is a special copy node if not null. - const TargetRegisterClass *CopySrcRC; + const TargetRegisterClass *CopyDstRC = + nullptr; ///< Is a special copy node if != nullptr. + const TargetRegisterClass *CopySrcRC = nullptr; - /// SUnit - Construct an SUnit for pre-regalloc scheduling to represent - /// an SDNode and any nodes flagged to it. + /// \brief Constructs an SUnit for pre-regalloc scheduling to represent an + /// SDNode and any nodes flagged to it. SUnit(SDNode *node, unsigned nodenum) - : Node(node), Instr(nullptr), OrigNode(nullptr), SchedClass(nullptr), - NodeNum(nodenum), NodeQueueId(0), NumPreds(0), NumSuccs(0), - NumPredsLeft(0), NumSuccsLeft(0), WeakPredsLeft(0), WeakSuccsLeft(0), - NumRegDefsLeft(0), Latency(0), isVRegCycle(false), isCall(false), + : Node(node), NodeNum(nodenum), isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false), isCommutable(false), hasPhysRegUses(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isScheduleLow(false), isCloned(false), - isUnbuffered(false), hasReservedResource(false), - SchedulingPref(Sched::None), isDepthCurrent(false), - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0), - BotReadyCycle(0), CopyDstRC(nullptr), CopySrcRC(nullptr) {} + isUnbuffered(false), hasReservedResource(false), isDepthCurrent(false), + isHeightCurrent(false) {} - /// SUnit - Construct an SUnit for post-regalloc scheduling to represent - /// a MachineInstr. + /// \brief Constructs an SUnit for post-regalloc scheduling to represent a + /// MachineInstr. SUnit(MachineInstr *instr, unsigned nodenum) - : Node(nullptr), Instr(instr), OrigNode(nullptr), SchedClass(nullptr), - NodeNum(nodenum), NodeQueueId(0), NumPreds(0), NumSuccs(0), - NumPredsLeft(0), NumSuccsLeft(0), WeakPredsLeft(0), WeakSuccsLeft(0), - NumRegDefsLeft(0), Latency(0), isVRegCycle(false), isCall(false), + : Instr(instr), NodeNum(nodenum), isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false), isCommutable(false), hasPhysRegUses(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isScheduleLow(false), isCloned(false), - isUnbuffered(false), hasReservedResource(false), - SchedulingPref(Sched::None), isDepthCurrent(false), - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0), - BotReadyCycle(0), CopyDstRC(nullptr), CopySrcRC(nullptr) {} + isUnbuffered(false), hasReservedResource(false), isDepthCurrent(false), + isHeightCurrent(false) {} - /// SUnit - Construct a placeholder SUnit. + /// \brief Constructs a placeholder SUnit. SUnit() - : Node(nullptr), Instr(nullptr), OrigNode(nullptr), SchedClass(nullptr), - NodeNum(BoundaryID), NodeQueueId(0), NumPreds(0), NumSuccs(0), - NumPredsLeft(0), NumSuccsLeft(0), WeakPredsLeft(0), WeakSuccsLeft(0), - NumRegDefsLeft(0), Latency(0), isVRegCycle(false), isCall(false), - isCallOp(false), isTwoAddress(false), isCommutable(false), - hasPhysRegUses(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), - isPending(false), isAvailable(false), isScheduled(false), - isScheduleHigh(false), isScheduleLow(false), isCloned(false), - isUnbuffered(false), hasReservedResource(false), - SchedulingPref(Sched::None), isDepthCurrent(false), - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0), - BotReadyCycle(0), CopyDstRC(nullptr), CopySrcRC(nullptr) {} + : isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false), + isCommutable(false), hasPhysRegUses(false), hasPhysRegDefs(false), + hasPhysRegClobbers(false), isPending(false), isAvailable(false), + isScheduled(false), isScheduleHigh(false), isScheduleLow(false), + isCloned(false), isUnbuffered(false), hasReservedResource(false), + isDepthCurrent(false), isHeightCurrent(false) {} /// \brief Boundary nodes are placeholders for the boundary of the /// scheduling region. @@ -359,46 +345,44 @@ namespace llvm { /// an assoicative data structure keyed on node ID. bool isBoundaryNode() const { return NodeNum == BoundaryID; } - /// setNode - Assign the representative SDNode for this SUnit. - /// This may be used during pre-regalloc scheduling. + /// Assigns the representative SDNode for this SUnit. This may be used + /// during pre-regalloc scheduling. void setNode(SDNode *N) { assert(!Instr && "Setting SDNode of SUnit with MachineInstr!"); Node = N; } - /// getNode - Return the representative SDNode for this SUnit. - /// This may be used during pre-regalloc scheduling. + /// Returns the representative SDNode for this SUnit. This may be used + /// during pre-regalloc scheduling. SDNode *getNode() const { assert(!Instr && "Reading SDNode of SUnit with MachineInstr!"); return Node; } - /// isInstr - Return true if this SUnit refers to a machine instruction as + /// \brief Returns true if this SUnit refers to a machine instruction as /// opposed to an SDNode. bool isInstr() const { return Instr; } - /// setInstr - Assign the instruction for the SUnit. - /// This may be used during post-regalloc scheduling. + /// Assigns the instruction for the SUnit. This may be used during + /// post-regalloc scheduling. void setInstr(MachineInstr *MI) { assert(!Node && "Setting MachineInstr of SUnit with SDNode!"); Instr = MI; } - /// getInstr - Return the representative MachineInstr for this SUnit. - /// This may be used during post-regalloc scheduling. + /// Returns the representative MachineInstr for this SUnit. This may be used + /// during post-regalloc scheduling. MachineInstr *getInstr() const { assert(!Node && "Reading MachineInstr of SUnit with SDNode!"); return Instr; } - /// addPred - This adds the specified edge as a pred of the current node if - /// not already. It also adds the current node as a successor of the - /// specified node. + /// Adds the specified edge as a pred of the current node if not already. + /// It also adds the current node as a successor of the 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. + /// \brief 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 = @@ -407,20 +391,19 @@ namespace llvm { 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. + /// 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. void removePred(const SDep &D); - /// getDepth - Return the depth of this node, which is the length of the - /// maximum path up to any node which has no predecessors. + /// Returns the depth of this node, which is the length of the maximum path + /// up to any node which has no predecessors. unsigned getDepth() const { if (!isDepthCurrent) const_cast<SUnit *>(this)->ComputeDepth(); return Depth; } - /// getHeight - Return the height of this node, which is the length of the + /// \brief Returns the height of this node, which is the length of the /// maximum path down to any node which has no successors. unsigned getHeight() const { if (!isHeightCurrent) @@ -428,38 +411,36 @@ namespace llvm { return Height; } - /// setDepthToAtLeast - If NewDepth is greater than this node's - /// depth value, set it to be the new depth value. This also - /// recursively marks successor nodes dirty. + /// \brief If NewDepth is greater than this node's depth value, sets it to + /// be the new depth value. This also recursively marks successor nodes + /// dirty. void setDepthToAtLeast(unsigned NewDepth); - /// setDepthToAtLeast - If NewDepth is greater than this node's - /// depth value, set it to be the new height value. This also - /// recursively marks predecessor nodes dirty. + /// \brief If NewDepth is greater than this node's depth value, set it to be + /// the new height value. This also recursively marks predecessor nodes + /// dirty. void setHeightToAtLeast(unsigned NewHeight); - /// setDepthDirty - Set a flag in this node to indicate that its - /// stored Depth value will require recomputation the next time - /// getDepth() is called. + /// \brief Sets a flag in this node to indicate that its stored Depth value + /// will require recomputation the next time getDepth() is called. void setDepthDirty(); - /// setHeightDirty - Set a flag in this node to indicate that its - /// stored Height value will require recomputation the next time - /// getHeight() is called. + /// \brief Sets a flag in this node to indicate that its stored Height value + /// will require recomputation the next time getHeight() is called. void setHeightDirty(); - /// isPred - Test if node N is a predecessor of this node. - bool isPred(SUnit *N) { - for (unsigned i = 0, e = (unsigned)Preds.size(); i != e; ++i) - if (Preds[i].getSUnit() == N) + /// Tests if node N is a predecessor of this node. + bool isPred(const SUnit *N) const { + for (const SDep &Pred : Preds) + if (Pred.getSUnit() == N) return true; return false; } - /// isSucc - Test if node N is a successor of this node. - bool isSucc(SUnit *N) { - for (unsigned i = 0, e = (unsigned)Succs.size(); i != e; ++i) - if (Succs[i].getSUnit() == N) + /// Tests if node N is a successor of this node. + bool isSucc(const SUnit *N) const { + for (const SDep &Succ : Succs) + if (Succ.getSUnit() == N) return true; return false; } @@ -471,7 +452,7 @@ namespace llvm { return NumSuccsLeft == 0; } - /// \brief Order this node's predecessor edges such that the critical path + /// \brief Orders this node's predecessor edges such that the critical path /// edge occurs first. void biasCriticalPath(); @@ -484,7 +465,7 @@ namespace llvm { void ComputeHeight(); }; - /// Return true if the specified SDep is equivalent except for latency. + /// Returns true if the specified SDep is equivalent except for latency. inline bool SDep::overlaps(const SDep &Other) const { if (Dep != Other.Dep) return false; @@ -499,31 +480,33 @@ namespace llvm { llvm_unreachable("Invalid dependency kind!"); } - //// getSUnit - Return the SUnit to which this edge points. + //// Returns the SUnit to which this edge points. inline SUnit *SDep::getSUnit() const { return Dep.getPointer(); } - //// setSUnit - Assign the SUnit to which this edge points. + //// Assigns the SUnit to which this edge points. inline void SDep::setSUnit(SUnit *SU) { Dep.setPointer(SU); } - /// getKind - Return an enum value representing the kind of the dependence. + /// Returns an enum value representing the kind of the dependence. inline SDep::Kind SDep::getKind() const { return Dep.getInt(); } //===--------------------------------------------------------------------===// - /// SchedulingPriorityQueue - This interface is used to plug different - /// priorities computation algorithms into the list scheduler. It implements - /// the interface of a standard priority queue, where nodes are inserted in - /// arbitrary order and returned in priority order. The computation of the - /// priority and the representation of the queue are totally up to the - /// implementation to decide. - /// + + /// \brief This interface is used to plug different priorities computation + /// algorithms into the list scheduler. It implements the interface of a + /// standard priority queue, where nodes are inserted in arbitrary order and + /// returned in priority order. The computation of the priority and the + /// representation of the queue are totally up to the implementation to + /// decide. class SchedulingPriorityQueue { virtual void anchor(); - unsigned CurCycle; + + unsigned CurCycle = 0; bool HasReadyFilter; + public: - SchedulingPriorityQueue(bool rf = false): - CurCycle(0), HasReadyFilter(rf) {} - virtual ~SchedulingPriorityQueue() {} + SchedulingPriorityQueue(bool rf = false) : HasReadyFilter(rf) {} + + virtual ~SchedulingPriorityQueue() = default; virtual bool isBottomUp() const = 0; @@ -542,6 +525,7 @@ namespace llvm { assert(!HasReadyFilter && "The ready filter must override isReady()"); return true; } + virtual void push(SUnit *U) = 0; void push_all(const std::vector<SUnit *> &Nodes) { @@ -556,10 +540,9 @@ namespace llvm { virtual void dump(ScheduleDAG *) const {} - /// scheduledNode - As each node is scheduled, this method is invoked. This - /// allows the priority function to adjust the priority of related - /// unscheduled nodes, for example. - /// + /// As each node is scheduled, this method is invoked. This allows the + /// priority function to adjust the priority of related unscheduled nodes, + /// for example. virtual void scheduledNode(SUnit *) {} virtual void unscheduledNode(SUnit *) {} @@ -575,14 +558,14 @@ namespace llvm { class ScheduleDAG { public: - const TargetMachine &TM; // Target processor - const TargetInstrInfo *TII; // Target instruction information - const TargetRegisterInfo *TRI; // Target processor register info - MachineFunction &MF; // Machine function - MachineRegisterInfo &MRI; // Virtual/real register map - std::vector<SUnit> SUnits; // The scheduling units. - SUnit EntrySU; // Special node for the region entry. - SUnit ExitSU; // Special node for the region exit. + const TargetMachine &TM; ///< Target processor + const TargetInstrInfo *TII; ///< Target instruction information + const TargetRegisterInfo *TRI; ///< Target processor register info + MachineFunction &MF; ///< Machine function + MachineRegisterInfo &MRI; ///< Virtual/real register map + std::vector<SUnit> SUnits; ///< The scheduling units. + SUnit EntrySU; ///< Special node for the region entry. + SUnit ExitSU; ///< Special node for the region exit. #ifdef NDEBUG static const bool StressSched = false; @@ -594,43 +577,39 @@ namespace llvm { virtual ~ScheduleDAG(); - /// clearDAG - clear the DAG state (between regions). + /// Clears the DAG state (between regions). void clearDAG(); - /// getInstrDesc - Return the MCInstrDesc of this SUnit. - /// Return NULL for SDNodes without a machine opcode. + /// Returns the MCInstrDesc of this SUnit. + /// Returns NULL for SDNodes without a machine opcode. const MCInstrDesc *getInstrDesc(const SUnit *SU) const { if (SU->isInstr()) return &SU->getInstr()->getDesc(); return getNodeDesc(SU->getNode()); } - /// viewGraph - Pop up a GraphViz/gv window with the ScheduleDAG rendered - /// using 'dot'. - /// + /// Pops up a GraphViz/gv window with the ScheduleDAG rendered using 'dot'. virtual void viewGraph(const Twine &Name, const Twine &Title); virtual void viewGraph(); virtual void dumpNode(const SUnit *SU) const = 0; - /// getGraphNodeLabel - Return a label for an SUnit node in a visualization - /// of the ScheduleDAG. + /// Returns a label for an SUnit node in a visualization of the ScheduleDAG. virtual std::string getGraphNodeLabel(const SUnit *SU) const = 0; - /// getDAGLabel - Return a label for the region of code covered by the DAG. + /// Returns a label for the region of code covered by the DAG. virtual std::string getDAGName() const = 0; - /// addCustomGraphFeatures - Add custom features for a visualization of - /// the ScheduleDAG. + /// Adds custom features for a visualization of the ScheduleDAG. virtual void addCustomGraphFeatures(GraphWriter<ScheduleDAG*> &) const {} #ifndef NDEBUG - /// VerifyScheduledDAG - Verify that all SUnits were scheduled and that - /// their state is consistent. Return the number of scheduled SUnits. + /// \brief Verifies that all SUnits were scheduled and that their state is + /// consistent. Returns the number of scheduled SUnits. unsigned VerifyScheduledDAG(bool isBottomUp); #endif private: - // Return the MCInstrDesc of this SDNode or NULL. + /// Returns the MCInstrDesc of this SDNode or NULL. const MCInstrDesc *getNodeDesc(const SDNode *Node) const; }; @@ -640,6 +619,7 @@ namespace llvm { unsigned Operand; SUnitIterator(SUnit *N, unsigned Op) : Node(N), Operand(Op) {} + public: bool operator==(const SUnitIterator& x) const { return Operand == x.Operand; @@ -666,7 +646,8 @@ namespace llvm { unsigned getOperand() const { return Operand; } const SUnit *getNode() const { return Node; } - /// isCtrlDep - Test if this is not an SDep::Data dependence. + + /// Tests if this is not an SDep::Data dependence. bool isCtrlDep() const { return getSDep().isCtrl(); } @@ -700,56 +681,61 @@ namespace llvm { } }; - /// ScheduleDAGTopologicalSort is a class that computes a topological - /// ordering for SUnits and provides methods for dynamically updating - /// the ordering as new edges are added. + /// This class can compute a topological ordering for SUnits and provides + /// methods for dynamically updating the ordering as new edges are added. /// /// This allows a very fast implementation of IsReachable, for example. - /// class ScheduleDAGTopologicalSort { - /// SUnits - A reference to the ScheduleDAG's SUnits. + /// A reference to the ScheduleDAG's SUnits. std::vector<SUnit> &SUnits; SUnit *ExitSU; - /// Index2Node - Maps topological index to the node number. + /// Maps topological index to the node number. std::vector<int> Index2Node; - /// Node2Index - Maps the node number to its topological index. + /// Maps the node number to its topological index. std::vector<int> Node2Index; - /// Visited - a set of nodes visited during a DFS traversal. + /// a set of nodes visited during a DFS traversal. BitVector Visited; - /// DFS - make a DFS traversal and mark all nodes affected by the - /// edge insertion. These nodes will later get new topological indexes - /// by means of the Shift method. + /// Makes a DFS traversal and mark all nodes affected by the edge insertion. + /// These nodes will later get new topological indexes by means of the Shift + /// method. void DFS(const SUnit *SU, int UpperBound, bool& HasLoop); - /// Shift - reassign topological indexes for the nodes in the DAG - /// to preserve the topological ordering. + /// \brief Reassigns topological indexes for the nodes in the DAG to + /// preserve the topological ordering. void Shift(BitVector& Visited, int LowerBound, int UpperBound); - /// Allocate - assign the topological index to the node n. + /// Assigns the topological index to the node n. void Allocate(int n, int index); public: ScheduleDAGTopologicalSort(std::vector<SUnit> &SUnits, SUnit *ExitSU); - /// InitDAGTopologicalSorting - create the initial topological - /// ordering from the DAG to be scheduled. + /// Creates the initial topological ordering from the DAG to be scheduled. void InitDAGTopologicalSorting(); - /// IsReachable - Checks if SU is reachable from TargetSU. + /// Returns an array of SUs that are both in the successor + /// subtree of StartSU and in the predecessor subtree of TargetSU. + /// StartSU and TargetSU are not in the array. + /// Success is false if TargetSU is not in the successor subtree of + /// StartSU, else it is true. + std::vector<int> GetSubGraph(const SUnit &StartSU, const SUnit &TargetSU, + bool &Success); + + /// Checks if \p SU is reachable from \p TargetSU. bool IsReachable(const SUnit *SU, const SUnit *TargetSU); - /// WillCreateCycle - Return true if addPred(TargetSU, SU) creates a cycle. + /// Returns true if addPred(TargetSU, SU) creates a cycle. bool WillCreateCycle(SUnit *TargetSU, SUnit *SU); - /// AddPred - Updates the topological ordering to accommodate an edge - /// to be added from SUnit X to SUnit Y. + /// \brief Updates the topological ordering to accommodate an edge to be + /// added from SUnit \p X to SUnit \p Y. void AddPred(SUnit *Y, SUnit *X); - /// RemovePred - Updates the topological ordering to accommodate an - /// an edge to be removed from the specified node N from the predecessors - /// of the current node M. + /// \brief Updates the topological ordering to accommodate an an edge to be + /// removed from the specified node \p N from the predecessors of the + /// current node \p M. void RemovePred(SUnit *M, SUnit *N); typedef std::vector<int>::iterator iterator; @@ -766,6 +752,7 @@ namespace llvm { reverse_iterator rend() { return Index2Node.rend(); } const_reverse_iterator rend() const { return Index2Node.rend(); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_CODEGEN_SCHEDULEDAG_H diff --git a/include/llvm/CodeGen/ScheduleDAGInstrs.h b/include/llvm/CodeGen/ScheduleDAGInstrs.h index 2746765f6e45..21e1740aa6b8 100644 --- a/include/llvm/CodeGen/ScheduleDAGInstrs.h +++ b/include/llvm/CodeGen/ScheduleDAGInstrs.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements the ScheduleDAGInstrs class, which implements -// scheduling for a MachineInstr-based dependency graph. +/// \file Implements the ScheduleDAGInstrs class, which implements scheduling +/// for a MachineInstr-based dependency graph. // //===----------------------------------------------------------------------===// @@ -95,8 +95,7 @@ namespace llvm { }; typedef SmallVector<UnderlyingObject, 4> UnderlyingObjectsVector; - /// ScheduleDAGInstrs - A ScheduleDAG subclass for scheduling lists of - /// MachineInstrs. + /// A ScheduleDAG for scheduling lists of MachineInstr. class ScheduleDAGInstrs : public ScheduleDAG { protected: const MachineLoopInfo *MLI; @@ -119,8 +118,8 @@ namespace llvm { /// Whether lane masks should get tracked. bool TrackLaneMasks; - /// State specific to the current scheduling region. - /// ------------------------------------------------ + // State specific to the current scheduling region. + // ------------------------------------------------ /// The block in which to insert instructions MachineBasicBlock *BB; @@ -138,8 +137,8 @@ namespace llvm { /// scheduling region is mapped to an SUnit. DenseMap<MachineInstr*, SUnit*> MISUnitMap; - /// State internal to DAG building. - /// ------------------------------- + // State internal to DAG building. + // ------------------------------- /// Defs, Uses - Remember where defs and uses of each register are as we /// iterate upward through the instructions. This is allocated here instead @@ -163,64 +162,64 @@ namespace llvm { 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. + /// \brief 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. + /// Reduces maps in FIFO order, by N SUs. This is better than turning + /// every Nth memory SU into BarrierChain in buildSchedGraph(), since + /// it avoids unnecessary edges between seen SUs above the new BarrierChain, + /// and those below it. 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. + /// \brief Adds 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); + /// Adds dependencies as needed from all SUs in list to SU. + void addChainDependencies(SUnit *SU, SUList &SUs, unsigned Latency) { + for (SUnit *Entry : SUs) + addChainDependency(SU, Entry, Latency); } - /// Add dependencies as needed from all SUs in map, to SU. + /// Adds 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. + /// Adds 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. + /// Adds 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. + /// Inserts a barrier chain in a huge region, far below current SU. + /// Adds 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. + typedef std::vector<std::pair<MachineInstr *, MachineInstr *>> + DbgValueVector; + /// Remember instruction that precedes DBG_VALUE. /// These are generated by buildSchedGraph but persist so they can be /// referenced when emitting the final schedule. - typedef std::vector<std::pair<MachineInstr *, MachineInstr *> > - DbgValueVector; DbgValueVector DbgValues; MachineInstr *FirstDbgValue; @@ -234,81 +233,86 @@ namespace llvm { ~ScheduleDAGInstrs() override {} - /// \brief Get the machine model for instruction scheduling. + /// Gets the machine model for instruction scheduling. const TargetSchedModel *getSchedModel() const { return &SchedModel; } - /// \brief Resolve and cache a resolved scheduling class for an SUnit. + /// Resolves and cache a resolved scheduling class for an SUnit. const MCSchedClassDesc *getSchedClass(SUnit *SU) const { if (!SU->SchedClass && SchedModel.hasInstrSchedModel()) SU->SchedClass = SchedModel.resolveSchedClass(SU->getInstr()); return SU->SchedClass; } - /// begin - Return an iterator to the top of the current scheduling region. + /// Returns an iterator to the top of the current scheduling region. MachineBasicBlock::iterator begin() const { return RegionBegin; } - /// end - Return an iterator to the bottom of the current scheduling region. + /// Returns an iterator to the bottom of the current scheduling region. MachineBasicBlock::iterator end() const { return RegionEnd; } - /// newSUnit - Creates a new SUnit and return a ptr to it. + /// Creates a new SUnit and return a ptr to it. SUnit *newSUnit(MachineInstr *MI); - /// getSUnit - Return an existing SUnit for this MI, or NULL. + /// Returns an existing SUnit for this MI, or nullptr. SUnit *getSUnit(MachineInstr *MI) const; - /// startBlock - Prepare to perform scheduling in the given block. + /// Prepares to perform scheduling in the given block. virtual void startBlock(MachineBasicBlock *BB); - /// finishBlock - Clean up after scheduling in the given block. + /// Cleans up after scheduling in the given block. virtual void finishBlock(); - /// Initialize the scheduler state for the next scheduling region. + /// \brief Initialize the DAG and common scheduler state for a new + /// scheduling region. This does not actually create the DAG, only clears + /// it. The scheduling driver may call BuildSchedGraph multiple times per + /// scheduling region. virtual void enterRegion(MachineBasicBlock *bb, MachineBasicBlock::iterator begin, MachineBasicBlock::iterator end, unsigned regioninstrs); - /// Notify that the scheduler has finished scheduling the current region. + /// Called when the scheduler has finished scheduling the current region. virtual void exitRegion(); - /// buildSchedGraph - Build SUnits from the MachineBasicBlock that we are - /// input. + /// Builds SUnits for the current region. + /// If \p RPTracker is non-null, compute register pressure as a side effect. + /// The DAG builder is an efficient place to do it because it already visits + /// operands. void buildSchedGraph(AliasAnalysis *AA, RegPressureTracker *RPTracker = nullptr, PressureDiffs *PDiffs = nullptr, LiveIntervals *LIS = nullptr, bool TrackLaneMasks = false); - /// addSchedBarrierDeps - Add dependencies from instructions in the current - /// list of instructions being scheduled to scheduling barrier. We want to - /// make sure instructions which define registers that are either used by - /// the terminator or are live-out are properly scheduled. This is - /// especially important when the definition latency of the return value(s) - /// are too high to be hidden by the branch or when the liveout registers - /// used by instructions in the fallthrough block. + /// \brief Adds dependencies from instructions in the current list of + /// instructions being scheduled to scheduling barrier. We want to make sure + /// instructions which define registers that are either used by the + /// terminator or are live-out are properly scheduled. This is especially + /// important when the definition latency of the return value(s) are too + /// high to be hidden by the branch or when the liveout registers used by + /// instructions in the fallthrough block. void addSchedBarrierDeps(); - /// schedule - Order nodes according to selected style, filling - /// in the Sequence member. + /// Orders nodes according to selected style. /// /// Typically, a scheduling algorithm will implement schedule() without /// overriding enterRegion() or exitRegion(). virtual void schedule() = 0; - /// finalizeSchedule - Allow targets to perform final scheduling actions at - /// the level of the whole MachineFunction. By default does nothing. + /// Allow targets to perform final scheduling actions at the level of the + /// whole MachineFunction. By default does nothing. virtual void finalizeSchedule() {} void dumpNode(const SUnit *SU) const override; - /// Return a label for a DAG node that points to an instruction. + /// Returns a label for a DAG node that points to an instruction. std::string getGraphNodeLabel(const SUnit *SU) const override; - /// Return a label for the region of code covered by the DAG. + /// Returns a label for the region of code covered by the DAG. std::string getDAGName() const override; - /// \brief Fix register kill flags that scheduling has made invalid. + /// Fixes register kill flags that scheduling has made invalid. void fixupKills(MachineBasicBlock *MBB); + protected: void initSUnits(); void addPhysRegDataDeps(SUnit *SU, unsigned OperIdx); @@ -316,21 +320,22 @@ namespace llvm { void addVRegDefDeps(SUnit *SU, unsigned OperIdx); void addVRegUseDeps(SUnit *SU, unsigned OperIdx); - /// \brief PostRA helper for rewriting kill flags. + /// Initializes register live-range state for updating kills. + /// PostRA helper for rewriting kill flags. void startBlockForKills(MachineBasicBlock *BB); - /// \brief Toggle a register operand kill flag. + /// Toggles a register operand kill flag. /// /// Other adjustments may be made to the instruction if necessary. Return /// true if the operand has been deleted, false if not. - bool toggleKillFlag(MachineInstr *MI, MachineOperand &MO); + void toggleKillFlag(MachineInstr &MI, MachineOperand &MO); /// Returns a mask for which lanes get read/written by the given (register) /// machine operand. LaneBitmask getLaneMaskForMO(const MachineOperand &MO) const; }; - /// newSUnit - Creates a new SUnit and return a ptr to it. + /// Creates a new SUnit and return a ptr to it. inline SUnit *ScheduleDAGInstrs::newSUnit(MachineInstr *MI) { #ifndef NDEBUG const SUnit *Addr = SUnits.empty() ? nullptr : &SUnits[0]; @@ -341,13 +346,13 @@ namespace llvm { return &SUnits.back(); } - /// getSUnit - Return an existing SUnit for this MI, or NULL. + /// Returns an existing SUnit for this MI, or nullptr. inline SUnit *ScheduleDAGInstrs::getSUnit(MachineInstr *MI) const { DenseMap<MachineInstr*, SUnit*>::const_iterator I = MISUnitMap.find(MI); if (I == MISUnitMap.end()) return nullptr; return I->second; } -} // namespace llvm +} // end namespace llvm #endif diff --git a/include/llvm/CodeGen/ScheduleDAGMutation.h b/include/llvm/CodeGen/ScheduleDAGMutation.h index 02fe2294815c..5c236427e0b8 100644 --- a/include/llvm/CodeGen/ScheduleDAGMutation.h +++ b/include/llvm/CodeGen/ScheduleDAGMutation.h @@ -1,4 +1,4 @@ -//==- ScheduleDAGMutation.h - MachineInstr Scheduling ------------*- C++ -*-==// +//===- ScheduleDAGMutation.h - MachineInstr Scheduling ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,16 +16,19 @@ #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() {} +class ScheduleDAGInstrs; - virtual void apply(ScheduleDAGInstrs *DAG) = 0; - }; -} +/// Mutate the DAG as a postpass after normal DAG building. +class ScheduleDAGMutation { + virtual void anchor(); -#endif +public: + virtual ~ScheduleDAGMutation() = default; + + virtual void apply(ScheduleDAGInstrs *DAG) = 0; +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_SCHEDULEDAGMUTATION_H diff --git a/include/llvm/CodeGen/ScheduleDFS.h b/include/llvm/CodeGen/ScheduleDFS.h index b2108ad3bedb..c2013661cfff 100644 --- a/include/llvm/CodeGen/ScheduleDFS.h +++ b/include/llvm/CodeGen/ScheduleDFS.h @@ -14,16 +14,16 @@ #ifndef LLVM_CODEGEN_SCHEDULEDFS_H #define LLVM_CODEGEN_SCHEDULEDFS_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/ScheduleDAG.h" -#include "llvm/Support/DataTypes.h" #include <vector> +#include <cassert> +#include <cstdint> namespace llvm { class raw_ostream; -class IntEqClasses; -class ScheduleDAGInstrs; -class SUnit; /// \brief Represent the ILP of the subDAG rooted at a DAG node. /// @@ -75,18 +75,18 @@ class SchedDFSResult { /// interior node. Finally, it is set to a representative subtree ID during /// finalization. struct NodeData { - unsigned InstrCount; - unsigned SubtreeID; + unsigned InstrCount = 0; + unsigned SubtreeID = InvalidSubtreeID; - NodeData(): InstrCount(0), SubtreeID(InvalidSubtreeID) {} + NodeData() = default; }; /// \brief Per-Subtree data computed during DFS. struct TreeData { - unsigned ParentTreeID; - unsigned SubInstrCount; + unsigned ParentTreeID = InvalidSubtreeID; + unsigned SubInstrCount = 0; - TreeData(): ParentTreeID(InvalidSubtreeID), SubInstrCount(0) {} + TreeData() = default; }; /// \brief Record a connection between subtrees and the connection level. @@ -107,7 +107,7 @@ class SchedDFSResult { // For each subtree discovered during DFS, record its connections to other // subtrees. - std::vector<SmallVector<Connection, 4> > SubtreeConnections; + std::vector<SmallVector<Connection, 4>> SubtreeConnections; /// Cache the current connection level of each subtree. /// This mutable array is updated during scheduling. @@ -189,6 +189,6 @@ public: raw_ostream &operator<<(raw_ostream &OS, const ILPValue &Val); -} // namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_SCHEDULEDFS_H diff --git a/include/llvm/CodeGen/ScheduleHazardRecognizer.h b/include/llvm/CodeGen/ScheduleHazardRecognizer.h index 214be2794ba3..ace4a2d836ca 100644 --- a/include/llvm/CodeGen/ScheduleHazardRecognizer.h +++ b/include/llvm/CodeGen/ScheduleHazardRecognizer.h @@ -29,10 +29,10 @@ protected: /// state. Important to restore the state after backtracking. Additionally, /// MaxLookAhead=0 identifies a fake recognizer, allowing the client to /// bypass virtual calls. Currently the PostRA scheduler ignores it. - unsigned MaxLookAhead; + unsigned MaxLookAhead = 0; public: - ScheduleHazardRecognizer(): MaxLookAhead(0) {} + ScheduleHazardRecognizer() = default; virtual ~ScheduleHazardRecognizer(); enum HazardType { @@ -117,6 +117,6 @@ public: } }; -} +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_SCHEDULEHAZARDRECOGNIZER_H diff --git a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h index e0c30fe4d82a..466ab532030c 100644 --- a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h +++ b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h @@ -17,8 +17,8 @@ #define LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H #include "llvm/CodeGen/ScheduleHazardRecognizer.h" -#include "llvm/Support/DataTypes.h" #include <cassert> +#include <cstddef> #include <cstring> namespace llvm { @@ -38,21 +38,25 @@ class ScoreboardHazardRecognizer : public ScheduleHazardRecognizer { // bottom-up scheduler, then the scoreboard cycles are the inverse of the // scheduler's cycles. class Scoreboard { - unsigned *Data; + unsigned *Data = nullptr; // The maximum number of cycles monitored by the Scoreboard. This // value is determined based on the target itineraries to ensure // that all hazards can be tracked. - size_t Depth; + size_t Depth = 0; + // Indices into the Scoreboard that represent the current cycle. - size_t Head; + size_t Head = 0; + public: - Scoreboard():Data(nullptr), Depth(0), Head(0) { } + Scoreboard() = default; + ~Scoreboard() { delete[] Data; } size_t getDepth() const { return Depth; } + unsigned& operator[](size_t idx) const { // Depth is expected to be a power-of-2. assert(Depth && !(Depth & (Depth - 1)) && @@ -93,10 +97,10 @@ class ScoreboardHazardRecognizer : public ScheduleHazardRecognizer { const ScheduleDAG *DAG; /// IssueWidth - Max issue per cycle. 0=Unknown. - unsigned IssueWidth; + unsigned IssueWidth = 0; /// IssueCount - Count instructions issued in this cycle. - unsigned IssueCount; + unsigned IssueCount = 0; Scoreboard ReservedScoreboard; Scoreboard RequiredScoreboard; @@ -119,6 +123,6 @@ public: void RecedeCycle() override; }; -} +} // end namespace llvm -#endif //!LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H +#endif // LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 54d0436e4ab8..6f0509543e7d 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -36,6 +36,7 @@ namespace llvm { class MachineConstantPoolValue; class MachineFunction; class MDNode; +class OptimizationRemarkEmitter; class SDDbgValue; class TargetLowering; class SelectionDAGTargetInfo; @@ -171,6 +172,10 @@ class SelectionDAG { LLVMContext *Context; CodeGenOpt::Level OptLevel; + /// The function-level optimization remark emitter. Used to emit remarks + /// whenever manipulating the DAG. + OptimizationRemarkEmitter *ORE; + /// The starting token. SDNode EntryNode; @@ -239,7 +244,7 @@ public: std::function<void(SDNode *, SDNode *)> Callback; DAGNodeDeletedListener(SelectionDAG &DAG, std::function<void(SDNode *, SDNode *)> Callback) - : DAGUpdateListener(DAG), Callback(Callback) {} + : DAGUpdateListener(DAG), Callback(std::move(Callback)) {} void NodeDeleted(SDNode *N, SDNode *E) override { Callback(N, E); } }; @@ -318,7 +323,7 @@ public: ~SelectionDAG(); /// Prepare this SelectionDAG to process code in the given MachineFunction. - void init(MachineFunction &mf); + void init(MachineFunction &NewMF, OptimizationRemarkEmitter &NewORE); /// Clear state and free memory necessary to make this /// SelectionDAG ready to process a new block. @@ -331,6 +336,7 @@ public: const TargetLowering &getTargetLoweringInfo() const { return *TLI; } const SelectionDAGTargetInfo &getSelectionDAGInfo() const { return *TSI; } LLVMContext *getContext() const {return Context; } + OptimizationRemarkEmitter &getORE() const { return *ORE; } /// Pop up a GraphViz/gv window with the DAG rendered using 'dot'. void viewGraph(const std::string &Title); @@ -480,6 +486,13 @@ public: bool isTarget = false, bool isOpaque = false); SDValue getConstant(const APInt &Val, const SDLoc &DL, EVT VT, bool isTarget = false, bool isOpaque = false); + + SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget = false, + bool IsOpaque = false) { + return getConstant(APInt::getAllOnesValue(VT.getScalarSizeInBits()), DL, + VT, IsTarget, IsOpaque); + } + SDValue getConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT, bool isTarget = false, bool isOpaque = false); SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, @@ -733,6 +746,9 @@ public: return getNode(ISD::CALLSEQ_END, DL, NodeTys, Ops); } + /// Return true if the result of this operation is always undefined. + bool isUndef(unsigned Opcode, ArrayRef<SDValue> Ops); + /// Return an UNDEF node. UNDEF does not have a useful SDLoc. SDValue getUNDEF(EVT VT) { return getNode(ISD::UNDEF, SDLoc(), VT); @@ -1274,6 +1290,19 @@ public: void computeKnownBits(SDValue Op, APInt &KnownZero, APInt &KnownOne, const APInt &DemandedElts, unsigned Depth = 0) const; + /// Used to represent the possible overflow behavior of an operation. + /// Never: the operation cannot overflow. + /// Always: the operation will always overflow. + /// Sometime: the operation may or may not overflow. + enum OverflowKind { + OFK_Never, + OFK_Sometime, + OFK_Always, + }; + + /// Determine if the result of the addition of 2 node can overflow. + OverflowKind computeOverflowKind(SDValue N0, SDValue N1) const; + /// 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. @@ -1288,6 +1317,17 @@ public: /// target nodes to be understood. unsigned ComputeNumSignBits(SDValue Op, 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. The DemandedElts argument allows + /// us to only collect the minimum sign bits of the requested vector elements. + /// Targets can implement the ComputeNumSignBitsForTarget method in the + /// TargetLowering class to allow target nodes to be understood. + unsigned ComputeNumSignBits(SDValue Op, const APInt &DemandedElts, + 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 diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index 61d7ec4ecf5b..591b2f773344 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -20,6 +20,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/Pass.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include <memory> namespace llvm { class FastISel; @@ -29,6 +30,7 @@ namespace llvm { class MachineBasicBlock; class MachineFunction; class MachineInstr; + class OptimizationRemarkEmitter; class TargetLowering; class TargetLibraryInfo; class FunctionLoweringInfo; @@ -53,6 +55,12 @@ public: CodeGenOpt::Level OptLevel; const TargetInstrInfo *TII; const TargetLowering *TLI; + bool FastISelFailed; + SmallPtrSet<const Instruction *, 4> ElidedArgCopyInstrs; + + /// Current optimization remark emitter. + /// Used to report things like combines and FastISel failures. + std::unique_ptr<OptimizationRemarkEmitter> ORE; static char ID; @@ -151,7 +159,9 @@ public: OPC_MorphNodeTo, // Space-optimized forms that implicitly encode number of result VTs. OPC_MorphNodeTo0, OPC_MorphNodeTo1, OPC_MorphNodeTo2, - OPC_CompleteMatch + OPC_CompleteMatch, + // Contains offset in table for pattern being selected + OPC_Coverage }; enum { @@ -213,6 +223,15 @@ protected: void SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops, const SDLoc &DL); + /// getPatternForIndex - Patterns selected by tablegen during ISEL + virtual StringRef getPatternForIndex(unsigned index) { + llvm_unreachable("Tblgen should generate the implementation of this!"); + } + + /// getIncludePathForIndex - get the td source location of pattern instantiation + virtual StringRef getIncludePathForIndex(unsigned index) { + llvm_unreachable("Tblgen should generate the implementation of this!"); + } public: // Calls to these predicates are generated by tblgen. bool CheckAndMask(SDValue LHS, ConstantSDNode *RHS, @@ -270,6 +289,8 @@ private: SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTs, ArrayRef<SDValue> Ops, unsigned EmitNodeInfo); + SDNode *MutateStrictFPToFP(SDNode *Node, unsigned NewOpc); + /// Prepares the landing pad to take incoming values or do other EH /// personality specific tasks. Returns true if the block should be /// instruction selected, false if no code should be emitted for it. diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index b6f5424dbbd7..81cc0b39cf87 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/SelectionDAGNodes.h - SelectionDAG Nodes ---*- C++ -*-===// +//===- llvm/CodeGen/SelectionDAGNodes.h - SelectionDAG Nodes ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -118,11 +118,11 @@ namespace ISD { class SDValue { friend struct DenseMapInfo<SDValue>; - SDNode *Node; // The node defining the value we are using. - unsigned ResNo; // Which return value of the node we are using. + SDNode *Node = nullptr; // The node defining the value we are using. + unsigned ResNo = 0; // Which return value of the node we are using. public: - SDValue() : Node(nullptr), ResNo(0) {} + SDValue() = default; SDValue(SDNode *node, unsigned resno); /// get the index which selects a specific result in the SDNode @@ -250,16 +250,16 @@ class SDUse { /// Val - The value being used. SDValue Val; /// User - The user of this value. - SDNode *User; + SDNode *User = nullptr; /// Prev, Next - Pointers to the uses list of the SDNode referred by /// this operand. - SDUse **Prev, *Next; - - SDUse(const SDUse &U) = delete; - void operator=(const SDUse &U) = delete; + SDUse **Prev = nullptr; + SDUse *Next = nullptr; public: - SDUse() : User(nullptr), Prev(nullptr), Next(nullptr) {} + SDUse() = default; + SDUse(const SDUse &U) = delete; + SDUse &operator=(const SDUse &) = delete; /// Normally SDUse will just implicitly convert to an SDValue that it holds. operator const SDValue&() const { return Val; } @@ -350,20 +350,15 @@ private: bool NoSignedZeros : 1; bool AllowReciprocal : 1; bool VectorReduction : 1; + bool AllowContract : 1; public: /// Default constructor turns off all optimization flags. - SDNodeFlags() { - NoUnsignedWrap = false; - NoSignedWrap = false; - Exact = false; - UnsafeAlgebra = false; - NoNaNs = false; - NoInfs = false; - NoSignedZeros = false; - AllowReciprocal = false; - VectorReduction = false; - } + SDNodeFlags() + : NoUnsignedWrap(false), NoSignedWrap(false), Exact(false), + UnsafeAlgebra(false), NoNaNs(false), NoInfs(false), + NoSignedZeros(false), AllowReciprocal(false), VectorReduction(false), + AllowContract(false) {} // These are mutators for each flag. void setNoUnsignedWrap(bool b) { NoUnsignedWrap = b; } @@ -375,6 +370,7 @@ public: void setNoSignedZeros(bool b) { NoSignedZeros = b; } void setAllowReciprocal(bool b) { AllowReciprocal = b; } void setVectorReduction(bool b) { VectorReduction = b; } + void setAllowContract(bool b) { AllowContract = b; } // These are accessors for each flag. bool hasNoUnsignedWrap() const { return NoUnsignedWrap; } @@ -386,6 +382,7 @@ public: bool hasNoSignedZeros() const { return NoSignedZeros; } bool hasAllowReciprocal() const { return AllowReciprocal; } bool hasVectorReduction() const { return VectorReduction; } + bool hasAllowContract() const { return AllowContract; } /// Clear any flags in this flag set that aren't also set in Flags. void intersectWith(const SDNodeFlags *Flags) { @@ -397,6 +394,8 @@ public: NoInfs &= Flags->NoInfs; NoSignedZeros &= Flags->NoSignedZeros; AllowReciprocal &= Flags->AllowReciprocal; + VectorReduction &= Flags->VectorReduction; + AllowContract &= Flags->AllowContract; } }; @@ -446,6 +445,7 @@ protected: class LSBaseSDNodeBitfields { friend class LSBaseSDNode; + uint16_t : NumMemSDNodeBits; uint16_t AddressingMode : 3; // enum ISD::MemIndexedMode @@ -493,21 +493,26 @@ protected: static_assert(sizeof(StoreSDNodeBitfields) <= 2, "field too wide"); private: + friend class SelectionDAG; + // TODO: unfriend HandleSDNode once we fix its operand handling. + friend class HandleSDNode; + /// Unique id per SDNode in the DAG. - int NodeId; + int NodeId = -1; /// The values that are used by this operation. - SDUse *OperandList; + SDUse *OperandList = nullptr; /// The types of the values this node defines. SDNode's may /// define multiple values simultaneously. const EVT *ValueList; /// List of uses for this SDNode. - SDUse *UseList; + SDUse *UseList = nullptr; /// The number of entries in the Operand/Value list. - unsigned short NumOperands, NumValues; + unsigned short NumOperands = 0; + unsigned short NumValues; // The ordering of the SDNodes. It roughly corresponds to the ordering of the // original LLVM instructions. @@ -522,10 +527,6 @@ private: /// Return a pointer to the specified value type. static const EVT *getValueTypeList(EVT VT); - friend class SelectionDAG; - // TODO: unfriend HandleSDNode once we fix its operand handling. - friend class HandleSDNode; - public: /// Unique and persistent id per SDNode in the DAG. /// Used for debug printing. @@ -616,10 +617,10 @@ public: /// operands that use a specific SDNode. class use_iterator : public std::iterator<std::forward_iterator_tag, SDUse, ptrdiff_t> { - SDUse *Op; - friend class SDNode; + SDUse *Op = nullptr; + explicit use_iterator(SDUse *op) : Op(op) {} public: @@ -628,8 +629,8 @@ public: typedef std::iterator<std::forward_iterator_tag, SDUse, ptrdiff_t>::pointer pointer; + use_iterator() = default; use_iterator(const use_iterator &I) : Op(I.Op) {} - use_iterator() : Op(nullptr) {} bool operator==(const use_iterator &x) const { return Op == x.Op; @@ -737,11 +738,15 @@ public: return false; } + /// Return true if all the users of N are contained in Nodes. + /// NOTE: Requires at least one match, but doesn't require them all. + static bool areOnlyUsersOf(ArrayRef<const SDNode *> Nodes, const SDNode *N); + /// Return the number of values used by this operation. unsigned getNumOperands() const { return NumOperands; } /// Helper method returns the integer value of a ConstantSDNode operand. - uint64_t getConstantOperandVal(unsigned Num) const; + inline uint64_t getConstantOperandVal(unsigned Num) const; const SDValue &getOperand(unsigned Num) const { assert(Num < NumOperands && "Invalid child # of SDNode!"); @@ -896,9 +901,8 @@ protected: /// 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), NodeId(-1), OperandList(nullptr), ValueList(VTs.VTs), - UseList(nullptr), NumOperands(0), NumValues(VTs.NumVTs), IROrder(Order), - debugLoc(std::move(dl)) { + : NodeType(Opc), ValueList(VTs.VTs), NumValues(VTs.NumVTs), + IROrder(Order), debugLoc(std::move(dl)) { memset(&RawSDNodeBits, 0, sizeof(RawSDNodeBits)); assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor"); assert(NumValues == VTs.NumVTs && @@ -1366,10 +1370,10 @@ public: }; class ConstantSDNode : public SDNode { - const ConstantInt *Value; - friend class SelectionDAG; + const ConstantInt *Value; + ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val, const DebugLoc &DL, EVT VT) : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DL, @@ -1396,11 +1400,15 @@ public: } }; -class ConstantFPSDNode : public SDNode { - const ConstantFP *Value; +uint64_t SDNode::getConstantOperandVal(unsigned Num) const { + return cast<ConstantSDNode>(getOperand(Num))->getZExtValue(); +} +class ConstantFPSDNode : public SDNode { friend class SelectionDAG; + const ConstantFP *Value; + ConstantFPSDNode(bool isTarget, const ConstantFP *val, const DebugLoc &DL, EVT VT) : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, 0, DL, @@ -1471,10 +1479,12 @@ ConstantSDNode *isConstOrConstSplat(SDValue V); ConstantFPSDNode *isConstOrConstSplatFP(SDValue V); class GlobalAddressSDNode : public SDNode { + friend class SelectionDAG; + const GlobalValue *TheGlobal; int64_t Offset; unsigned char TargetFlags; - friend class SelectionDAG; + GlobalAddressSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, const GlobalValue *GA, EVT VT, int64_t o, unsigned char TargetFlags); @@ -1495,10 +1505,10 @@ public: }; class FrameIndexSDNode : public SDNode { - int FI; - friend class SelectionDAG; + int FI; + FrameIndexSDNode(int fi, EVT VT, bool isTarg) : SDNode(isTarg ? ISD::TargetFrameIndex : ISD::FrameIndex, 0, DebugLoc(), getSDVTList(VT)), FI(fi) { @@ -1514,11 +1524,11 @@ public: }; class JumpTableSDNode : public SDNode { + friend class SelectionDAG; + int JTI; unsigned char TargetFlags; - friend class SelectionDAG; - JumpTableSDNode(int jti, EVT VT, bool isTarg, unsigned char TF) : SDNode(isTarg ? ISD::TargetJumpTable : ISD::JumpTable, 0, DebugLoc(), getSDVTList(VT)), JTI(jti), TargetFlags(TF) { @@ -1535,6 +1545,8 @@ public: }; class ConstantPoolSDNode : public SDNode { + friend class SelectionDAG; + union { const Constant *ConstVal; MachineConstantPoolValue *MachineCPVal; @@ -1543,8 +1555,6 @@ class ConstantPoolSDNode : public SDNode { unsigned Alignment; // Minimum alignment requirement of CP (not log2 value). unsigned char TargetFlags; - friend class SelectionDAG; - ConstantPoolSDNode(bool isTarget, const Constant *c, EVT VT, int o, unsigned Align, unsigned char TF) : SDNode(isTarget ? ISD::TargetConstantPool : ISD::ConstantPool, 0, @@ -1598,12 +1608,12 @@ public: /// Completely target-dependent object reference. class TargetIndexSDNode : public SDNode { + friend class SelectionDAG; + unsigned char TargetFlags; int Index; int64_t Offset; - friend class SelectionDAG; - public: TargetIndexSDNode(int Idx, EVT VT, int64_t Ofs, unsigned char TF) : SDNode(ISD::TargetIndex, 0, DebugLoc(), getSDVTList(VT)), @@ -1619,10 +1629,10 @@ public: }; class BasicBlockSDNode : public SDNode { - MachineBasicBlock *MBB; - friend class SelectionDAG; + MachineBasicBlock *MBB; + /// Debug info is meaningful and potentially useful here, but we create /// blocks out of order when they're jumped to, which makes it a bit /// harder. Let's see if we need it first. @@ -1640,10 +1650,10 @@ public: /// A "pseudo-class" with methods for operating on BUILD_VECTORs. class BuildVectorSDNode : public SDNode { +public: // These are constructed as SDNodes and then cast to BuildVectorSDNodes. explicit BuildVectorSDNode() = delete; -public: /// Check if this is a constant splat, and if so, find the /// smallest element size that splats the vector. If MinSplatBits is /// nonzero, the element size must be at least that large. Note that the @@ -1700,10 +1710,10 @@ public: /// in the LLVM IR representation. /// class SrcValueSDNode : public SDNode { - const Value *V; - friend class SelectionDAG; + const Value *V; + /// Create a SrcValue for a general value. explicit SrcValueSDNode(const Value *v) : SDNode(ISD::SRCVALUE, 0, DebugLoc(), getSDVTList(MVT::Other)), V(v) {} @@ -1718,10 +1728,10 @@ public: }; class MDNodeSDNode : public SDNode { - const MDNode *MD; - friend class SelectionDAG; + const MDNode *MD; + explicit MDNodeSDNode(const MDNode *md) : SDNode(ISD::MDNODE_SDNODE, 0, DebugLoc(), getSDVTList(MVT::Other)), MD(md) {} @@ -1735,10 +1745,10 @@ public: }; class RegisterSDNode : public SDNode { - unsigned Reg; - friend class SelectionDAG; + unsigned Reg; + RegisterSDNode(unsigned reg, EVT VT) : SDNode(ISD::Register, 0, DebugLoc(), getSDVTList(VT)), Reg(reg) {} @@ -1751,11 +1761,11 @@ public: }; class RegisterMaskSDNode : public SDNode { + friend class SelectionDAG; + // The memory for RegMask is not owned by the node. const uint32_t *RegMask; - friend class SelectionDAG; - RegisterMaskSDNode(const uint32_t *mask) : SDNode(ISD::RegisterMask, 0, DebugLoc(), getSDVTList(MVT::Untyped)), RegMask(mask) {} @@ -1769,12 +1779,12 @@ public: }; class BlockAddressSDNode : public SDNode { + friend class SelectionDAG; + const BlockAddress *BA; int64_t Offset; unsigned char TargetFlags; - friend class SelectionDAG; - BlockAddressSDNode(unsigned NodeTy, EVT VT, const BlockAddress *ba, int64_t o, unsigned char Flags) : SDNode(NodeTy, 0, DebugLoc(), getSDVTList(VT)), @@ -1793,10 +1803,10 @@ public: }; class EHLabelSDNode : public SDNode { - MCSymbol *Label; - friend class SelectionDAG; + MCSymbol *Label; + EHLabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) {} @@ -1809,11 +1819,11 @@ public: }; class ExternalSymbolSDNode : public SDNode { + friend class SelectionDAG; + const char *Symbol; unsigned char TargetFlags; - friend class SelectionDAG; - ExternalSymbolSDNode(bool isTarget, const char *Sym, unsigned char TF, EVT VT) : SDNode(isTarget ? ISD::TargetExternalSymbol : ISD::ExternalSymbol, 0, DebugLoc(), getSDVTList(VT)), Symbol(Sym), TargetFlags(TF) {} @@ -1829,9 +1839,10 @@ public: }; class MCSymbolSDNode : public SDNode { + friend class SelectionDAG; + MCSymbol *Symbol; - friend class SelectionDAG; MCSymbolSDNode(MCSymbol *Symbol, EVT VT) : SDNode(ISD::MCSymbol, 0, DebugLoc(), getSDVTList(VT)), Symbol(Symbol) {} @@ -1844,10 +1855,10 @@ public: }; class CondCodeSDNode : public SDNode { - ISD::CondCode Condition; - friend class SelectionDAG; + ISD::CondCode Condition; + explicit CondCodeSDNode(ISD::CondCode Cond) : SDNode(ISD::CONDCODE, 0, DebugLoc(), getSDVTList(MVT::Other)), Condition(Cond) {} @@ -1863,10 +1874,10 @@ public: /// This class is used to represent EVT's, which are used /// to parameterize some operations. class VTSDNode : public SDNode { - EVT ValueType; - friend class SelectionDAG; + EVT ValueType; + explicit VTSDNode(EVT VT) : SDNode(ISD::VALUETYPE, 0, DebugLoc(), getSDVTList(MVT::Other)), ValueType(VT) {} @@ -1995,6 +2006,7 @@ public: class MaskedLoadSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; + MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::LoadExtType ETy, bool IsExpanding, EVT MemVT, MachineMemOperand *MMO) @@ -2114,11 +2126,11 @@ private: friend class SelectionDAG; MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, SDVTList VTs) - : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} + : SDNode(Opc, Order, DL, VTs) {} /// Memory reference descriptions for this instruction. - mmo_iterator MemRefs; - mmo_iterator MemRefsEnd; + mmo_iterator MemRefs = nullptr; + mmo_iterator MemRefsEnd = nullptr; public: mmo_iterator memoperands_begin() const { return MemRefs; } @@ -2184,9 +2196,11 @@ template <> struct GraphTraits<SDNode*> { typedef SDNodeIterator ChildIteratorType; static NodeRef getEntryNode(SDNode *N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { return SDNodeIterator::begin(N); } + static ChildIteratorType child_end(NodeRef N) { return SDNodeIterator::end(N); } diff --git a/include/llvm/CodeGen/SlotIndexes.h b/include/llvm/CodeGen/SlotIndexes.h index 2ac3b3d86cb6..14fc3a499a08 100644 --- a/include/llvm/CodeGen/SlotIndexes.h +++ b/include/llvm/CodeGen/SlotIndexes.h @@ -602,19 +602,15 @@ namespace llvm { return newIndex; } - /// Remove the given machine instruction from the mapping. - void removeMachineInstrFromMaps(MachineInstr &MI) { - // remove index -> MachineInstr and - // MachineInstr -> index mappings - Mi2IndexMap::iterator mi2iItr = mi2iMap.find(&MI); - if (mi2iItr != mi2iMap.end()) { - IndexListEntry *miEntry(mi2iItr->second.listEntry()); - assert(miEntry->getInstr() == &MI && "Instruction indexes broken."); - // FIXME: Eventually we want to actually delete these indexes. - miEntry->setInstr(nullptr); - mi2iMap.erase(mi2iItr); - } - } + /// Removes machine instruction (bundle) \p MI from the mapping. + /// This should be called before MachineInstr::eraseFromParent() is used to + /// remove a whole bundle or an unbundled instruction. + void removeMachineInstrFromMaps(MachineInstr &MI); + + /// Removes a single machine instruction \p MI from the mapping. + /// This should be called before MachineInstr::eraseFromBundle() is used to + /// remove a single instruction (out of a bundle). + void removeSingleMachineInstrFromMaps(MachineInstr &MI); /// ReplaceMachineInstrInMaps - Replacing a machine instr with a new one in /// maps used by register allocator. \returns the index where the new diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h index 7b55b7968635..a18936feea7b 100644 --- a/include/llvm/CodeGen/StackMaps.h +++ b/include/llvm/CodeGen/StackMaps.h @@ -1,4 +1,4 @@ -//===------------------- StackMaps.h - StackMaps ----------------*- C++ -*-===// +//===- StackMaps.h - StackMaps ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -13,7 +13,11 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/MC/MCSymbol.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/Support/Debug.h" +#include <algorithm> +#include <cassert> +#include <cstdint> #include <vector> namespace llvm { @@ -21,6 +25,9 @@ namespace llvm { class AsmPrinter; class MCExpr; class MCStreamer; +class MCSymbol; +class raw_ostream; +class TargetRegisterInfo; /// \brief MI-level stackmap operands. /// @@ -189,21 +196,22 @@ public: Constant, ConstantIndex }; - LocationType Type; - unsigned Size; - unsigned Reg; - int64_t Offset; - Location() : Type(Unprocessed), Size(0), Reg(0), Offset(0) {} + LocationType Type = Unprocessed; + unsigned Size = 0; + unsigned Reg = 0; + int64_t Offset = 0; + + Location() = default; Location(LocationType Type, unsigned Size, unsigned Reg, int64_t Offset) : Type(Type), Size(Size), Reg(Reg), Offset(Offset) {} }; struct LiveOutReg { - unsigned short Reg; - unsigned short DwarfRegNum; - unsigned short Size; + unsigned short Reg = 0; + unsigned short DwarfRegNum = 0; + unsigned short Size = 0; - LiveOutReg() : Reg(0), DwarfRegNum(0), Size(0) {} + LiveOutReg() = default; LiveOutReg(unsigned short Reg, unsigned short DwarfRegNum, unsigned short Size) : Reg(Reg), DwarfRegNum(DwarfRegNum), Size(Size) {} @@ -245,18 +253,20 @@ private: typedef MapVector<uint64_t, uint64_t> ConstantPool; struct FunctionInfo { - uint64_t StackSize; - uint64_t RecordCount; - FunctionInfo() : StackSize(0), RecordCount(1) {} - explicit FunctionInfo(uint64_t StackSize) : StackSize(StackSize), RecordCount(1) {} + uint64_t StackSize = 0; + uint64_t RecordCount = 1; + + FunctionInfo() = default; + explicit FunctionInfo(uint64_t StackSize) : StackSize(StackSize) {} }; struct CallsiteInfo { - const MCExpr *CSOffsetExpr; - uint64_t ID; + const MCExpr *CSOffsetExpr = nullptr; + uint64_t ID = 0; LocationVec Locations; LiveOutVec LiveOuts; - CallsiteInfo() : CSOffsetExpr(nullptr), ID(0) {} + + CallsiteInfo() = default; CallsiteInfo(const MCExpr *CSOffsetExpr, uint64_t ID, LocationVec &&Locations, LiveOutVec &&LiveOuts) : CSOffsetExpr(CSOffsetExpr), ID(ID), Locations(std::move(Locations)), @@ -309,6 +319,7 @@ private: void print(raw_ostream &OS); void debug() { print(dbgs()); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_CODEGEN_STACKMAPS_H diff --git a/include/llvm/CodeGen/StackProtector.h b/include/llvm/CodeGen/StackProtector.h index 1b3c0eb4a4d0..0655f19a323e 100644 --- a/include/llvm/CodeGen/StackProtector.h +++ b/include/llvm/CodeGen/StackProtector.h @@ -1,4 +1,4 @@ -//===-- StackProtector.h - Stack Protector Insertion ----------------------===// +//===- StackProtector.h - Stack Protector Insertion -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,8 +23,10 @@ #include "llvm/IR/ValueMap.h" #include "llvm/Pass.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetMachine.h" namespace llvm { + class Function; class Module; class PHINode; @@ -48,11 +50,11 @@ public: typedef ValueMap<const AllocaInst *, SSPLayoutKind> SSPLayoutMap; private: - const TargetMachine *TM; + const TargetMachine *TM = nullptr; /// TLI - Keep a pointer of a TargetLowering to consult for determining /// target type sizes. - const TargetLoweringBase *TLI; + const TargetLoweringBase *TLI = nullptr; const Triple Trip; Function *F; @@ -67,7 +69,7 @@ private: /// \brief The minimum size of buffers that will receive stack smashing /// protection when -fstack-protection is used. - unsigned SSPBufferSize; + unsigned SSPBufferSize = 0; /// VisitedPHIs - The set of PHI nodes visited when determining /// if a variable's reference has been taken. This set @@ -111,12 +113,13 @@ private: public: static char ID; // Pass identification, replacement for typeid. - StackProtector() - : FunctionPass(ID), TM(nullptr), TLI(nullptr), SSPBufferSize(0) { + + StackProtector() : FunctionPass(ID) { initializeStackProtectorPass(*PassRegistry::getPassRegistry()); } + StackProtector(const TargetMachine *TM) - : FunctionPass(ID), TM(TM), TLI(nullptr), Trip(TM->getTargetTriple()), + : FunctionPass(ID), TM(TM), Trip(TM->getTargetTriple()), SSPBufferSize(8) { initializeStackProtectorPass(*PassRegistry::getPassRegistry()); } @@ -134,6 +137,7 @@ public: bool runOnFunction(Function &Fn) override; }; + } // end namespace llvm #endif // LLVM_CODEGEN_STACKPROTECTOR_H diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index cc71fa3918a1..adf2b3ea1c9b 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -1,4 +1,4 @@ -//==-- llvm/CodeGen/TargetLoweringObjectFileImpl.h - Object Info -*- C++ -*-==// +//==- llvm/CodeGen/TargetLoweringObjectFileImpl.h - Object Info --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -15,24 +15,22 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H +#include "llvm/IR/Module.h" #include "llvm/MC/MCExpr.h" -#include "llvm/MC/SectionKind.h" #include "llvm/Target/TargetLoweringObjectFile.h" namespace llvm { - class MachineModuleInfo; - class Mangler; - class MCAsmInfo; - class MCSection; - class MCSectionMachO; - class MCSymbol; - class MCContext; - class GlobalValue; - class TargetMachine; +class GlobalValue; +class MachineModuleInfo; +class Mangler; +class MCContext; +class MCSection; +class MCSymbol; +class TargetMachine; class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { - bool UseInitArray; + bool UseInitArray = false; mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections protected: @@ -40,9 +38,8 @@ protected: MCSymbolRefExpr::VK_None; public: - TargetLoweringObjectFileELF() : UseInitArray(false) {} - - ~TargetLoweringObjectFileELF() override {} + TargetLoweringObjectFileELF() = default; + ~TargetLoweringObjectFileELF() override = default; void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM, const MCSymbol *Sym) const override; @@ -89,12 +86,10 @@ public: const TargetMachine &TM) const override; }; - - class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { public: - ~TargetLoweringObjectFileMachO() override {} TargetLoweringObjectFileMachO(); + ~TargetLoweringObjectFileMachO() override = default; void Initialize(MCContext &Ctx, const TargetMachine &TM) override; @@ -135,13 +130,11 @@ public: const TargetMachine &TM) const override; }; - - class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { mutable unsigned NextUniqueID = 0; public: - ~TargetLoweringObjectFileCOFF() override {} + ~TargetLoweringObjectFileCOFF() override = default; void Initialize(MCContext &Ctx, const TargetMachine &TM) override; MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, @@ -171,6 +164,29 @@ public: const GlobalValue *GV) const override; }; +class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { + mutable unsigned NextUniqueID = 0; + +public: + TargetLoweringObjectFileWasm() = default; + ~TargetLoweringObjectFileWasm() override = default; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, + const Function &F) const override; + + void InitializeWasm(); + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; +}; + } // end namespace llvm -#endif +#endif // LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H diff --git a/include/llvm/CodeGen/TargetPassConfig.h b/include/llvm/CodeGen/TargetPassConfig.h index 2287f9aca4bf..f0c826dc1d45 100644 --- a/include/llvm/CodeGen/TargetPassConfig.h +++ b/include/llvm/CodeGen/TargetPassConfig.h @@ -115,6 +115,10 @@ protected: /// Default setting for -enable-tail-merge on this target. bool EnableTailMerge; + /// Require processing of functions such that callees are generated before + /// callers. + bool RequireCodeGenSCCOrder; + public: TargetPassConfig(TargetMachine *tm, PassManagerBase &pm); // Dummy constructor. @@ -162,6 +166,11 @@ public: bool getEnableTailMerge() const { return EnableTailMerge; } void setEnableTailMerge(bool Enable) { setOpt(EnableTailMerge, Enable); } + bool requiresCodeGenSCCOrder() const { return RequireCodeGenSCCOrder; } + void setRequiresCodeGenSCCOrder(bool Enable = true) { + setOpt(RequireCodeGenSCCOrder, 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. @@ -286,6 +295,10 @@ public: /// verification is enabled. void addVerifyPass(const std::string &Banner); + /// Check whether or not GlobalISel should be enabled by default. + /// Fallback/abort behavior is controlled via other methods. + virtual bool isGlobalISelEnabled() const; + /// Check whether or not GlobalISel should abort on error. /// When this is disable, GlobalISel will fall back on SDISel instead of /// erroring out. diff --git a/include/llvm/CodeGen/TargetSchedule.h b/include/llvm/CodeGen/TargetSchedule.h index 81054aba066f..1992412120aa 100644 --- a/include/llvm/CodeGen/TargetSchedule.h +++ b/include/llvm/CodeGen/TargetSchedule.h @@ -1,4 +1,4 @@ -//===-- llvm/CodeGen/TargetSchedule.h - Sched Machine Model -----*- C++ -*-===// +//===- llvm/CodeGen/TargetSchedule.h - Sched Machine Model ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,10 +23,8 @@ namespace llvm { -class TargetRegisterInfo; -class TargetSubtargetInfo; -class TargetInstrInfo; class MachineInstr; +class TargetInstrInfo; /// Provide an instruction scheduling machine model to CodeGen passes. class TargetSchedModel { @@ -34,8 +32,8 @@ class TargetSchedModel { // processor. MCSchedModel SchedModel; InstrItineraryData InstrItins; - const TargetSubtargetInfo *STI; - const TargetInstrInfo *TII; + const TargetSubtargetInfo *STI = nullptr; + const TargetInstrInfo *TII = nullptr; SmallVector<unsigned, 16> ResourceFactors; unsigned MicroOpFactor; // Multiply to normalize microops to resource units. @@ -44,7 +42,7 @@ class TargetSchedModel { unsigned computeInstrLatency(const MCSchedClassDesc &SCDesc) const; public: - TargetSchedModel(): SchedModel(MCSchedModel::GetDefaultSchedModel()), STI(nullptr), TII(nullptr) {} + TargetSchedModel() : SchedModel(MCSchedModel::GetDefaultSchedModel()) {} /// \brief Initialize the machine model for instruction scheduling. /// @@ -93,6 +91,13 @@ public: /// \brief Maximum number of micro-ops that may be scheduled per cycle. unsigned getIssueWidth() const { return SchedModel.IssueWidth; } + /// \brief Return true if new group must begin. + bool mustBeginGroup(const MachineInstr *MI, + const MCSchedClassDesc *SC = nullptr) const; + /// \brief Return true if current group must end. + bool mustEndGroup(const MachineInstr *MI, + const MCSchedClassDesc *SC = nullptr) const; + /// \brief Return the number of issue slots required for this MI. unsigned getNumMicroOps(const MachineInstr *MI, const MCSchedClassDesc *SC = nullptr) const; @@ -178,13 +183,18 @@ public: bool UseDefaultDefLatency = true) const; unsigned computeInstrLatency(unsigned Opcode) const; + /// \brief Output dependency latency of a pair of defs of the same register. /// /// This is typically one cycle. unsigned computeOutputLatency(const MachineInstr *DefMI, unsigned DefIdx, const MachineInstr *DepMI) const; + + /// \brief Compute the reciprocal throughput of the given instruction. + Optional<double> computeInstrRThroughput(const MachineInstr *MI) const; + Optional<double> computeInstrRThroughput(unsigned Opcode) const; }; -} // namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_CODEGEN_TARGETSCHEDULE_H diff --git a/include/llvm/CodeGen/ValueTypes.h b/include/llvm/CodeGen/ValueTypes.h index 2699fa28f0f1..0a3063663cef 100644 --- a/include/llvm/CodeGen/ValueTypes.h +++ b/include/llvm/CodeGen/ValueTypes.h @@ -25,9 +25,9 @@ namespace llvm { class LLVMContext; class Type; - /// EVT - Extended Value Type. Capable of holding value types which are not - /// native for any processor (such as the i12345 type), as well as the types - /// a MVT can represent. + /// Extended Value Type. Capable of holding value types which are not native + /// for any processor (such as the i12345 type), as well as the types an MVT + /// can represent. struct EVT { private: MVT V; @@ -49,15 +49,15 @@ namespace llvm { return false; } - /// getFloatingPointVT - Returns the EVT that represents a floating point - /// type with the given number of bits. There are two floating point types - /// with 128 bits - this returns f128 rather than ppcf128. + /// Returns the EVT that represents a floating-point type with the given + /// number of bits. There are two floating-point types with 128 bits - this + /// returns f128 rather than ppcf128. static EVT getFloatingPointVT(unsigned BitWidth) { return MVT::getFloatingPointVT(BitWidth); } - /// getIntegerVT - Returns the EVT that represents an integer with the given - /// number of bits. + /// Returns the EVT that represents an integer with the given number of + /// bits. static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth) { MVT M = MVT::getIntegerVT(BitWidth); if (M.SimpleTy >= 0) @@ -65,8 +65,8 @@ namespace llvm { return getExtendedIntegerVT(Context, BitWidth); } - /// getVectorVT - Returns the EVT that represents a vector NumElements in - /// length, where each element is of type VT. + /// Returns the EVT that represents a vector NumElements in length, where + /// each element is of type VT. static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements) { MVT M = MVT::getVectorVT(VT.V, NumElements); if (M.SimpleTy >= 0) @@ -74,9 +74,9 @@ namespace llvm { return getExtendedVectorVT(Context, VT, NumElements); } - /// changeVectorElementTypeToInteger - Return a vector with the same number - /// of elements as this vector, but with the element type converted to an - /// integer type with the same bitwidth. + /// Return a vector with the same number of elements as this vector, but + /// with the element type converted to an integer type with the same + /// bitwidth. EVT changeVectorElementTypeToInteger() const { if (!isSimple()) return changeExtendedVectorElementTypeToInteger(); @@ -102,140 +102,136 @@ namespace llvm { return changeExtendedTypeToInteger(); } - /// isSimple - Test if the given EVT is simple (as opposed to being - /// extended). + /// Test if the given EVT is simple (as opposed to being extended). bool isSimple() const { return V.SimpleTy >= 0; } - /// isExtended - Test if the given EVT is extended (as opposed to - /// being simple). + /// Test if the given EVT is extended (as opposed to being simple). bool isExtended() const { return !isSimple(); } - /// isFloatingPoint - Return true if this is a FP, or a vector FP type. + /// Return true if this is a FP or a vector FP type. bool isFloatingPoint() const { return isSimple() ? V.isFloatingPoint() : isExtendedFloatingPoint(); } - /// isInteger - Return true if this is an integer, or a vector integer type. + /// Return true if this is an integer or a vector integer type. bool isInteger() const { return isSimple() ? V.isInteger() : isExtendedInteger(); } - /// isScalarInteger - Return true if this is an integer, but not a vector. + /// 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. + /// Return true if this is a vector value type. bool isVector() const { return isSimple() ? V.isVector() : isExtendedVector(); } - /// is16BitVector - Return true if this is a 16-bit vector type. + /// Return true if this is a 16-bit vector type. bool is16BitVector() const { return isSimple() ? V.is16BitVector() : isExtended16BitVector(); } - /// is32BitVector - Return true if this is a 32-bit vector type. + /// Return true if this is a 32-bit vector type. bool is32BitVector() const { return isSimple() ? V.is32BitVector() : isExtended32BitVector(); } - /// is64BitVector - Return true if this is a 64-bit vector type. + /// Return true if this is a 64-bit vector type. bool is64BitVector() const { return isSimple() ? V.is64BitVector() : isExtended64BitVector(); } - /// is128BitVector - Return true if this is a 128-bit vector type. + /// Return true if this is a 128-bit vector type. bool is128BitVector() const { return isSimple() ? V.is128BitVector() : isExtended128BitVector(); } - /// is256BitVector - Return true if this is a 256-bit vector type. + /// Return true if this is a 256-bit vector type. bool is256BitVector() const { return isSimple() ? V.is256BitVector() : isExtended256BitVector(); } - /// is512BitVector - Return true if this is a 512-bit vector type. + /// Return true if this is a 512-bit vector type. bool is512BitVector() const { return isSimple() ? V.is512BitVector() : isExtended512BitVector(); } - /// is1024BitVector - Return true if this is a 1024-bit vector type. + /// Return true if this is a 1024-bit vector type. bool is1024BitVector() const { return isSimple() ? V.is1024BitVector() : isExtended1024BitVector(); } - /// is2048BitVector - Return true if this is a 2048-bit vector type. + /// Return true if this is a 2048-bit vector type. bool is2048BitVector() const { return isSimple() ? V.is2048BitVector() : isExtended2048BitVector(); } - /// isOverloaded - Return true if this is an overloaded type for TableGen. + /// Return true if this is an overloaded type for TableGen. bool isOverloaded() const { return (V==MVT::iAny || V==MVT::fAny || V==MVT::vAny || V==MVT::iPTRAny); } - /// isByteSized - Return true if the bit size is a multiple of 8. + /// Return true if the bit size is a multiple of 8. bool isByteSized() const { return (getSizeInBits() & 7) == 0; } - /// isRound - Return true if the size is a power-of-two number of bytes. + /// Return true if the size is a power-of-two number of bytes. bool isRound() const { unsigned BitSize = getSizeInBits(); return BitSize >= 8 && !(BitSize & (BitSize - 1)); } - /// bitsEq - Return true if this has the same number of bits as VT. + /// Return true if this has the same number of bits as VT. bool bitsEq(EVT VT) const { if (EVT::operator==(VT)) return true; return getSizeInBits() == VT.getSizeInBits(); } - /// bitsGT - Return true if this has more bits than VT. + /// Return true if this has more bits than VT. bool bitsGT(EVT VT) const { if (EVT::operator==(VT)) return false; return getSizeInBits() > VT.getSizeInBits(); } - /// bitsGE - Return true if this has no less bits than VT. + /// Return true if this has no less bits than VT. bool bitsGE(EVT VT) const { if (EVT::operator==(VT)) return true; return getSizeInBits() >= VT.getSizeInBits(); } - /// bitsLT - Return true if this has less bits than VT. + /// Return true if this has less bits than VT. bool bitsLT(EVT VT) const { if (EVT::operator==(VT)) return false; return getSizeInBits() < VT.getSizeInBits(); } - /// bitsLE - Return true if this has no more bits than VT. + /// Return true if this has no more bits than VT. bool bitsLE(EVT VT) const { if (EVT::operator==(VT)) return true; return getSizeInBits() <= VT.getSizeInBits(); } - /// getSimpleVT - Return the SimpleValueType held in the specified - /// simple EVT. + /// Return the SimpleValueType held in the specified simple EVT. MVT getSimpleVT() const { assert(isSimple() && "Expected a SimpleValueType!"); return V; } - /// 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. EVT getScalarType() const { return isVector() ? getVectorElementType() : *this; } - /// getVectorElementType - Given a vector type, return the type of - /// each element. + /// Given a vector type, return the type of each element. EVT getVectorElementType() const { assert(isVector() && "Invalid vector type!"); if (isSimple()) @@ -243,8 +239,7 @@ namespace llvm { return getExtendedVectorElementType(); } - /// getVectorNumElements - Given a vector type, return the number of - /// elements it contains. + /// Given a vector type, return the number of elements it contains. unsigned getVectorNumElements() const { assert(isVector() && "Invalid vector type!"); if (isSimple()) @@ -252,7 +247,7 @@ namespace llvm { return getExtendedVectorNumElements(); } - /// getSizeInBits - Return the size of the specified value type in bits. + /// Return the size of the specified value type in bits. unsigned getSizeInBits() const { if (isSimple()) return V.getSizeInBits(); @@ -263,21 +258,21 @@ namespace llvm { return getScalarType().getSizeInBits(); } - /// getStoreSize - Return the number of bytes overwritten by a store - /// of the specified value type. + /// Return the number of bytes overwritten by a store of the specified value + /// type. unsigned getStoreSize() const { return (getSizeInBits() + 7) / 8; } - /// getStoreSizeInBits - Return the number of bits overwritten by a store - /// of the specified value type. + /// Return the number of bits overwritten by a store of the specified value + /// type. unsigned getStoreSizeInBits() const { return getStoreSize() * 8; } - /// getRoundIntegerType - Rounds the bit-width of the given integer EVT up - /// to the nearest power of two (and at least to eight), and returns the - /// integer EVT with that number of bits. + /// Rounds the bit-width of the given integer EVT up to the nearest power of + /// two (and at least to eight), and returns the integer EVT with that + /// number of bits. EVT getRoundIntegerType(LLVMContext &Context) const { assert(isInteger() && !isVector() && "Invalid integer type!"); unsigned BitWidth = getSizeInBits(); @@ -286,10 +281,9 @@ namespace llvm { return getIntegerVT(Context, 1 << Log2_32_Ceil(BitWidth)); } - /// getHalfSizedIntegerVT - Finds the smallest simple value type that is - /// greater than or equal to half the width of this EVT. If no simple - /// value type can be found, an extended integer value type of half the - /// size (rounded up) is returned. + /// Finds the smallest simple value type that is greater than or equal to + /// half the width of this EVT. If no simple value type can be found, an + /// extended integer value type of half the size (rounded up) is returned. EVT getHalfSizedIntegerVT(LLVMContext &Context) const { assert(isInteger() && !isVector() && "Invalid integer type!"); unsigned EVTSize = getSizeInBits(); @@ -302,7 +296,7 @@ namespace llvm { return getIntegerVT(Context, (EVTSize + 1) / 2); } - /// \brief Return a VT for an integer vector type with the size of the + /// Return a VT for an integer vector type with the size of the /// elements doubled. The typed returned may be an extended type. EVT widenIntegerVectorElementType(LLVMContext &Context) const { EVT EltVT = getVectorElementType(); @@ -310,14 +304,14 @@ namespace llvm { return EVT::getVectorVT(Context, EltVT, getVectorNumElements()); } - /// isPow2VectorType - Returns true if the given vector is a power of 2. + /// Returns true if the given vector is a power of 2. bool isPow2VectorType() const { unsigned NElts = getVectorNumElements(); return !(NElts & (NElts - 1)); } - /// getPow2VectorType - Widens the length of the given vector EVT up to - /// the nearest power of 2 and returns that type. + /// Widens the length of the given vector EVT up to the nearest power of 2 + /// and returns that type. EVT getPow2VectorType(LLVMContext &Context) const { if (!isPow2VectorType()) { unsigned NElts = getVectorNumElements(); @@ -329,16 +323,15 @@ namespace llvm { } } - /// getEVTString - This function returns value type as a string, - /// e.g. "i32". + /// This function returns value type as a string, e.g. "i32". std::string getEVTString() const; - /// getTypeForEVT - This method returns an LLVM type corresponding to the - /// specified EVT. For integer types, this returns an unsigned type. Note - /// that this will abort for types that cannot be represented. + /// This method returns an LLVM type corresponding to the specified EVT. + /// For integer types, this returns an unsigned type. Note that this will + /// abort for types that cannot be represented. Type *getTypeForEVT(LLVMContext &Context) const; - /// getEVT - Return the value type corresponding to the specified type. + /// Return the value type corresponding to the specified type. /// This returns all pointers as iPTR. If HandleUnknown is true, unknown /// types are returned as Other, otherwise they are invalid. static EVT getEVT(Type *Ty, bool HandleUnknown = false); @@ -350,8 +343,8 @@ namespace llvm { return (intptr_t)(LLVMTy); } - /// compareRawBits - A meaningless but well-behaved order, useful for - /// constructing containers. + /// A meaningless but well-behaved order, useful for constructing + /// containers. struct compareRawBits { bool operator()(EVT L, EVT R) const { if (L.V.SimpleTy == R.V.SimpleTy) diff --git a/include/llvm/Config/abi-breaking.h.cmake b/include/llvm/Config/abi-breaking.h.cmake index e5697f79e93d..4ce487b8f5f3 100644 --- a/include/llvm/Config/abi-breaking.h.cmake +++ b/include/llvm/Config/abi-breaking.h.cmake @@ -15,9 +15,8 @@ /* Define to enable checks that alter the LLVM C++ ABI */ #cmakedefine01 LLVM_ENABLE_ABI_BREAKING_CHECKS -/* Define to disable the link-time checking of mismatch for - LLVM_ENABLE_ABI_BREAKING_CHECKS */ -#cmakedefine01 LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING +/* Allow selectively disabling link-time mismatch checking so that header-only + ADT content from LLVM can be used without linking libSupport. */ #if !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING // ABI_BREAKING_CHECKS protection: provides link-time failure when clients build diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index ff41d75373c8..a3c919d39804 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -16,6 +16,8 @@ /* Define to 1 if you have the `backtrace' function. */ #cmakedefine HAVE_BACKTRACE ${HAVE_BACKTRACE} +#define BACKTRACE_HEADER <${BACKTRACE_HEADER}> + /* Define to 1 if you have the <CrashReporterClient.h> header file. */ #cmakedefine HAVE_CRASHREPORTERCLIENT_H @@ -51,6 +53,9 @@ /* Define if dlopen() is available on this platform. */ #cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN} +/* Define if dladdr() is available on this platform. */ +#cmakedefine HAVE_DLADDR ${HAVE_DLADDR} + /* Define to 1 if you have the <errno.h> header file. */ #cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H} @@ -375,9 +380,6 @@ /* Define if this is Win32ish platform */ #cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32} -/* Installation prefix directory */ -#cmakedefine LLVM_PREFIX "${LLVM_PREFIX}" - /* Define if we have the Intel JIT API runtime support library */ #cmakedefine01 LLVM_USE_INTEL_JITEVENTS diff --git a/include/llvm/Config/llvm-config.h.cmake b/include/llvm/Config/llvm-config.h.cmake index 359997057618..4b0c59460619 100644 --- a/include/llvm/Config/llvm-config.h.cmake +++ b/include/llvm/Config/llvm-config.h.cmake @@ -56,9 +56,6 @@ /* Define if this is Win32ish platform */ #cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32} -/* Installation prefix directory */ -#cmakedefine LLVM_PREFIX "${LLVM_PREFIX}" - /* Define if we have the Intel JIT API runtime support library */ #cmakedefine01 LLVM_USE_INTEL_JITEVENTS diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h index a327d450db55..487f3b6446fa 100644 --- a/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -14,8 +14,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> @@ -48,15 +48,13 @@ public: } // end namespace codeview -namespace msf { - template <typename Kind> struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> { - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::CVRecord<Kind> &Item) const { using namespace codeview; const RecordPrefix *Prefix = nullptr; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); uint32_t Offset = Reader.getOffset(); if (auto EC = Reader.readObject(Prefix)) @@ -76,8 +74,6 @@ struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> { } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H diff --git a/include/llvm/DebugInfo/CodeView/CVTypeDumper.h b/include/llvm/DebugInfo/CodeView/CVTypeDumper.h index e1dd6a10b5a1..02f14ea2107b 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeDumper.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeDumper.h @@ -22,10 +22,14 @@ namespace llvm { namespace codeview { +class TypeServerHandler; + /// Dumper for CodeView type streams found in COFF object files and PDB files. class CVTypeDumper { public: - explicit CVTypeDumper(TypeDatabase &TypeDB) : TypeDB(TypeDB) {} + explicit CVTypeDumper(TypeDatabase &TypeDB, + TypeServerHandler *Handler = nullptr) + : TypeDB(TypeDB), Handler(Handler) {} /// 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 @@ -48,6 +52,7 @@ public: private: TypeDatabase &TypeDB; + TypeServerHandler *Handler; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index d1b0363a4133..e9012db7602d 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -10,9 +10,10 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H -#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/Support/Error.h" @@ -23,18 +24,23 @@ class CVTypeVisitor { public: explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); + void addTypeServerHandler(TypeServerHandler &Handler); + Error visitTypeRecord(CVType &Record); Error visitMemberRecord(CVMemberRecord &Record); /// Visits the type records in Data. Sets the error flag on parse failures. Error visitTypeStream(const CVTypeArray &Types); + Error visitTypeStream(CVTypeRange Types); Error visitFieldListMemberStream(ArrayRef<uint8_t> FieldList); - Error visitFieldListMemberStream(msf::StreamReader Reader); + Error visitFieldListMemberStream(BinaryStreamReader Reader); private: /// The interface to the class that gets notified of each visitation. TypeVisitorCallbacks &Callbacks; + + TinyPtrVector<TypeServerHandler *> Handlers; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index e21cfa3d030a..2791c9dc3746 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -275,6 +275,12 @@ enum class MethodOptions : uint16_t { }; CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(MethodOptions) +/// Equivalent to CV_LABEL_TYPE_e. +enum class LabelType : uint16_t { + Near = 0x0, + Far = 0x4, +}; + /// Equivalent to CV_modifier_t. /// TODO: Add flag for _Atomic modifier enum class ModifierOptions : uint16_t { diff --git a/include/llvm/DebugInfo/CodeView/CodeViewError.h b/include/llvm/DebugInfo/CodeView/CodeViewError.h index 0556fd0e19f2..586a720ce6e4 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewError.h +++ b/include/llvm/DebugInfo/CodeView/CodeViewError.h @@ -21,6 +21,7 @@ enum class cv_error_code { insufficient_buffer, operation_unsupported, corrupt_record, + no_records, unknown_member_record, }; diff --git a/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h b/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h index 5a036b9d5b6c..b3976826a316 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h +++ b/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h @@ -17,8 +17,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" #include <cassert> #include <cstdint> @@ -33,8 +33,8 @@ class CodeViewRecordIO { } public: - explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {} - explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {} + explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {} + explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {} Error beginRecord(Optional<uint32_t> MaxLength); Error endRecord(); @@ -160,8 +160,8 @@ private: SmallVector<RecordLimit, 2> Limits; - msf::StreamReader *Reader = nullptr; - msf::StreamWriter *Writer = nullptr; + BinaryStreamReader *Reader = nullptr; + BinaryStreamWriter *Writer = nullptr; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/Formatters.h b/include/llvm/DebugInfo/CodeView/Formatters.h new file mode 100644 index 000000000000..37a91098a8b6 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/Formatters.h @@ -0,0 +1,40 @@ +//===- Formatters.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_FORMATTERS_H +#define LLVM_DEBUGINFO_CODEVIEW_FORMATTERS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatAdapters.h" + +namespace llvm { +namespace codeview { +namespace detail { +class GuidAdapter final : public llvm::FormatAdapter<ArrayRef<uint8_t>> { + ArrayRef<uint8_t> Guid; + +public: + explicit GuidAdapter(ArrayRef<uint8_t> Guid); + explicit GuidAdapter(StringRef Guid); + void format(llvm::raw_ostream &Stream, StringRef Style); +}; +} + +inline detail::GuidAdapter fmt_guid(StringRef Item) { + return detail::GuidAdapter(Item); +} + +inline detail::GuidAdapter fmt_guid(ArrayRef<uint8_t> Item) { + return detail::GuidAdapter(Item); +} +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h index 8860ae42fc09..a1c5c93cc3f8 100644 --- a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -11,8 +11,8 @@ #define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -59,23 +59,22 @@ struct ColumnNumberEntry { class ModuleSubstream { public: ModuleSubstream(); - ModuleSubstream(ModuleSubstreamKind Kind, msf::ReadableStreamRef Data); - static Error initialize(msf::ReadableStreamRef Stream, ModuleSubstream &Info); + ModuleSubstream(ModuleSubstreamKind Kind, BinaryStreamRef Data); + static Error initialize(BinaryStreamRef Stream, ModuleSubstream &Info); uint32_t getRecordLength() const; ModuleSubstreamKind getSubstreamKind() const; - msf::ReadableStreamRef getRecordData() const; + BinaryStreamRef getRecordData() const; private: ModuleSubstreamKind Kind; - msf::ReadableStreamRef Data; + BinaryStreamRef Data; }; -typedef msf::VarStreamArray<ModuleSubstream> ModuleSubstreamArray; +typedef VarStreamArray<ModuleSubstream> ModuleSubstreamArray; } // namespace codeview -namespace msf { template <> struct VarStreamArrayExtractor<codeview::ModuleSubstream> { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, + Error operator()(BinaryStreamRef Stream, uint32_t &Length, codeview::ModuleSubstream &Info) const { if (auto EC = codeview::ModuleSubstream::initialize(Stream, Info)) return EC; @@ -83,7 +82,6 @@ template <> struct VarStreamArrayExtractor<codeview::ModuleSubstream> { return Error::success(); } }; -} // namespace msf } // namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h index f9927d660933..1a40654a3f33 100644 --- a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -15,9 +15,9 @@ #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> @@ -28,8 +28,8 @@ namespace codeview { struct LineColumnEntry { support::ulittle32_t NameIndex; - msf::FixedStreamArray<LineNumberEntry> LineNumbers; - msf::FixedStreamArray<ColumnNumberEntry> Columns; + FixedStreamArray<LineNumberEntry> LineNumbers; + FixedStreamArray<ColumnNumberEntry> Columns; }; struct FileChecksumEntry { @@ -38,49 +38,47 @@ struct FileChecksumEntry { ArrayRef<uint8_t> Checksum; // The bytes of the checksum. }; -typedef msf::VarStreamArray<LineColumnEntry> LineInfoArray; -typedef msf::VarStreamArray<FileChecksumEntry> FileChecksumArray; +typedef VarStreamArray<LineColumnEntry> LineInfoArray; +typedef VarStreamArray<FileChecksumEntry> FileChecksumArray; class IModuleSubstreamVisitor { public: virtual ~IModuleSubstreamVisitor() = default; virtual Error visitUnknown(ModuleSubstreamKind Kind, - msf::ReadableStreamRef Data) = 0; - virtual Error visitSymbols(msf::ReadableStreamRef Data); - virtual Error visitLines(msf::ReadableStreamRef Data, + BinaryStreamRef Data) = 0; + virtual Error visitSymbols(BinaryStreamRef Data); + virtual Error visitLines(BinaryStreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines); - virtual Error visitStringTable(msf::ReadableStreamRef Data); - virtual Error visitFileChecksums(msf::ReadableStreamRef Data, + virtual Error visitStringTable(BinaryStreamRef Data); + virtual Error visitFileChecksums(BinaryStreamRef Data, const FileChecksumArray &Checksums); - virtual Error visitFrameData(msf::ReadableStreamRef Data); - virtual Error visitInlineeLines(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeImports(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeExports(msf::ReadableStreamRef Data); - virtual Error visitILLines(msf::ReadableStreamRef Data); - virtual Error visitFuncMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitTypeMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitMergedAssemblyInput(msf::ReadableStreamRef Data); - virtual Error visitCoffSymbolRVA(msf::ReadableStreamRef Data); + virtual Error visitFrameData(BinaryStreamRef Data); + virtual Error visitInlineeLines(BinaryStreamRef Data); + virtual Error visitCrossScopeImports(BinaryStreamRef Data); + virtual Error visitCrossScopeExports(BinaryStreamRef Data); + virtual Error visitILLines(BinaryStreamRef Data); + virtual Error visitFuncMDTokenMap(BinaryStreamRef Data); + virtual Error visitTypeMDTokenMap(BinaryStreamRef Data); + virtual Error visitMergedAssemblyInput(BinaryStreamRef Data); + virtual Error visitCoffSymbolRVA(BinaryStreamRef Data); }; Error visitModuleSubstream(const ModuleSubstream &R, IModuleSubstreamVisitor &V); } // end namespace codeview -namespace msf { - template <> class VarStreamArrayExtractor<codeview::LineColumnEntry> { public: VarStreamArrayExtractor(const codeview::LineSubstreamHeader *Header) : Header(Header) {} - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::LineColumnEntry &Item) const { using namespace codeview; const LineFileBlockHeader *BlockHeader; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); if (auto EC = Reader.readObject(BlockHeader)) return EC; bool HasColumn = Header->Flags & LineFlags::HaveColumns; @@ -113,11 +111,11 @@ private: template <> class VarStreamArrayExtractor<codeview::FileChecksumEntry> { public: - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::FileChecksumEntry &Item) const { using namespace codeview; const FileChecksum *Header; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); if (auto EC = Reader.readObject(Header)) return EC; Item.FileNameOffset = Header->FileNameOffset; @@ -129,8 +127,6 @@ public: } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/RecordSerialization.h b/include/llvm/DebugInfo/CodeView/RecordSerialization.h index 97b6f561bb97..58449c2c7565 100644 --- a/include/llvm/DebugInfo/CodeView/RecordSerialization.h +++ b/include/llvm/DebugInfo/CodeView/RecordSerialization.h @@ -15,7 +15,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cinttypes> @@ -41,37 +41,37 @@ struct RecordPrefix { StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData); StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData); -inline Error consume(msf::StreamReader &Reader) { return Error::success(); } +inline Error consume(BinaryStreamReader &Reader) { return Error::success(); } /// 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. -Error consume(msf::StreamReader &Reader, APSInt &Num); +Error consume(BinaryStreamReader &Reader, APSInt &Num); /// Decodes a numeric leaf value that is known to be a particular type. -Error consume_numeric(msf::StreamReader &Reader, uint64_t &Value); +Error consume_numeric(BinaryStreamReader &Reader, uint64_t &Value); /// Decodes signed and unsigned fixed-length integers. -Error consume(msf::StreamReader &Reader, uint32_t &Item); -Error consume(msf::StreamReader &Reader, int32_t &Item); +Error consume(BinaryStreamReader &Reader, uint32_t &Item); +Error consume(BinaryStreamReader &Reader, int32_t &Item); /// Decodes a null terminated string. -Error consume(msf::StreamReader &Reader, StringRef &Item); +Error consume(BinaryStreamReader &Reader, StringRef &Item); Error consume(StringRef &Data, APSInt &Num); Error consume(StringRef &Data, uint32_t &Item); /// Decodes an arbitrary object whose layout matches that of the underlying /// byte sequence, and returns a pointer to the object. -template <typename T> Error consume(msf::StreamReader &Reader, T *&Item) { +template <typename T> Error consume(BinaryStreamReader &Reader, T *&Item) { return Reader.readObject(Item); } template <typename T, typename U> struct serialize_conditional_impl { serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { if (!Func()) return Error::success(); return consume(Reader, Item); @@ -89,7 +89,7 @@ serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) { template <typename T, typename U> struct serialize_array_impl { serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { return Reader.readArray(Item, Func()); } @@ -100,7 +100,7 @@ template <typename T, typename U> struct serialize_array_impl { template <typename T> struct serialize_vector_tail_impl { serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { T Field; // Stop when we run out of bytes or we hit record padding bytes. while (!Reader.empty() && Reader.peek() < LF_PAD0) { @@ -118,14 +118,14 @@ struct serialize_null_term_string_array_impl { serialize_null_term_string_array_impl(std::vector<StringRef> &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { if (Reader.empty()) return make_error<CodeViewError>(cv_error_code::insufficient_buffer, "Null terminated string is empty!"); while (Reader.peek() != 0) { StringRef Field; - if (auto EC = Reader.readZeroString(Field)) + if (auto EC = Reader.readCString(Field)) return EC; Item.push_back(Field); } @@ -138,7 +138,7 @@ struct serialize_null_term_string_array_impl { template <typename T> struct serialize_arrayref_tail_impl { serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { uint32_t Count = Reader.bytesRemaining() / sizeof(T); return Reader.readArray(Item, Count); } @@ -149,7 +149,7 @@ template <typename T> struct serialize_arrayref_tail_impl { template <typename T> struct serialize_numeric_impl { serialize_numeric_impl(T &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { return consume_numeric(Reader, Item); } @@ -201,42 +201,42 @@ template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) { #define CV_NUMERIC_FIELD(I) serialize_numeric(I) template <typename T, typename U> -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_conditional_impl<T, U> &Item) { return Item.deserialize(Reader); } template <typename T, typename U> -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_array_impl<T, U> &Item) { return Item.deserialize(Reader); } -inline Error consume(msf::StreamReader &Reader, +inline Error consume(BinaryStreamReader &Reader, const serialize_null_term_string_array_impl &Item) { return Item.deserialize(Reader); } template <typename T> -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_vector_tail_impl<T> &Item) { return Item.deserialize(Reader); } template <typename T> -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_arrayref_tail_impl<T> &Item) { return Item.deserialize(Reader); } template <typename T> -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_numeric_impl<T> &Item) { return Item.deserialize(Reader); } template <typename T, typename U, typename... Args> -Error consume(msf::StreamReader &Reader, T &&X, U &&Y, Args &&... Rest) { +Error consume(BinaryStreamReader &Reader, T &&X, U &&Y, Args &&... Rest) { if (auto EC = consume(Reader, X)) return EC; return consume(Reader, Y, std::forward<Args>(Rest)...); diff --git a/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h b/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h index 13c2bb14ecf5..c1a5152930ff 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ b/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" namespace llvm { @@ -25,10 +25,11 @@ class SymbolVisitorDelegate; class SymbolDeserializer : public SymbolVisitorCallbacks { struct MappingInfo { explicit MappingInfo(ArrayRef<uint8_t> RecordData) - : Stream(RecordData), Reader(Stream), Mapping(Reader) {} + : Stream(RecordData, llvm::support::little), Reader(Stream), + Mapping(Reader) {} - msf::ByteStream Stream; - msf::StreamReader Reader; + BinaryByteStream Stream; + BinaryStreamReader Reader; SymbolRecordMapping Mapping; }; diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h index 57772d39e972..c5a5549bf818 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -13,13 +13,13 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstddef> @@ -176,7 +176,7 @@ struct BinaryAnnotationIterator { return Data == Other.Data; } - bool operator!=(BinaryAnnotationIterator Other) const { + bool operator!=(const BinaryAnnotationIterator &Other) const { return !(*this == Other); } @@ -938,7 +938,7 @@ public: }; typedef CVRecord<SymbolKind> CVSymbol; -typedef msf::VarStreamArray<CVSymbol> CVSymbolArray; +typedef VarStreamArray<CVSymbol> CVSymbolArray; } // end namespace codeview } // end namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h b/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h index 1bd14ed1347a..0a1837a0d935 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h @@ -14,16 +14,14 @@ #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" namespace llvm { -namespace msf { -class StreamReader; -class StreamWriter; -} +class BinaryStreamReader; +class BinaryStreamWriter; namespace codeview { class SymbolRecordMapping : public SymbolVisitorCallbacks { public: - explicit SymbolRecordMapping(msf::StreamReader &Reader) : IO(Reader) {} - explicit SymbolRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {} + explicit SymbolRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {} + explicit SymbolRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {} Error visitSymbolBegin(CVSymbol &Record) override; Error visitSymbolEnd(CVSymbol &Record) override; diff --git a/include/llvm/DebugInfo/CodeView/SymbolSerializer.h b/include/llvm/DebugInfo/CodeView/SymbolSerializer.h index 4eb914e7ae6b..f2e99bd83326 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolSerializer.h +++ b/include/llvm/DebugInfo/CodeView/SymbolSerializer.h @@ -12,8 +12,6 @@ #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -21,14 +19,19 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" namespace llvm { +class BinaryStreamWriter; namespace codeview { class SymbolSerializer : public SymbolVisitorCallbacks { - uint32_t RecordStart = 0; - msf::StreamWriter &Writer; + BumpPtrAllocator &Storage; + std::vector<uint8_t> RecordBuffer; + MutableBinaryByteStream Stream; + BinaryStreamWriter Writer; SymbolRecordMapping Mapping; Optional<SymbolKind> CurrentSymbol; @@ -42,40 +45,10 @@ class SymbolSerializer : public SymbolVisitorCallbacks { } public: - explicit SymbolSerializer(msf::StreamWriter &Writer) - : Writer(Writer), Mapping(Writer) {} + explicit SymbolSerializer(BumpPtrAllocator &Storage); - virtual Error visitSymbolBegin(CVSymbol &Record) override { - assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!"); - - RecordStart = Writer.getOffset(); - if (auto EC = writeRecordPrefix(Record.kind())) - return EC; - - CurrentSymbol = Record.kind(); - if (auto EC = Mapping.visitSymbolBegin(Record)) - return EC; - - return Error::success(); - } - - virtual Error visitSymbolEnd(CVSymbol &Record) override { - assert(CurrentSymbol.hasValue() && "Not in a symbol mapping!"); - - if (auto EC = Mapping.visitSymbolEnd(Record)) - return EC; - - uint32_t RecordEnd = Writer.getOffset(); - Writer.setOffset(RecordStart); - uint16_t Length = RecordEnd - Writer.getOffset() - 2; - if (auto EC = Writer.writeInteger(Length)) - return EC; - - Writer.setOffset(RecordEnd); - CurrentSymbol.reset(); - - return Error::success(); - } + virtual Error visitSymbolBegin(CVSymbol &Record) override; + virtual Error visitSymbolEnd(CVSymbol &Record) override; #define SYMBOL_RECORD(EnumName, EnumVal, Name) \ virtual Error visitKnownRecord(CVSymbol &CVR, Name &Record) override { \ diff --git a/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h index 2b468a289fd8..2bef3f61adfc 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h +++ b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h @@ -15,9 +15,7 @@ namespace llvm { -namespace msf { -class StreamReader; -} // end namespace msf +class BinaryStreamReader; namespace codeview { @@ -25,7 +23,7 @@ class SymbolVisitorDelegate { public: virtual ~SymbolVisitorDelegate() = default; - virtual uint32_t getRecordOffset(msf::StreamReader Reader) = 0; + virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0; virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0; virtual StringRef getStringTable() = 0; }; diff --git a/include/llvm/DebugInfo/CodeView/TypeDatabase.h b/include/llvm/DebugInfo/CodeView/TypeDatabase.h index cccc2868ffb5..54ad862cfa7e 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDatabase.h +++ b/include/llvm/DebugInfo/CodeView/TypeDatabase.h @@ -27,13 +27,15 @@ public: TypeIndex getNextTypeIndex() const; /// Records the name of a type, and reserves its type index. - void recordType(StringRef Name, CVType Data); + void recordType(StringRef Name, const CVType &Data); /// Saves the name in a StringSet and creates a stable StringRef. StringRef saveTypeName(StringRef TypeName); StringRef getTypeName(TypeIndex Index) const; + const CVType &getTypeRecord(TypeIndex Index) const; + bool containsTypeIndex(TypeIndex Index) const; uint32_t size() const; diff --git a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h index dc5eaf82845b..0e3443789170 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -16,8 +16,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include <cassert> #include <cstdint> @@ -29,10 +29,11 @@ namespace codeview { class TypeDeserializer : public TypeVisitorCallbacks { struct MappingInfo { explicit MappingInfo(ArrayRef<uint8_t> RecordData) - : Stream(RecordData), Reader(Stream), Mapping(Reader) {} + : Stream(RecordData, llvm::support::little), Reader(Stream), + Mapping(Reader) {} - msf::ByteStream Stream; - msf::StreamReader Reader; + BinaryByteStream Stream; + BinaryStreamReader Reader; TypeRecordMapping Mapping; }; @@ -72,16 +73,16 @@ private: class FieldListDeserializer : public TypeVisitorCallbacks { struct MappingInfo { - explicit MappingInfo(msf::StreamReader &R) + explicit MappingInfo(BinaryStreamReader &R) : Reader(R), Mapping(Reader), StartOffset(0) {} - msf::StreamReader &Reader; + BinaryStreamReader &Reader; TypeRecordMapping Mapping; uint32_t StartOffset; }; public: - explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) { + explicit FieldListDeserializer(BinaryStreamReader &Reader) : Mapping(Reader) { CVType FieldList; FieldList.Type = TypeLeafKind::LF_FIELDLIST; consumeError(Mapping.Mapping.visitTypeBegin(FieldList)); diff --git a/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h b/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h index a466e4298158..00bb09137e48 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h +++ b/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h @@ -28,8 +28,16 @@ public: TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes) : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {} + /// When dumping types from an IPI stream in a PDB, a type index may refer to + /// a type or an item ID. The dumper will lookup the "name" of the index in + /// the item database if appropriate. If ItemDB is null, it will use TypeDB, + /// which is correct when dumping types from an object file (/Z7). + void setItemDB(TypeDatabase &DB) { ItemDB = &DB; } + void printTypeIndex(StringRef FieldName, TypeIndex TI) const; + void printItemIndex(StringRef FieldName, TypeIndex TI) const; + /// Action to take on unknown types. By default, they are ignored. Error visitUnknownType(CVType &Record) override; Error visitUnknownMember(CVMemberRecord &Record) override; @@ -54,11 +62,17 @@ private: void printMemberAttributes(MemberAccess Access, MethodKind Kind, MethodOptions Options); + /// Get the database of indices for the stream that we are dumping. If ItemDB + /// is set, then we must be dumping an item (IPI) stream. This will also + /// always get the appropriate DB for printing item names. + TypeDatabase &getSourceDB() const { return ItemDB ? *ItemDB : TypeDB; } + ScopedPrinter *W; bool PrintRecordBytes = false; TypeDatabase &TypeDB; + TypeDatabase *ItemDB = nullptr; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h index 4f1c047815d2..1f10872c8768 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -18,7 +18,7 @@ #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include <algorithm> #include <cstdint> @@ -26,9 +26,7 @@ namespace llvm { -namespace msf { -class StreamReader; -} // end namespace msf +class BinaryStreamReader; namespace codeview { @@ -42,7 +40,8 @@ struct CVMemberRecord { TypeLeafKind Kind; ArrayRef<uint8_t> Data; }; -typedef msf::VarStreamArray<CVType> CVTypeArray; +typedef VarStreamArray<CVType> CVTypeArray; +typedef iterator_range<CVTypeArray::Iterator> CVTypeRange; /// Equvalent to CV_fldattr_t in cvinfo.h. struct MemberAttributes { @@ -106,10 +105,6 @@ public: 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); - TypeIndex getContainingType() const { return ContainingType; } PointerToMemberRepresentation getRepresentation() const { return Representation; @@ -139,10 +134,6 @@ public: : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), Modifiers(Modifiers) {} - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getModifiedType() const { return ModifiedType; } ModifierOptions getModifiers() const { return Modifiers; } @@ -161,10 +152,6 @@ 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); - TypeIndex getReturnType() const { return ReturnType; } CallingConvention getCallConv() const { return CallConv; } FunctionOptions getOptions() const { return Options; } @@ -193,10 +180,6 @@ 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); - TypeIndex getReturnType() const { return ReturnType; } TypeIndex getClassType() const { return ClassType; } TypeIndex getThisType() const { return ThisType; } @@ -216,6 +199,16 @@ public: int32_t ThisPointerAdjustment; }; +// LF_LABEL +class LabelRecord : public TypeRecord { +public: + explicit LabelRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + + LabelRecord(LabelType Mode) : TypeRecord(TypeRecordKind::Label), Mode(Mode) {} + + LabelType Mode; +}; + // LF_MFUNC_ID class MemberFuncIdRecord : public TypeRecord { public: @@ -225,10 +218,6 @@ public: : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType), 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); - TypeIndex getClassType() const { return ClassType; } TypeIndex getFunctionType() const { return FunctionType; } StringRef getName() const { return Name; } @@ -237,17 +226,26 @@ public: StringRef Name; }; -// LF_ARGLIST, LF_SUBSTR_LIST +// LF_ARGLIST class ArgListRecord : public TypeRecord { public: explicit ArgListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} ArgListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices) - : TypeRecord(Kind), StringIndices(Indices) {} + : TypeRecord(Kind), ArgIndices(Indices) {} - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); + ArrayRef<TypeIndex> getIndices() const { return ArgIndices; } + + std::vector<TypeIndex> ArgIndices; +}; + +// LF_SUBSTR_LIST +class StringListRecord : public TypeRecord { +public: + explicit StringListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + + StringListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices) + : TypeRecord(Kind), StringIndices(Indices) {} ArrayRef<TypeIndex> getIndices() const { return StringIndices; } @@ -290,10 +288,6 @@ public: : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType), Attrs(Attrs), MemberInfo(Member) {} - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getReferentType() const { return ReferentType; } PointerKind getPointerKind() const { @@ -356,10 +350,6 @@ public: NestedTypeRecord(TypeIndex Type, StringRef Name) : TypeRecord(TypeRecordKind::NestedType), 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); - TypeIndex getNestedType() const { return Type; } StringRef getName() const { return Name; } @@ -374,10 +364,6 @@ public: explicit FieldListRecord(ArrayRef<uint8_t> Data) : TypeRecord(TypeRecordKind::FieldList), Data(Data) {} - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap) { return false; } - ArrayRef<uint8_t> Data; }; @@ -390,10 +376,6 @@ public: : 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); - TypeIndex getElementType() const { return ElementType; } TypeIndex getIndexType() const { return IndexType; } uint64_t getSize() const { return Size; } @@ -414,10 +396,6 @@ 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; @@ -451,10 +429,6 @@ public: : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName), 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); - HfaKind getHfa() const { uint16_t Value = static_cast<uint16_t>(Options); Value = (Value & HfaKindMask) >> HfaKindShift; @@ -506,9 +480,6 @@ 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); - TypeIndex getUnderlyingType() const { return UnderlyingType; } TypeIndex UnderlyingType; }; @@ -521,10 +492,6 @@ public: : 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); - TypeIndex getType() const { return Type; } uint8_t getBitOffset() const { return BitOffset; } uint8_t getBitSize() const { return BitSize; } @@ -542,10 +509,6 @@ public: 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); - ArrayRef<VFTableSlotKind> getSlots() const { if (!SlotsRef.empty()) return SlotsRef; @@ -565,10 +528,6 @@ public: : 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); - StringRef getGuid() const { return Guid; } uint32_t getAge() const { return Age; } @@ -587,10 +546,6 @@ 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); - TypeIndex getId() const { return Id; } StringRef getString() const { return String; } @@ -606,10 +561,6 @@ public: : 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); - TypeIndex getParentScope() const { return ParentScope; } TypeIndex getFunctionType() const { return FunctionType; } @@ -629,10 +580,6 @@ public: : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), SourceFile(SourceFile), LineNumber(LineNumber) {} - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getUDT() const { return UDT; } TypeIndex getSourceFile() const { return SourceFile; } uint32_t getLineNumber() const { return LineNumber; } @@ -651,8 +598,6 @@ public: : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), SourceFile(SourceFile), LineNumber(LineNumber), Module(Module) {} - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getUDT() const { return UDT; } TypeIndex getSourceFile() const { return SourceFile; } uint32_t getLineNumber() const { return LineNumber; } @@ -672,10 +617,6 @@ public: : 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); - ArrayRef<TypeIndex> getArgs() const { return ArgIndices; } SmallVector<TypeIndex, 4> ArgIndices; }; @@ -693,10 +634,6 @@ public: MethodNames.insert(MethodNames.end(), Methods.begin(), Methods.end()); } - /// Rewrite member type indices with IndexMap. Returns false if a type index - /// is not in the map. - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex getCompleteClass() const { return CompleteClass; } TypeIndex getOverriddenVTable() const { return OverriddenVFTable; } uint32_t getVFPtrOffset() const { return VFPtrOffset; } @@ -725,10 +662,6 @@ public: : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Attrs(Access, MK, Options), 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); - TypeIndex getType() const { return Type; } MethodKind getMethodKind() const { return Attrs.getMethodKind(); } MethodOptions getOptions() const { return Attrs.getFlags(); } @@ -754,10 +687,6 @@ 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); - ArrayRef<OneMethodRecord> getMethods() const { return Methods; } std::vector<OneMethodRecord> Methods; }; @@ -771,10 +700,6 @@ public: : 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); - uint16_t getNumOverloads() const { return NumOverloads; } TypeIndex getMethodList() const { return MethodList; } StringRef getName() const { return Name; } @@ -796,10 +721,6 @@ public: : TypeRecord(TypeRecordKind::DataMember), Attrs(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); - MemberAccess getAccess() const { return Attrs.getAccess(); } TypeIndex getType() const { return Type; } uint64_t getFieldOffset() const { return FieldOffset; } @@ -822,10 +743,6 @@ public: : TypeRecord(TypeRecordKind::StaticDataMember), Attrs(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); - MemberAccess getAccess() const { return Attrs.getAccess(); } TypeIndex getType() const { return Type; } StringRef getName() const { return Name; } @@ -846,10 +763,6 @@ public: : TypeRecord(TypeRecordKind::Enumerator), Attrs(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); - MemberAccess getAccess() const { return Attrs.getAccess(); } APSInt getValue() const { return Value; } StringRef getName() const { return Name; } @@ -866,10 +779,6 @@ 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); - TypeIndex getType() const { return Type; } TypeIndex Type; @@ -886,10 +795,6 @@ public: : TypeRecord(TypeRecordKind::BaseClass), Attrs(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); - MemberAccess getAccess() const { return Attrs.getAccess(); } TypeIndex getBaseType() const { return Type; } uint64_t getBaseOffset() const { return Offset; } @@ -914,10 +819,6 @@ public: : TypeRecord(Kind), Attrs(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); - MemberAccess getAccess() const { return Attrs.getAccess(); } TypeIndex getBaseType() const { return BaseType; } TypeIndex getVBPtrType() const { return VBPtrType; } @@ -942,8 +843,6 @@ public: TypeIndex getContinuationIndex() const { return ContinuationIndex; } - bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap); - TypeIndex ContinuationIndex; }; diff --git a/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h b/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h index fe470a72abbb..924ca0470fad 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h @@ -16,15 +16,14 @@ #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class StreamReader; -class StreamWriter; -} +class BinaryStreamReader; +class BinaryStreamWriter; + namespace codeview { class TypeRecordMapping : public TypeVisitorCallbacks { public: - explicit TypeRecordMapping(msf::StreamReader &Reader) : IO(Reader) {} - explicit TypeRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {} + explicit TypeRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {} + explicit TypeRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {} Error visitTypeBegin(CVType &Record) override; Error visitTypeEnd(CVType &Record) override; diff --git a/include/llvm/DebugInfo/CodeView/TypeRecords.def b/include/llvm/DebugInfo/CodeView/TypeRecords.def index c98dbac21a7a..8c193bb13cb7 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecords.def +++ b/include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -41,6 +41,7 @@ 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_LABEL, 0x000e, Label) TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList) TYPE_RECORD(LF_FIELDLIST, 0x1203, FieldList) @@ -79,9 +80,7 @@ MEMBER_RECORD(LF_INDEX, 0x1404, ListContinuation) 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_SUBSTR_LIST, 0x1604, StringList) TYPE_RECORD(LF_STRING_ID, 0x1605, StringId) TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine) TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine) @@ -103,7 +102,6 @@ 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) diff --git a/include/llvm/DebugInfo/CodeView/TypeSerializer.h b/include/llvm/DebugInfo/CodeView/TypeSerializer.h index e05922194638..1f4873c4f969 100644 --- a/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ b/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -12,8 +12,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -56,8 +56,8 @@ class TypeSerializer : public TypeVisitorCallbacks { Optional<TypeLeafKind> TypeKind; Optional<TypeLeafKind> MemberKind; std::vector<uint8_t> RecordBuffer; - msf::MutableByteStream Stream; - msf::StreamWriter Writer; + MutableBinaryByteStream Stream; + BinaryStreamWriter Writer; TypeRecordMapping Mapping; RecordList SeenRecords; diff --git a/include/llvm/DebugInfo/CodeView/TypeServerHandler.h b/include/llvm/DebugInfo/CodeView/TypeServerHandler.h new file mode 100644 index 000000000000..35f06eaf6eb4 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeServerHandler.h @@ -0,0 +1,36 @@ +//===- TypeServerHandler.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_TYPESERVERHANDLER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H + +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class TypeVisitorCallbacks; + +class TypeServerHandler { +public: + virtual ~TypeServerHandler() {} + + /// Handle a TypeServer record. If the implementation returns true + /// the record will not be processed by the top-level visitor. If + /// it returns false, it will be processed. If it returns an Error, + /// then the top-level visitor will fail. + virtual Expected<bool> handle(TypeServer2Record &TS, + TypeVisitorCallbacks &Callbacks) { + return false; + } +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h index af396c79d074..2246f197e784 100644 --- a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h +++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -13,12 +13,17 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/Support/Error.h" namespace llvm { namespace codeview { +class TypeServerHandler; + /// Merges one type stream into another. Returns true on success. -bool mergeTypeStreams(TypeTableBuilder &DestStream, const CVTypeArray &Types); +Error mergeTypeStreams(TypeTableBuilder &DestIdStream, + TypeTableBuilder &DestTypeStream, + TypeServerHandler *Handler, const CVTypeArray &Types); } // end namespace codeview } // end namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h index 4e6d81ece318..102bee4b0801 100644 --- a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -121,6 +121,12 @@ public: } return Index; } + + /// Stop building the record. + void reset() { + if (auto EC = TempSerializer.visitTypeEnd(Type)) + consumeError(std::move(EC)); + } }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 804419c517df..e3386a8dcd24 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -1,4 +1,4 @@ -//===-- DIContext.h ---------------------------------------------*- C++ -*-===// +//===- DIContext.h ----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -32,26 +32,28 @@ class raw_ostream; struct DILineInfo { std::string FileName; std::string FunctionName; - uint32_t Line; - uint32_t Column; + uint32_t Line = 0; + uint32_t Column = 0; + uint32_t StartLine = 0; // DWARF-specific. - uint32_t Discriminator; + uint32_t Discriminator = 0; - DILineInfo() - : FileName("<invalid>"), FunctionName("<invalid>"), Line(0), Column(0), - Discriminator(0) {} + DILineInfo() : FileName("<invalid>"), FunctionName("<invalid>") {} bool operator==(const DILineInfo &RHS) const { return Line == RHS.Line && Column == RHS.Column && - FileName == RHS.FileName && FunctionName == RHS.FunctionName; + FileName == RHS.FileName && FunctionName == RHS.FunctionName && + StartLine == RHS.StartLine && Discriminator == RHS.Discriminator; } bool operator!=(const DILineInfo &RHS) const { return !(*this == RHS); } bool operator<(const DILineInfo &RHS) const { - return std::tie(FileName, FunctionName, Line, Column) < - std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column); + return std::tie(FileName, FunctionName, Line, Column, StartLine, + Discriminator) < + std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column, + RHS.StartLine, RHS.Discriminator); } }; @@ -86,10 +88,10 @@ public: /// DIGlobal - container for description of a global variable. struct DIGlobal { std::string Name; - uint64_t Start; - uint64_t Size; + uint64_t Start = 0; + uint64_t Size = 0; - DIGlobal() : Name("<invalid>"), Start(0), Size(0) {} + DIGlobal() : Name("<invalid>") {} }; /// A DINameKind is passed to name search methods to specify a @@ -175,8 +177,8 @@ private: /// on the fly. class LoadedObjectInfo { protected: - LoadedObjectInfo(const LoadedObjectInfo &) = default; LoadedObjectInfo() = default; + LoadedObjectInfo(const LoadedObjectInfo &) = default; public: virtual ~LoadedObjectInfo() = default; diff --git a/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h b/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h index db9bd506be89..7324f6e3eb38 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -1,4 +1,4 @@ -//===-- DWARFAbbreviationDeclaration.h --------------------------*- C++ -*-===// +//===- DWARFAbbreviationDeclaration.h ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,22 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H -#define LLVM_LIB_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#ifndef LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#define LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" +#include <cassert> +#include <cstddef> +#include <cstdint> + namespace llvm { -class DWARFUnit; class DWARFFormValue; +class DWARFUnit; class raw_ostream; class DWARFAbbreviationDeclaration { @@ -25,6 +30,7 @@ public: struct AttributeSpec { AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional<int64_t> V) : Attr(A), Form(F), ByteSizeOrValue(V) {} + dwarf::Attribute Attr; dwarf::Form Form; /// The following field is used for ByteSize for non-implicit_const @@ -41,9 +47,11 @@ public: /// * Form == DW_FORM_implicit_const: /// ByteSizeOrValue contains value for the implicit_const attribute. Optional<int64_t> ByteSizeOrValue; + bool isImplicitConst() const { return Form == dwarf::DW_FORM_implicit_const; } + /// Get the fixed byte size of this Form if possible. This function might /// use the DWARFUnit to calculate the size of the Form, like for /// DW_AT_address and DW_AT_ref_addr, so this isn't just an accessor for @@ -55,6 +63,7 @@ public: DWARFAbbreviationDeclaration(); uint32_t getCode() const { return Code; } + uint8_t getCodeByteSize() const { return CodeByteSize; } dwarf::Tag getTag() const { return Tag; } bool hasChildren() const { return HasChildren; } @@ -66,9 +75,17 @@ public: } dwarf::Form getFormByIndex(uint32_t idx) const { - if (idx < AttributeSpecs.size()) - return AttributeSpecs[idx].Form; - return dwarf::Form(0); + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Form; + } + + size_t getNumAttributes() const { + return AttributeSpecs.size(); + } + + dwarf::Attribute getAttrByIndex(uint32_t idx) const { + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Attr; } /// Get the index of the specified attribute. @@ -109,16 +126,16 @@ private: /// abbreviation declaration. struct FixedSizeInfo { /// The fixed byte size for fixed size forms. - uint16_t NumBytes; + uint16_t NumBytes = 0; /// Number of DW_FORM_address forms in this abbrevation declaration. - uint8_t NumAddrs; + uint8_t NumAddrs = 0; /// Number of DW_FORM_ref_addr forms in this abbrevation declaration. - uint8_t NumRefAddrs; + uint8_t NumRefAddrs = 0; /// Number of 4 byte in DWARF32 and 8 byte in DWARF64 forms. - uint8_t NumDwarfOffsets; - /// Constructor - FixedSizeInfo() - : NumBytes(0), NumAddrs(0), NumRefAddrs(0), NumDwarfOffsets(0) {} + uint8_t NumDwarfOffsets = 0; + + FixedSizeInfo() = default; + /// Calculate the fixed size in bytes given a DWARFUnit. /// /// \param U the DWARFUnit to use when determing the byte size. @@ -138,6 +155,6 @@ private: Optional<FixedSizeInfo> FixedAttributeSize; }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 63343728fa99..f95a013d7552 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -1,4 +1,4 @@ -//===--- DWARFAcceleratorTable.h --------------------------------*- C++ -*-===// +//===- DWARFAcceleratorTable.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,19 +7,21 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFACCELERATORTABLE_H -#define LLVM_LIB_DEBUGINFO_DWARFACCELERATORTABLE_H +#ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H +#define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" #include <cstdint> +#include <utility> namespace llvm { -class DWARFAcceleratorTable { +class raw_ostream; +class DWARFAcceleratorTable { struct Header { uint32_t Magic; uint16_t Version; @@ -41,6 +43,7 @@ class DWARFAcceleratorTable { DataExtractor AccelSection; DataExtractor StringSection; const RelocAddrMap& Relocs; + public: DWARFAcceleratorTable(DataExtractor AccelSection, DataExtractor StringSection, const RelocAddrMap &Relocs) @@ -50,6 +53,6 @@ public: void dump(raw_ostream &OS) const; }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFAttribute.h b/include/llvm/DebugInfo/DWARF/DWARFAttribute.h new file mode 100644 index 000000000000..5919aaddea40 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFAttribute.h @@ -0,0 +1,56 @@ +//===- DWARFAttribute.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_DWARFATTRIBUTE_H +#define LLVM_DEBUGINFO_DWARFATTRIBUTE_H + +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Support/Dwarf.h" +#include <cstdint> + +namespace llvm { + +//===----------------------------------------------------------------------===// +/// Encapsulates a DWARF attribute value and all of the data required to +/// describe the attribute value. +/// +/// This class is designed to be used by clients that want to iterate across all +/// attributes in a DWARFDie. +struct DWARFAttribute { + /// The debug info/types offset for this attribute. + uint32_t Offset = 0; + /// The debug info/types section byte size of the data for this attribute. + uint32_t ByteSize = 0; + /// The attribute enumeration of this attribute. + dwarf::Attribute Attr; + /// The form and value for this attribute. + DWARFFormValue Value; + + DWARFAttribute(uint32_t O, dwarf::Attribute A = dwarf::Attribute(0), + dwarf::Form F = dwarf::Form(0)) : Attr(A), Value(F) {} + + bool isValid() const { + return Offset != 0 && Attr != dwarf::Attribute(0); + } + + explicit operator bool() const { + return isValid(); + } + + void clear() { + Offset = 0; + ByteSize = 0; + Attr = dwarf::Attribute(0); + Value = DWARFFormValue(); + } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFATTRIBUTE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index bba3abe6e9e9..b2a4d247ccc6 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -1,4 +1,4 @@ -//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===// +//===- DWARFCompileUnit.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFCOMPILEUNIT_H -#define LLVM_LIB_DEBUGINFO_DWARFCOMPILEUNIT_H +#ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H +#define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H #include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" namespace llvm { @@ -23,12 +24,15 @@ public: const DWARFUnitIndex::Entry *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. ~DWARFCompileUnit() override; + + void dump(raw_ostream &OS); + + static const DWARFSectionKind Section = DW_SECT_INFO; }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index ef310e704005..f941cdd1060a 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -1,4 +1,4 @@ -//===-- DWARFContext.h ------------------------------------------*- C++ -*-===// +//===- DWARFContext.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,15 @@ // //===----------------------------------------------------------------------===/ -#ifndef LLVM_LIB_DEBUGINFO_DWARFCONTEXT_H -#define LLVM_LIB_DEBUGINFO_DWARFCONTEXT_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H +#define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" @@ -30,6 +31,7 @@ #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Host.h" #include <cstdint> #include <deque> #include <map> @@ -38,6 +40,9 @@ namespace llvm { +class MemoryBuffer; +class raw_ostream; + // In place of applying the relocations to the data we've read from disk we use // a separate mapping table to the side and checking that at locations in the // dwarf where we expect relocated values. This adds a bit of complexity to the @@ -293,10 +298,16 @@ class DWARFContextInMemory : public DWARFContext { SmallVector<SmallString<32>, 4> UncompressedSections; + StringRef *MapSectionToMember(StringRef Name); + public: DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr); + DWARFContextInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, + bool isLittleEndian = sys::IsLittleEndianHost); + bool isLittleEndian() const override { return IsLittleEndian; } uint8_t getAddressSize() const override { return AddressSize; } const DWARFSection &getInfoSection() override { return InfoSection; } @@ -321,20 +332,26 @@ public: // Sections for DWARF5 split dwarf proposal. const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; } + const TypeSectionMap &getTypesDWOSections() override { return TypesDWOSections; } + StringRef getAbbrevDWOSection() override { return AbbrevDWOSection; } const DWARFSection &getLineDWOSection() override { return LineDWOSection; } const DWARFSection &getLocDWOSection() override { return LocDWOSection; } StringRef getStringDWOSection() override { return StringDWOSection; } + StringRef getStringOffsetDWOSection() override { return StringOffsetDWOSection; } + StringRef getRangeDWOSection() override { return RangeDWOSection; } + StringRef getAddrSection() override { return AddrSection; } + StringRef getCUIndexSection() override { return CUIndexSection; } StringRef getGdbIndexSection() override { return GdbIndexSection; } StringRef getTUIndexSection() override { return TUIndexSection; } @@ -342,4 +359,4 @@ public: } // end namespace llvm -#endif // LLVM_LIB_DEBUGINFO_DWARFCONTEXT_H +#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index f732deef548c..9f86fe508389 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugAbbrev.h --------------------------------------*- C++ -*-===// +//===- DWARFDebugAbbrev.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGABBREV_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGABBREV_H +#ifndef LLVM_DEBUGINFO_DWARFDEBUGABBREV_H +#define LLVM_DEBUGINFO_DWARFDEBUGABBREV_H #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> #include <map> #include <vector> @@ -76,6 +78,6 @@ private: void clear(); }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFDEBUGABBREV_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h index 5a602392add8..40eb7e9a8836 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugArangeSet.h -----------------------------------*- C++ -*-===// +//===- DWARFDebugArangeSet.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGARANGESET_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGARANGESET_H +#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H #include "llvm/ADT/iterator_range.h" #include "llvm/Support/DataExtractor.h" +#include <cstdint> #include <vector> namespace llvm { @@ -40,6 +41,7 @@ public: struct Descriptor { uint64_t Address; uint64_t Length; + uint64_t getEndAddress() const { return Address + Length; } }; @@ -53,6 +55,7 @@ private: public: DWARFDebugArangeSet() { clear(); } + void clear(); bool extract(DataExtractor data, uint32_t *offset_ptr); void dump(raw_ostream &OS) const; @@ -67,6 +70,6 @@ public: } }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h index 791f010a8892..c06771d6afb4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugAranges.h -------------------------------------*- C++ -*-===// +//===- DWARFDebugAranges.h --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGARANGES_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGARANGES_H +#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGES_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGES_H #include "llvm/ADT/DenseSet.h" #include "llvm/Support/DataExtractor.h" +#include <cstdint> #include <vector> namespace llvm { @@ -42,6 +43,7 @@ private: else Length = HighPC - LowPC; } + uint64_t HighPC() const { if (Length) return LowPC + Length; @@ -51,6 +53,7 @@ private: bool containsAddress(uint64_t Address) const { return LowPC <= Address && Address < HighPC(); } + bool operator<(const Range &other) const { return LowPC < other.LowPC; } @@ -73,7 +76,6 @@ private: } }; - typedef std::vector<Range> RangeColl; typedef RangeColl::const_iterator RangeCollIterator; @@ -82,6 +84,6 @@ private: DenseSet<uint32_t> ParsedCUOffsets; }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGES_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index cd76c909ddae..e0a779bb8182 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// +//===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,23 +7,24 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGFRAME_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGFRAME_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/raw_ostream.h" #include <memory> #include <vector> namespace llvm { class FrameEntry; +class raw_ostream; /// \brief A parsed .debug_frame or .eh_frame section /// class DWARFDebugFrame { // True if this is parsing an eh_frame section. bool IsEH; + public: DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); @@ -39,7 +40,6 @@ private: std::vector<std::unique_ptr<FrameEntry>> Entries; }; +} // end namespace llvm -} // namespace llvm - -#endif +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h b/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h index f36f470980b1..fc2423a2708b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===// +//===- DWARFDebugInfoEntry.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,43 +7,37 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGINFOENTRY_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGINFOENTRY_H +#ifndef LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H +#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/Dwarf.h" +#include <cstdint> namespace llvm { -class DWARFDebugAranges; -class DWARFCompileUnit; +class DataExtractor; class DWARFUnit; -class DWARFContext; -class DWARFFormValue; -struct DWARFDebugInfoEntryInlinedChain; /// DWARFDebugInfoEntry - A DIE with only the minimum required data. class DWARFDebugInfoEntry { /// Offset within the .debug_info of the start of this entry. - uint32_t Offset; + uint32_t Offset = 0; /// The integer depth of this DIE within the compile unit DIEs where the /// compile/type unit DIE has a depth of zero. - uint32_t Depth; + uint32_t Depth = 0; + + const DWARFAbbreviationDeclaration *AbbrevDecl = nullptr; - const DWARFAbbreviationDeclaration *AbbrevDecl; public: - DWARFDebugInfoEntry() - : Offset(0), Depth(0), AbbrevDecl(nullptr) {} + DWARFDebugInfoEntry() = default; /// Extracts a debug info entry, which is a child of a given unit, /// starting at a given offset. If DIE can't be extracted, returns false and /// doesn't change OffsetPtr. bool extractFast(const DWARFUnit &U, uint32_t *OffsetPtr); + /// High performance extraction should use this call. bool extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, const DataExtractor &DebugInfoData, @@ -52,15 +46,18 @@ public: uint32_t getOffset() const { return Offset; } uint32_t getDepth() const { return Depth; } + dwarf::Tag getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : dwarf::DW_TAG_null; } + bool hasChildren() const { return AbbrevDecl && AbbrevDecl->hasChildren(); } + const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const { return AbbrevDecl; } }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index 878f1c76ebf6..e5bb24707b63 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugLine.h ----------------------------------------*- C++ -*-===// +//===- DWARFDebugLine.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGLINE_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGLINE_H +#ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H +#define LLVM_DEBUGINFO_DWARFDEBUGLINE_H #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" +#include <cstdint> #include <map> #include <string> #include <vector> @@ -24,13 +25,14 @@ class raw_ostream; class DWARFDebugLine { public: DWARFDebugLine(const RelocAddrMap* LineInfoRelocMap) : RelocMap(LineInfoRelocMap) {} + struct FileNameEntry { - FileNameEntry() : Name(nullptr), DirIdx(0), ModTime(0), Length(0) {} + FileNameEntry() = default; - const char *Name; - uint64_t DirIdx; - uint64_t ModTime; - uint64_t Length; + const char *Name = nullptr; + uint64_t DirIdx = 0; + uint64_t ModTime = 0; + uint64_t Length = 0; }; struct Prologue { @@ -64,9 +66,11 @@ public: std::vector<FileNameEntry> FileNames; bool IsDWARF64; + uint32_t sizeofTotalLength() const { return IsDWARF64 ? 12 : 4; } + uint32_t sizeofPrologueLength() const { return IsDWARF64 ? 8 : 4; } @@ -76,10 +80,12 @@ public: return PrologueLength + sizeofTotalLength() + sizeof(Version) + sizeofPrologueLength(); } + // Length of the line table data in bytes (not including the prologue). uint32_t getStatementTableLength() const { return TotalLength + sizeofTotalLength() - getLength(); } + int32_t getMaxLineIncrementForSpecialOpcode() const { return LineBase + (int8_t)LineRange - 1; } @@ -146,6 +152,8 @@ public: // compilation unit may consist of multiple sequences, which are not // guaranteed to be in the order of ascending instruction address. struct Sequence { + Sequence(); + // Sequence describes instructions at address range [LowPC, HighPC) // and is described by line table rows [FirstRowIndex, LastRowIndex). uint64_t LowPC; @@ -154,15 +162,16 @@ public: unsigned LastRowIndex; bool Empty; - Sequence(); void reset(); static bool orderByLowPC(const Sequence& LHS, const Sequence& RHS) { return LHS.LowPC < RHS.LowPC; } + bool isValid() const { return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex); } + bool containsPC(uint64_t pc) const { return (LowPC <= pc && pc < HighPC); } @@ -177,6 +186,7 @@ public: void appendRow(const DWARFDebugLine::Row &R) { Rows.push_back(R); } + void appendSequence(const DWARFDebugLine::Sequence &S) { Sequences.push_back(S); } @@ -249,6 +259,7 @@ private: const RelocAddrMap *RelocMap; LineTableMapTy LineTableMap; }; -} -#endif +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGLINE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index bd44c2e5aab9..6d4cd8d1b5a3 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugLoc.h -----------------------------------------*- C++ -*-===// +//===- DWARFDebugLoc.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGLOC_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGLOC_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" +#include <cstdint> namespace llvm { @@ -49,8 +50,10 @@ class DWARFDebugLoc { public: DWARFDebugLoc(const RelocAddrMap &LocRelocMap) : RelocMap(LocRelocMap) {} + /// Print the location lists found within the debug_loc section. void dump(raw_ostream &OS) const; + /// Parse the debug_loc section accessible via the 'data' parameter using the /// specified address size to interpret the address ranges. void parse(DataExtractor data, unsigned AddressSize); @@ -76,6 +79,7 @@ public: void parse(DataExtractor data); void dump(raw_ostream &OS) const; }; -} -#endif +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index 5a0352dacdb9..85d98b45afcd 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugMacro.h ---------------------------------------*- C++ -*-===// +//===- DWARFDebugMacro.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -50,6 +50,7 @@ public: /// Print the macro list found within the debug_macinfo section. void dump(raw_ostream &OS) const; + /// Parse the debug_macinfo section accessible via the 'data' parameter. void parse(DataExtractor data); }; diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h index 2b23837e32d6..9d36bb7ad211 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugPubTable.h ------------------------------------*- C++ -*-===// +//===- DWARFDebugPubTable.h -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGPUBTABLE_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGPUBTABLE_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/DataExtractor.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Dwarf.h" +#include <cstdint> #include <vector> namespace llvm { @@ -28,7 +28,7 @@ public: uint32_t SecOffset; /// An entry of the various gnu_pub* debug sections. - llvm::dwarf::PubIndexEntryDescriptor Descriptor; + dwarf::PubIndexEntryDescriptor Descriptor; /// The name of the object as given by the DW_AT_name attribute of the /// referenced DIE. @@ -68,10 +68,12 @@ private: public: DWARFDebugPubTable(StringRef Data, bool LittleEndian, bool GnuStyle); + void dump(StringRef Name, raw_ostream &OS) const; ArrayRef<Set> getData() { return Sets; } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h index c930bd603d4d..018a049a3ed8 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -1,4 +1,4 @@ -//===-- DWARFDebugRangeList.h -----------------------------------*- C++ -*-===// +//===- DWARFDebugRangeList.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDEBUGRANGELIST_H -#define LLVM_LIB_DEBUGINFO_DWARFDEBUGRANGELIST_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H #include "llvm/Support/DataExtractor.h" +#include <cassert> +#include <cstdint> +#include <utility> #include <vector> namespace llvm { @@ -34,12 +37,14 @@ public: // address past the end of the address range. The ending address must // be greater than or equal to the beginning address. uint64_t EndAddress; + // The end of any given range list is marked by an end of list entry, // which consists of a 0 for the beginning address offset // and a 0 for the ending address offset. bool isEndOfListEntry() const { return (StartAddress == 0) && (EndAddress == 0); } + // A base address selection entry consists of: // 1. The value of the largest representable address offset // (for example, 0xffffffff when the size of an address is 32 bits). @@ -63,6 +68,7 @@ private: public: DWARFDebugRangeList() { clear(); } + void clear(); void dump(raw_ostream &OS) const; bool extract(DataExtractor data, uint32_t *offset_ptr); @@ -74,6 +80,6 @@ public: DWARFAddressRangesVector getAbsoluteRanges(uint64_t BaseAddress) const; }; -} // namespace llvm +} // end namespace llvm -#endif // LLVM_DEBUGINFO_DWARFDEBUGRANGELIST_H +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDie.h b/include/llvm/DebugInfo/DWARF/DWARFDie.h index e335e28b39d7..33e24fe3adc9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -1,4 +1,4 @@ -//===-- DWARFDie.h --------------------------------------------------------===// +//===- DWARFDie.h -----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,18 +7,25 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFDIE_H -#define LLVM_LIB_DEBUGINFO_DWARFDIE_H +#ifndef LLVM_DEBUGINFO_DWARFDIE_H +#define LLVM_DEBUGINFO_DWARFDIE_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/Support/Dwarf.h" +#include <cassert> +#include <cstdint> +#include <iterator> namespace llvm { class DWARFUnit; -class DWARFDebugInfoEntry; class raw_ostream; //===----------------------------------------------------------------------===// @@ -34,10 +41,11 @@ class raw_ostream; /// also simplifies the attribute extraction calls by not having to specify the /// DWARFUnit for each call. class DWARFDie { - DWARFUnit *U; - const DWARFDebugInfoEntry *Die; + DWARFUnit *U = nullptr; + const DWARFDebugInfoEntry *Die = nullptr; + public: - DWARFDie() : U(nullptr), Die(nullptr) {} + DWARFDie() = default; DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry * D) : U(Unit), Die(D) {} bool isValid() const { return U && Die; } @@ -45,7 +53,6 @@ public: const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; } DWARFUnit *getDwarfUnit() const { return U; } - /// Get the abbreviation declaration for this DIE. /// /// \returns the abbreviation declaration or NULL for null tags. @@ -78,6 +85,7 @@ public: bool isNULL() const { return getAbbreviationDeclarationPtr() == nullptr; } + /// Returns true if DIE represents a subprogram (not inlined). bool isSubprogramDIE() const; @@ -123,76 +131,33 @@ public: /// \param Attr the attribute to extract. /// \returns an optional DWARFFormValue that will have the form value if the /// attribute was successfully extracted. - Optional<DWARFFormValue> getAttributeValue(dwarf::Attribute Attr) const; - - /// Extract the specified attribute from this DIE as a C string. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \param FailValue the value to return if this DIE doesn't have this - /// attribute. - /// \returns the NULL terminated C string value owned by the DWARF section - /// that contains the string or FailValue if the attribute doesn't exist or - /// if the attribute's form isn't a form that describes an string. - const char *getAttributeValueAsString(dwarf::Attribute Attr, - const char *FailValue) const; + Optional<DWARFFormValue> find(dwarf::Attribute Attr) const; - /// Extract the specified attribute from this DIE as an address. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \returns an optional value for the attribute. - Optional<uint64_t> getAttributeValueAsAddress(dwarf::Attribute Attr) const; - - /// Extract the specified attribute from this DIE as a signed integer. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \returns an optional value for the attribute. - Optional<int64_t> - getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const; - - /// Extract the specified attribute from this DIE as an unsigned integer. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \returns an optional value for the attribute. - Optional<uint64_t> - getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const; + /// Extract the first value of any attribute in Attrs from this DIE. + /// + /// Extract the first attribute that matches from this DIE only. This call + /// doesn't look for the attribute value in any DW_AT_specification or + /// DW_AT_abstract_origin referenced DIEs. The attributes will be searched + /// linearly in the order they are specified within Attrs. + /// + /// \param Attrs an array of DWARF attribute to look for. + /// \returns an optional that has a valid DWARFFormValue for the first + /// matching attribute in Attrs, or None if none of the attributes in Attrs + /// exist in this DIE. + Optional<DWARFFormValue> find(ArrayRef<dwarf::Attribute> Attrs) const; + + /// Extract the first value of any attribute in Attrs from this DIE and + /// recurse into any DW_AT_specification or DW_AT_abstract_origin referenced + /// DIEs. + /// + /// \param Attrs an array of DWARF attribute to look for. + /// \returns an optional that has a valid DWARFFormValue for the first + /// matching attribute in Attrs, or None if none of the attributes in Attrs + /// exist in this DIE or in any DW_AT_specification or DW_AT_abstract_origin + /// DIEs. + Optional<DWARFFormValue> + findRecursively(ArrayRef<dwarf::Attribute> Attrs) const; - /// Extract the specified attribute from this DIE as absolute DIE Offset. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \returns an optional value for the attribute. - Optional<uint64_t> getAttributeValueAsReference(dwarf::Attribute Attr) const; - - /// Extract the specified attribute from this DIE as absolute section offset. - /// - /// Extract an attribute value from this DIE only. This call doesn't look - /// for the attribute value in any DW_AT_specification or - /// DW_AT_abstract_origin referenced DIEs. - /// - /// \param Attr the attribute to extract. - /// \returns an optional value for the attribute. - Optional<uint64_t> - getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const; - /// Extract the specified attribute from this DIE as the referenced DIE. /// /// Regardless of the reference type, return the correct DWARFDie instance if @@ -266,6 +231,12 @@ public: /// references if necessary. Returns null if no name is found. const char *getName(DINameKind Kind) const; + /// Returns the declaration line (start line) for a DIE, assuming it specifies + /// a subprogram. This may be fetched from specification or abstract origin + /// for this subprogram by resolving DW_AT_sepcification or + /// DW_AT_abstract_origin references if necessary. + uint64_t getDeclLine() const; + /// Retrieves values of DW_AT_call_file, DW_AT_call_line and DW_AT_call_column /// from DIE (or zeroes if they are missing). This function looks for /// DW_AT_call attributes in this DIE only, it will not resolve the attribute @@ -286,14 +257,47 @@ public: getInlinedChainForAddress(const uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) const; + class attribute_iterator; + + /// Get an iterator range to all attributes in the current DIE only. + /// + /// \returns an iterator range for the attributes of the current DIE. + iterator_range<attribute_iterator> attributes() const; + class iterator; iterator begin() const; iterator end() const; iterator_range<iterator> children() const; }; - +class DWARFDie::attribute_iterator : + public iterator_facade_base<attribute_iterator, std::forward_iterator_tag, + const DWARFAttribute> { + /// The DWARF DIE we are extracting attributes from. + DWARFDie Die; + /// The value vended to clients via the operator*() or operator->(). + DWARFAttribute AttrValue; + /// The attribute index within the abbreviation declaration in Die. + uint32_t Index; + + /// Update the attribute index and attempt to read the attribute value. If the + /// attribute is able to be read, update AttrValue and the Index member + /// variable. If the attribute value is not able to be read, an appropriate + /// error will be set if the Err member variable is non-NULL and the iterator + /// will be set to the end value so iteration stops. + void updateForIndex(const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I); + +public: + attribute_iterator() = delete; + explicit attribute_iterator(DWARFDie D, bool End); + + attribute_iterator &operator++(); + explicit operator bool() const { return AttrValue.isValid(); } + const DWARFAttribute &operator*() const { return AttrValue; } + bool operator==(const attribute_iterator &X) const { return Index == X.Index; } +}; + inline bool operator==(const DWARFDie &LHS, const DWARFDie &RHS) { return LHS.getDebugInfoEntry() == RHS.getDebugInfoEntry() && LHS.getDwarfUnit() == RHS.getDwarfUnit(); @@ -313,16 +317,19 @@ class DWARFDie::iterator : public iterator_facade_base<iterator, } public: iterator() = default; + explicit iterator(DWARFDie D) : Die(D) { // If we start out with only a Null DIE then invalidate. skipNull(); } + iterator &operator++() { Die = Die.getSibling(); // Don't include the NULL die when iterating. skipNull(); return *this; } + explicit operator bool() const { return Die.isValid(); } const DWARFDie &operator*() const { return Die; } bool operator==(const iterator &X) const { return Die == X.Die; } @@ -344,4 +351,4 @@ inline iterator_range<DWARFDie::iterator> DWARFDie::children() const { } // end namespace llvm -#endif // LLVM_LIB_DEBUGINFO_DWARFDIE_H +#endif // LLVM_DEBUGINFO_DWARFDIE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 1b7659dfb04a..c8d7a0c1ac7a 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -1,4 +1,4 @@ -//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===// +//===- DWARFFormValue.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,15 @@ #ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H #define LLVM_DEBUGINFO_DWARFFORMVALUE_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" +#include <cstdint> namespace llvm { -template <typename T> class ArrayRef; class DWARFUnit; class raw_ostream; @@ -37,7 +39,7 @@ public: private: struct ValueType { - ValueType() : data(nullptr) { + ValueType() { uval = 0; } @@ -46,20 +48,27 @@ private: int64_t sval; const char* cstr; }; - const uint8_t* data; + const uint8_t* data = nullptr; }; dwarf::Form Form; // Form for this value. ValueType Value; // Contains all data for the form. - const DWARFUnit *U; // Remember the DWARFUnit at extract time. + const DWARFUnit *U = nullptr; // Remember the DWARFUnit at extract time. public: - DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F), U(nullptr) {} + DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} + dwarf::Form getForm() const { return Form; } void setForm(dwarf::Form F) { Form = F; } void setUValue(uint64_t V) { Value.uval = V; } void setSValue(int64_t V) { Value.sval = V; } void setPValue(const char *V) { Value.cstr = V; } + + void setBlockValue(const ArrayRef<uint8_t> &Data) { + Value.data = Data.data(); + setUValue(Data.size()); + } + bool isFormClass(FormClass FC) const; const DWARFUnit *getUnit() const { return U; } void dump(raw_ostream &OS) const; @@ -72,6 +81,7 @@ public: /// \returns whether the extraction succeeded. bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, const DWARFUnit *U); + bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t*)Value.cstr; } @@ -87,6 +97,7 @@ public: Optional<ArrayRef<uint8_t>> getAsBlock() const; Optional<uint64_t> getAsCStringOffset() const; Optional<uint64_t> getAsReferenceUVal() const; + /// Get the fixed byte size for a given form. /// /// If the form always has a fixed valid byte size that doesn't depend on a @@ -105,6 +116,7 @@ public: /// and was needed to calculate the byte size. static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const DWARFUnit *U = nullptr); + /// Get the fixed byte size for a given form. /// /// If the form has a fixed byte size given a valid DWARF version and address @@ -133,6 +145,7 @@ public: /// \returns true on success, false if the form was not skipped. bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *U) const; + /// Skip a form in \p debug_info_data at offset specified by \p offset_ptr. /// /// Skips the bytes for this form in the debug info and updates the offset. @@ -145,6 +158,7 @@ public: /// \returns true on success, false if the form was not skipped. static bool skipValue(dwarf::Form form, DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *U); + /// Skip a form in \p debug_info_data at offset specified by \p offset_ptr. /// /// Skips the bytes for this form in the debug info and updates the offset. @@ -164,6 +178,154 @@ private: void dumpString(raw_ostream &OS) const; }; -} +namespace dwarf { + + /// Take an optional DWARFFormValue and try to extract a string value from it. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and was a string. + inline Optional<const char*> toString(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsCString(); + return None; + } + + /// Take an optional DWARFFormValue and extract a string value from it. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the string value or Default if the V doesn't have a value or the + /// form value's encoding wasn't a string. + inline const char* + toString(const Optional<DWARFFormValue>& V, const char *Default) { + return toString(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract an unsigned constant. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a unsigned constant form. + inline Optional<uint64_t> toUnsigned(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsUnsignedConstant(); + return None; + } + + /// Take an optional DWARFFormValue and extract a unsigned constant. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the extracted unsigned value or Default if the V doesn't have a + /// value or the form value's encoding wasn't an unsigned constant form. + inline uint64_t + toUnsigned(const Optional<DWARFFormValue>& V, uint64_t Default) { + return toUnsigned(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract an reference. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a reference form. + inline Optional<uint64_t> toReference(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsReference(); + return None; + } + + /// Take an optional DWARFFormValue and extract a reference. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the extracted reference value or Default if the V doesn't have a + /// value or the form value's encoding wasn't a reference form. + inline uint64_t + toReference(const Optional<DWARFFormValue>& V, uint64_t Default) { + return toReference(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract an signed constant. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a signed constant form. + inline Optional<int64_t> toSigned(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsSignedConstant(); + return None; + } + + /// Take an optional DWARFFormValue and extract a signed integer. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the extracted signed integer value or Default if the V doesn't + /// have a value or the form value's encoding wasn't a signed integer form. + inline int64_t + toSigned(const Optional<DWARFFormValue>& V, int64_t Default) { + return toSigned(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract an address. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a address form. + inline Optional<uint64_t> toAddress(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsAddress(); + return None; + } + + /// Take an optional DWARFFormValue and extract a address. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the extracted address value or Default if the V doesn't have a + /// value or the form value's encoding wasn't an address form. + inline uint64_t + toAddress(const Optional<DWARFFormValue>& V, uint64_t Default) { + return toAddress(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract an section offset. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a section offset form. + inline Optional<uint64_t> toSectionOffset(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsSectionOffset(); + return None; + } + + /// Take an optional DWARFFormValue and extract a section offset. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \param Default the default value to return in case of failure. + /// \returns the extracted section offset value or Default if the V doesn't + /// have a value or the form value's encoding wasn't a section offset form. + inline uint64_t + toSectionOffset(const Optional<DWARFFormValue>& V, uint64_t Default) { + return toSectionOffset(V).getValueOr(Default); + } + + /// Take an optional DWARFFormValue and try to extract block data. + /// + /// \param V and optional DWARFFormValue to attempt to extract the value from. + /// \returns an optional value that contains a value if the form value + /// was valid and has a block form. + inline Optional<ArrayRef<uint8_t>> + toBlock(const Optional<DWARFFormValue>& V) { + if (V) + return V->getAsBlock(); + return None; + } + +} // end namespace dwarf + +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARFFORMVALUE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h b/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h index 66041be96566..7a52218663b9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h +++ b/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h @@ -1,4 +1,4 @@ -//===-- DWARFGdbIndex.h -----------------------------------------*- C++ -*-===// +//===- DWARFGdbIndex.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFGDBINDEX_H -#define LLVM_LIB_DEBUGINFO_DWARFGDBINDEX_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H +#define LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <utility> namespace llvm { + +class raw_ostream; + class DWARFGdbIndex { uint32_t Version; @@ -63,6 +68,7 @@ public: bool HasContent = false; bool HasError = false; }; -} -#endif // LLVM_LIB_DEBUGINFO_DWARFGDBINDEX_H +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h b/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h index d7fe3032e505..af01bddeed15 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h +++ b/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h @@ -1,4 +1,4 @@ -//===-- DWARFRelocMap.h -----------------------------------------*- C++ -*-===// +//===- DWARFRelocMap.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,16 +7,17 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFRELOCMAP_H -#define LLVM_LIB_DEBUGINFO_DWARFRELOCMAP_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H +#define LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H #include "llvm/ADT/DenseMap.h" +#include <cstdint> +#include <utility> namespace llvm { -typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; +typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t>> RelocAddrMap; -} // namespace llvm - -#endif +} // end namespace llvm +#endif // LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFSection.h b/include/llvm/DebugInfo/DWARF/DWARFSection.h index 3e27b529e97b..2b8a53a4c93e 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFSection.h +++ b/include/llvm/DebugInfo/DWARF/DWARFSection.h @@ -1,4 +1,4 @@ -//===-- DWARFSection.h ------------------------------------------*- C++ -*-===// +//===- DWARFSection.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFSECTION_H -#define LLVM_LIB_DEBUGINFO_DWARFSECTION_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFSECTION_H +#define LLVM_DEBUGINFO_DWARF_DWARFSECTION_H -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" namespace llvm { @@ -20,6 +20,6 @@ struct DWARFSection { RelocAddrMap Relocs; }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARF_DWARFSECTION_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index 4f1e1292a1f1..703316005887 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -1,4 +1,4 @@ -//===-- DWARFTypeUnit.h -----------------------------------------*- C++ -*-===// +//===- DWARFTypeUnit.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,27 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFTYPEUNIT_H -#define LLVM_LIB_DEBUGINFO_DWARFTYPEUNIT_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H +#define LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> namespace llvm { +class DWARFContext; +class DWARFDebugAbbrev; +struct DWARFSection; +class raw_ostream; + class DWARFTypeUnit : public DWARFUnit { private: uint64_t TypeHash; uint32_t TypeOffset; + public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, @@ -26,9 +36,11 @@ public: const DWARFUnitIndex::Entry *Entry) : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, UnitSection, Entry) {} + uint32_t getHeaderSize() const override { return DWARFUnit::getHeaderSize() + 12; } + void dump(raw_ostream &OS, bool Brief = false); static const DWARFSectionKind Section = DW_SECT_TYPES; @@ -36,7 +48,6 @@ protected: bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) override; }; -} - -#endif +} // end namespace llvm +#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index db7b59be90c2..40eb4434bd61 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -1,4 +1,4 @@ -//===-- DWARFUnit.h ---------------------------------------------*- C++ -*-===// +//===- DWARFUnit.h ----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,32 +7,37 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFUNIT_H -#define LLVM_LIB_DEBUGINFO_DWARFUNIT_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNIT_H +#define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H -#include "llvm/ADT/Optional.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Dwarf.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> #include <vector> namespace llvm { -namespace object { -class ObjectFile; -} - +class DWARFAbbreviationDeclarationSet; class DWARFContext; class DWARFDebugAbbrev; class DWARFUnit; -class StringRef; -class raw_ostream; /// Base class for all DWARFUnitSection classes. This provides the /// functionality common to all unit types. @@ -47,12 +52,12 @@ public: DWARFUnitIndex *Index = nullptr); protected: + ~DWARFUnitSectionBase() = default; + virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, bool isLittleEndian, bool isDWO) = 0; - - ~DWARFUnitSectionBase() = default; }; const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, @@ -65,7 +70,7 @@ class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>, bool Parsed = false; public: - typedef llvm::SmallVectorImpl<std::unique_ptr<UnitType>> UnitVector; + typedef SmallVectorImpl<std::unique_ptr<UnitType>> UnitVector; typedef typename UnitVector::iterator iterator; typedef llvm::iterator_range<typename UnitVector::iterator> iterator_range; @@ -122,8 +127,9 @@ class DWARFUnit { uint32_t Offset; uint32_t Length; - uint16_t Version; const DWARFAbbreviationDeclarationSet *Abbrevs; + uint16_t Version; + uint8_t UnitType; uint8_t AddrSize; uint64_t BaseAddr; // The compile unit debug information entry items. @@ -134,9 +140,11 @@ class DWARFUnit { class DWOHolder { object::OwningBinary<object::ObjectFile> DWOFile; std::unique_ptr<DWARFContext> DWOContext; - DWARFUnit *DWOU; + DWARFUnit *DWOU = nullptr; + public: DWOHolder(StringRef DWOPath); + DWARFUnit *getUnit() const { return DWOU; } }; std::unique_ptr<DWOHolder> DWO; @@ -151,8 +159,9 @@ class DWARFUnit { protected: virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); + /// Size in bytes of the unit header. - virtual uint32_t getHeaderSize() const { return 11; } + virtual uint32_t getHeaderSize() const { return Version <= 4 ? 11 : 12; } public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, @@ -168,10 +177,12 @@ public: StringRef getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } StringRef getStringOffsetSection() const { return StringOffsetSection; } + void setAddrOffsetSection(StringRef AOS, uint32_t Base) { AddrOffsetSection = AOS; AddrOffsetSectionBase = Base; } + void setRangesSection(StringRef RS, uint32_t Base) { RangeSection = RS; RangeSectionBase = Base; @@ -184,6 +195,7 @@ public: DataExtractor getDebugInfoExtractor() const { return DataExtractor(InfoSection.Data, isLittleEndian, AddrSize); } + DataExtractor getStringExtractor() const { return DataExtractor(StringSection, false, 0); } @@ -202,23 +214,30 @@ public: uint32_t getNextUnitOffset() const { return Offset + Length + 4; } uint32_t getLength() const { return Length; } uint16_t getVersion() const { return Version; } + dwarf::DwarfFormat getFormat() const { return dwarf::DwarfFormat::DWARF32; // FIXME: Support DWARF64. } + const DWARFAbbreviationDeclarationSet *getAbbreviations() const { return Abbrevs; } + + uint8_t getUnitType() const { return UnitType; } uint8_t getAddressByteSize() const { return AddrSize; } + uint8_t getRefAddrByteSize() const { if (Version == 2) return AddrSize; return getDwarfOffsetByteSize(); } + uint8_t getDwarfOffsetByteSize() const { if (getFormat() == dwarf::DwarfFormat::DWARF64) return 8; return 4; } + uint64_t getBaseAddress() const { return BaseAddr; } void setBaseAddress(uint64_t base_addr) { @@ -308,9 +327,11 @@ private: /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it /// hasn't already been done. Returns the number of DIEs parsed at this call. size_t extractDIEsIfNeeded(bool CUDieOnly); + /// extractDIEsToVector - Appends all parsed DIEs to a vector. void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, std::vector<DWARFDebugInfoEntry> &DIEs) const; + /// clearDIEs - Clear parsed DIEs to keep memory usage low. void clearDIEs(bool KeepCUDie); @@ -324,6 +345,6 @@ private: DWARFDie getSubprogramForAddress(uint64_t Address); }; -} +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_DWARF_DWARFUNIT_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h index 9f051cd7081c..8e2ce023695b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -1,4 +1,4 @@ -//===-- DWARFUnitIndex.h --------------------------------------------------===// +//===- DWARFUnitIndex.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H -#define LLVM_LIB_DEBUGINFO_DWARFUNITINDEX_H +#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H +#define LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #include <cstdint> +#include <memory> namespace llvm { +class raw_ostream; + enum DWARFSectionKind { DW_SECT_INFO = 1, DW_SECT_TYPES, @@ -57,9 +59,11 @@ 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; } }; @@ -72,21 +76,26 @@ private: std::unique_ptr<Entry[]> Rows; static StringRef getColumnHeader(DWARFSectionKind DS); + bool parseImpl(DataExtractor IndexData); public: - bool parse(DataExtractor IndexData); DWARFUnitIndex(DWARFSectionKind InfoColumnKind) : InfoColumnKind(InfoColumnKind) {} + + bool parse(DataExtractor IndexData); 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); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H diff --git a/include/llvm/DebugInfo/MSF/ByteStream.h b/include/llvm/DebugInfo/MSF/ByteStream.h deleted file mode 100644 index 547844be5e5d..000000000000 --- a/include/llvm/DebugInfo/MSF/ByteStream.h +++ /dev/null @@ -1,169 +0,0 @@ -//===- 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_MSF_BYTESTREAM_H -#define LLVM_DEBUGINFO_MSF_BYTESTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MemoryBuffer.h" -#include <algorithm> -#include <cstdint> -#include <cstring> -#include <memory> - -namespace llvm { -namespace msf { - -class ByteStream : public ReadableStream { -public: - ByteStream() = default; - explicit ByteStream(ArrayRef<uint8_t> Data) : Data(Data) {} - explicit ByteStream(StringRef Data) - : Data(Data.bytes_begin(), Data.bytes_end()) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override { - if (Offset > Data.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - if (Data.size() < Size + Offset) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - Buffer = Data.slice(Offset, Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override { - if (Offset >= Data.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - Buffer = Data.slice(Offset); - return Error::success(); - } - - uint32_t getLength() const override { return Data.size(); } - - ArrayRef<uint8_t> data() const { return Data; } - - StringRef str() const { - const char *CharData = reinterpret_cast<const char *>(Data.data()); - return StringRef(CharData, Data.size()); - } - -protected: - ArrayRef<uint8_t> Data; -}; - -// MemoryBufferByteStream behaves like a read-only ByteStream, but has its data -// backed by an llvm::MemoryBuffer. It also owns the underlying MemoryBuffer. -class MemoryBufferByteStream : public ByteStream { -public: - explicit MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer) - : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(), - Buffer->getBuffer().bytes_end())), - MemBuffer(std::move(Buffer)) {} - - std::unique_ptr<MemoryBuffer> MemBuffer; -}; - -class MutableByteStream : public WritableStream { -public: - MutableByteStream() = default; - explicit MutableByteStream(MutableArrayRef<uint8_t> Data) - : Data(Data), ImmutableStream(Data) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override { - return ImmutableStream.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override { - return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() const override { return ImmutableStream.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override { - if (Buffer.empty()) - return Error::success(); - - if (Data.size() < Buffer.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - if (Offset > Buffer.size() - Data.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - - uint8_t *DataPtr = const_cast<uint8_t *>(Data.data()); - ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); - return Error::success(); - } - - Error commit() const override { return Error::success(); } - - MutableArrayRef<uint8_t> data() const { return Data; } - -private: - MutableArrayRef<uint8_t> Data; - ByteStream ImmutableStream; -}; - -// A simple adapter that acts like a ByteStream but holds ownership over -// and underlying FileOutputBuffer. -class FileBufferByteStream : public WritableStream { -private: - class StreamImpl : public MutableByteStream { - public: - StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer) - : MutableByteStream(MutableArrayRef<uint8_t>(Buffer->getBufferStart(), - Buffer->getBufferEnd())), - FileBuffer(std::move(Buffer)) {} - - Error commit() const override { - if (FileBuffer->commit()) - return llvm::make_error<MSFError>(msf_error_code::not_writable); - return Error::success(); - } - - private: - std::unique_ptr<FileOutputBuffer> FileBuffer; - }; - -public: - explicit FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer) - : Impl(std::move(Buffer)) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override { - return Impl.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override { - return Impl.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() const override { return Impl.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const override { - return Impl.writeBytes(Offset, Data); - } - - Error commit() const override { return Impl.commit(); } - -private: - StreamImpl Impl; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BYTESTREAM_H diff --git a/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/include/llvm/DebugInfo/MSF/MappedBlockStream.h index fff4e9cecef5..c91f6f725c80 100644 --- a/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ b/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -15,8 +15,10 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> @@ -37,29 +39,33 @@ struct MSFLayout; /// the MSF. MappedBlockStream provides methods for reading from and writing /// to one of these streams transparently, as if it were a contiguous sequence /// of bytes. -class MappedBlockStream : public ReadableStream { +class MappedBlockStream : public BinaryStream { friend class WritableMappedBlockStream; public: static std::unique_ptr<MappedBlockStream> createStream(uint32_t BlockSize, uint32_t NumBlocks, - const MSFStreamLayout &Layout, const ReadableStream &MsfData); + const MSFStreamLayout &Layout, BinaryStreamRef MsfData); static std::unique_ptr<MappedBlockStream> - createIndexedStream(const MSFLayout &Layout, const ReadableStream &MsfData, + createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex); static std::unique_ptr<MappedBlockStream> - createFpmStream(const MSFLayout &Layout, const ReadableStream &MsfData); + createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData); static std::unique_ptr<MappedBlockStream> - createDirectoryStream(const MSFLayout &Layout, const ReadableStream &MsfData); + createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData); + + llvm::support::endianness getEndian() const override { + return llvm::support::little; + } Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override; + ArrayRef<uint8_t> &Buffer) override; Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override; + ArrayRef<uint8_t> &Buffer) override; - uint32_t getLength() const override; + uint32_t getLength() override; uint32_t getNumBytesCopied() const; @@ -74,51 +80,56 @@ public: protected: MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &StreamLayout, - const ReadableStream &MsfData); + BinaryStreamRef MsfData); private: const MSFStreamLayout &getStreamLayout() const { return StreamLayout; } void fixCacheAfterWrite(uint32_t Offset, ArrayRef<uint8_t> Data) const; - Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const; + Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer); bool tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const; + ArrayRef<uint8_t> &Buffer); const uint32_t BlockSize; const uint32_t NumBlocks; const MSFStreamLayout StreamLayout; - const ReadableStream &MsfData; + BinaryStreamRef MsfData; typedef MutableArrayRef<uint8_t> CacheEntry; - mutable llvm::BumpPtrAllocator Pool; - mutable DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap; + llvm::BumpPtrAllocator Pool; + DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap; }; -class WritableMappedBlockStream : public WritableStream { +class WritableMappedBlockStream : public WritableBinaryStream { public: static std::unique_ptr<WritableMappedBlockStream> createStream(uint32_t BlockSize, uint32_t NumBlocks, - const MSFStreamLayout &Layout, const WritableStream &MsfData); + const MSFStreamLayout &Layout, WritableBinaryStreamRef MsfData); static std::unique_ptr<WritableMappedBlockStream> - createIndexedStream(const MSFLayout &Layout, const WritableStream &MsfData, + createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, uint32_t StreamIndex); static std::unique_ptr<WritableMappedBlockStream> - createDirectoryStream(const MSFLayout &Layout, const WritableStream &MsfData); + createDirectoryStream(const MSFLayout &Layout, + WritableBinaryStreamRef MsfData); static std::unique_ptr<WritableMappedBlockStream> - createFpmStream(const MSFLayout &Layout, const WritableStream &MsfData); + createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData); + + llvm::support::endianness getEndian() const override { + return llvm::support::little; + } Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override; + ArrayRef<uint8_t> &Buffer) override; Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override; - uint32_t getLength() const override; + ArrayRef<uint8_t> &Buffer) override; + uint32_t getLength() override; - Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override; + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override; - Error commit() const override; + Error commit() override; const MSFStreamLayout &getStreamLayout() const { return ReadInterface.getStreamLayout(); @@ -130,12 +141,12 @@ public: protected: WritableMappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &StreamLayout, - const WritableStream &MsfData); + WritableBinaryStreamRef MsfData); private: MappedBlockStream ReadInterface; - const WritableStream &WriteInterface; + WritableBinaryStreamRef WriteInterface; }; } // end namespace pdb diff --git a/include/llvm/DebugInfo/MSF/StreamInterface.h b/include/llvm/DebugInfo/MSF/StreamInterface.h deleted file mode 100644 index 09782d8e3b30..000000000000 --- a/include/llvm/DebugInfo/MSF/StreamInterface.h +++ /dev/null @@ -1,53 +0,0 @@ -//===- 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_MSF_STREAMINTERFACE_H -#define LLVM_DEBUGINFO_MSF_STREAMINTERFACE_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Error.h" -#include <cstdint> - -namespace llvm { -namespace msf { - -class ReadableStream { -public: - virtual ~ReadableStream() = default; - - // 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; - - virtual uint32_t getLength() const = 0; -}; - -class WritableStream : public ReadableStream { -public: - ~WritableStream() override = default; - - // 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 Error commit() const = 0; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMINTERFACE_H diff --git a/include/llvm/DebugInfo/MSF/StreamReader.h b/include/llvm/DebugInfo/MSF/StreamReader.h deleted file mode 100644 index fc2ca78dc18f..000000000000 --- a/include/llvm/DebugInfo/MSF/StreamReader.h +++ /dev/null @@ -1,121 +0,0 @@ -//===- 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_MSF_STREAMREADER_H -#define LLVM_DEBUGINFO_MSF_STREAMREADER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" - -#include <string> - -namespace llvm { -namespace msf { - -class StreamReader { -public: - StreamReader(ReadableStreamRef Stream); - - Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer); - Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size); - Error readInteger(uint8_t &Dest); - Error readInteger(uint16_t &Dest); - Error readInteger(uint32_t &Dest); - Error readInteger(uint64_t &Dest); - Error readInteger(int8_t &Dest); - Error readInteger(int16_t &Dest); - Error readInteger(int32_t &Dest); - Error readInteger(int64_t &Dest); - Error readZeroString(StringRef &Dest); - Error readFixedString(StringRef &Dest, uint32_t Length); - Error readStreamRef(ReadableStreamRef &Ref); - Error readStreamRef(ReadableStreamRef &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<MSFError>(msf_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) { - ReadableStreamRef 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<MSFError>(msf_error_code::invalid_format); - if (Offset + Length > Stream.getLength()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - ReadableStreamRef View = Stream.slice(Offset, Length); - Array = FixedStreamArray<T>(View); - Offset += Length; - return Error::success(); - } - - bool empty() const { return bytesRemaining() == 0; } - 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(); } - - Error skip(uint32_t Amount); - - uint8_t peek() const; - -private: - ReadableStreamRef Stream; - uint32_t Offset; -}; -} // namespace msf -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMREADER_H diff --git a/include/llvm/DebugInfo/MSF/StreamRef.h b/include/llvm/DebugInfo/MSF/StreamRef.h deleted file mode 100644 index eee71e53a39b..000000000000 --- a/include/llvm/DebugInfo/MSF/StreamRef.h +++ /dev/null @@ -1,135 +0,0 @@ -//===- 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_MSF_STREAMREF_H -#define LLVM_DEBUGINFO_MSF_STREAMREF_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> - -namespace llvm { -namespace msf { - -template <class StreamType, class RefType> class StreamRefBase { -public: - StreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} - StreamRefBase(const StreamType &Stream, uint32_t Offset, uint32_t Length) - : Stream(&Stream), ViewOffset(Offset), Length(Length) {} - - uint32_t getLength() const { return Length; } - const StreamType *getStream() const { return Stream; } - - RefType drop_front(uint32_t N) const { - if (!Stream) - return RefType(); - - N = std::min(N, Length); - return RefType(*Stream, ViewOffset + N, Length - N); - } - - RefType keep_front(uint32_t N) const { - if (!Stream) - return RefType(); - N = std::min(N, Length); - return RefType(*Stream, ViewOffset, N); - } - - RefType slice(uint32_t Offset, uint32_t Len) const { - return drop_front(Offset).keep_front(Len); - } - - bool operator==(const RefType &Other) const { - if (Stream != Other.Stream) - return false; - if (ViewOffset != Other.ViewOffset) - return false; - if (Length != Other.Length) - return false; - return true; - } - -protected: - const StreamType *Stream; - uint32_t ViewOffset; - uint32_t Length; -}; - -class ReadableStreamRef - : public StreamRefBase<ReadableStream, ReadableStreamRef> { -public: - ReadableStreamRef() = default; - ReadableStreamRef(const ReadableStream &Stream) - : StreamRefBase(Stream, 0, Stream.getLength()) {} - ReadableStreamRef(const ReadableStream &Stream, uint32_t Offset, - uint32_t Length) - : StreamRefBase(Stream, Offset, Length) {} - - // Use StreamRef.slice() instead. - ReadableStreamRef(const ReadableStreamRef &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<MSFError>(msf_error_code::insufficient_buffer); - if (Size + Offset > Length) - return make_error<MSFError>(msf_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<MSFError>(msf_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(); - } -}; - -class WritableStreamRef - : public StreamRefBase<WritableStream, WritableStreamRef> { -public: - WritableStreamRef() = default; - WritableStreamRef(const WritableStream &Stream) - : StreamRefBase(Stream, 0, Stream.getLength()) {} - WritableStreamRef(const WritableStream &Stream, uint32_t Offset, - uint32_t Length) - : StreamRefBase(Stream, Offset, Length) {} - - // Use StreamRef.slice() instead. - WritableStreamRef(const WritableStreamRef &S, uint32_t Offset, - uint32_t Length) = delete; - - Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { - if (Data.size() + Offset > Length) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - return Stream->writeBytes(ViewOffset + Offset, Data); - } - - Error commit() const { return Stream->commit(); } -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMREF_H diff --git a/include/llvm/DebugInfo/MSF/StreamWriter.h b/include/llvm/DebugInfo/MSF/StreamWriter.h deleted file mode 100644 index 2bb14434dd83..000000000000 --- a/include/llvm/DebugInfo/MSF/StreamWriter.h +++ /dev/null @@ -1,92 +0,0 @@ -//===- 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_MSF_STREAMWRITER_H -#define LLVM_DEBUGINFO_MSF_STREAMWRITER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Error.h" -#include <cstdint> -#include <type_traits> - -namespace llvm { -namespace msf { - -class StreamWriter { -public: - StreamWriter() = default; - explicit StreamWriter(WritableStreamRef Stream); - - Error writeBytes(ArrayRef<uint8_t> Buffer); - Error writeInteger(uint8_t Int); - Error writeInteger(uint16_t Dest); - Error writeInteger(uint32_t Dest); - Error writeInteger(uint64_t Dest); - Error writeInteger(int8_t Int); - Error writeInteger(int16_t Dest); - Error writeInteger(int32_t Dest); - Error writeInteger(int64_t Dest); - Error writeZeroString(StringRef Str); - Error writeFixedString(StringRef Str); - Error writeStreamRef(ReadableStreamRef Ref); - Error writeStreamRef(ReadableStreamRef 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.empty()) - return Error::success(); - - if (Array.size() > UINT32_MAX / sizeof(T)) - return make_error<MSFError>(msf_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: - WritableStreamRef Stream; - uint32_t Offset = 0; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMWRITER_H diff --git a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h index 9bf073831565..9713dce362d2 100644 --- a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h +++ b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h @@ -34,12 +34,11 @@ public: std::unique_ptr<ChildType> getChildAtIndex(uint32_t Index) const override { std::unique_ptr<PDBSymbol> Child = Enumerator->getChildAtIndex(Index); - return make_concrete_child(std::move(Child)); + return unique_dyn_cast_or_null<ChildType>(Child); } std::unique_ptr<ChildType> getNext() override { - std::unique_ptr<PDBSymbol> Child = Enumerator->getNext(); - return make_concrete_child(std::move(Child)); + return unique_dyn_cast_or_null<ChildType>(Enumerator->getNext()); } void reset() override { Enumerator->reset(); } @@ -50,11 +49,6 @@ public: } private: - std::unique_ptr<ChildType> - make_concrete_child(std::unique_ptr<PDBSymbol> Child) const { - ChildType *ConcreteChild = dyn_cast_or_null<ChildType>(Child.release()); - return std::unique_ptr<ChildType>(ConcreteChild); - } std::unique_ptr<IPDBEnumSymbols> Enumerator; }; diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 1e40c46f8a27..c0633cbdfa52 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -102,6 +102,7 @@ public: uint32_t getVirtualBaseDispIndex() const override; uint32_t getVirtualBaseOffset() const override; uint32_t getVirtualTableShapeId() const override; + std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override; PDB_DataKind getDataKind() const override; PDB_SymType getSymTag() const override; PDB_UniqueId getGuid() const override; diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 49866b8bb2f2..4c28e194bc70 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -21,6 +21,9 @@ class raw_ostream; namespace pdb { +class PDBSymbolTypeVTable; +class PDBSymbolTypeVTableShape; + /// 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 @@ -110,6 +113,8 @@ public: virtual Variant getValue() const = 0; virtual uint32_t getVirtualBaseDispIndex() const = 0; virtual uint32_t getVirtualBaseOffset() const = 0; + virtual std::unique_ptr<PDBSymbolTypeVTable> + getVirtualBaseTableType() const = 0; virtual uint32_t getVirtualTableShapeId() const = 0; virtual PDB_DataKind getDataKind() const = 0; virtual PDB_SymType getSymTag() const = 0; diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index 15e97ac198e5..85d9fe124859 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_IPDBSESSION_H #define LLVM_DEBUGINFO_PDB_IPDBSESSION_H +#include "PDBSymbol.h" #include "PDBTypes.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -33,15 +34,7 @@ public: template <typename T> std::unique_ptr<T> getConcreteSymbolById(uint32_t SymbolId) const { - auto Symbol(getSymbolById(SymbolId)); - if (!Symbol) - return nullptr; - - T *ConcreteSymbol = dyn_cast<T>(Symbol.get()); - if (!ConcreteSymbol) - return nullptr; - (void)Symbol.release(); - return std::unique_ptr<T>(ConcreteSymbol); + return unique_dyn_cast_or_null<T>(getSymbolById(SymbolId)); } virtual std::unique_ptr<PDBSymbol> diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/include/llvm/DebugInfo/PDB/Native/DbiStream.h index c97ca32ab43d..f49f5aaefaca 100644 --- a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -12,13 +12,15 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/PDBTypes.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/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -70,11 +72,11 @@ public: Expected<StringRef> getFileNameForIndex(uint32_t Index) const; - msf::FixedStreamArray<object::coff_section> getSectionHeaders(); + FixedStreamArray<object::coff_section> getSectionHeaders(); - msf::FixedStreamArray<object::FpoData> getFpoRecords(); + FixedStreamArray<object::FpoData> getFpoRecords(); - msf::FixedStreamArray<SecMapEntry> getSectionMap() const; + FixedStreamArray<SecMapEntry> getSectionMap() const; void visitSectionContributions(ISectionContribVisitor &Visitor) const; private: @@ -89,30 +91,30 @@ private: std::unique_ptr<msf::MappedBlockStream> Stream; std::vector<ModuleInfoEx> ModuleInfos; - NameHashTable ECNames; + StringTable ECNames; - msf::ReadableStreamRef ModInfoSubstream; - msf::ReadableStreamRef SecContrSubstream; - msf::ReadableStreamRef SecMapSubstream; - msf::ReadableStreamRef FileInfoSubstream; - msf::ReadableStreamRef TypeServerMapSubstream; - msf::ReadableStreamRef ECSubstream; + BinaryStreamRef ModInfoSubstream; + BinaryStreamRef SecContrSubstream; + BinaryStreamRef SecMapSubstream; + BinaryStreamRef FileInfoSubstream; + BinaryStreamRef TypeServerMapSubstream; + BinaryStreamRef ECSubstream; - msf::ReadableStreamRef NamesBuffer; + BinaryStreamRef NamesBuffer; - msf::FixedStreamArray<support::ulittle16_t> DbgStreams; + FixedStreamArray<support::ulittle16_t> DbgStreams; PdbRaw_DbiSecContribVer SectionContribVersion; - msf::FixedStreamArray<SectionContrib> SectionContribs; - msf::FixedStreamArray<SectionContrib2> SectionContribs2; - msf::FixedStreamArray<SecMapEntry> SectionMap; - msf::FixedStreamArray<support::little32_t> FileNameOffsets; + FixedStreamArray<SectionContrib> SectionContribs; + FixedStreamArray<SectionContrib2> SectionContribs2; + FixedStreamArray<SecMapEntry> SectionMap; + FixedStreamArray<support::little32_t> FileNameOffsets; std::unique_ptr<msf::MappedBlockStream> SectionHeaderStream; - msf::FixedStreamArray<object::coff_section> SectionHeaders; + FixedStreamArray<object::coff_section> SectionHeaders; std::unique_ptr<msf::MappedBlockStream> FpoStream; - msf::FixedStreamArray<object::FpoData> FpoRecords; + FixedStreamArray<object::FpoData> FpoRecords; const DbiStreamHeader *Header; }; diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h index 99a3ac7fb1da..16426bd93847 100644 --- a/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -14,11 +14,11 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" namespace llvm { @@ -31,11 +31,13 @@ struct coff_section; namespace pdb { class DbiStream; struct DbiStreamHeader; +class ModInfoBuilder; class PDBFile; class DbiStreamBuilder { public: DbiStreamBuilder(msf::MSFBuilder &Msf); + ~DbiStreamBuilder(); DbiStreamBuilder(const DbiStreamBuilder &) = delete; DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; @@ -55,13 +57,12 @@ public: uint32_t calculateSerializedLength() const; - Error addModuleInfo(StringRef ObjFile, StringRef Module); + Expected<ModInfoBuilder &> addModuleInfo(StringRef ModuleName); Error addModuleSourceFile(StringRef Module, StringRef File); Error finalizeMsfLayout(); - Error commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer); + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef MsfBuffer); // A helper function to create Section Contributions from COFF input // section headers. @@ -89,12 +90,6 @@ private: Error generateModiSubstream(); Error generateFileInfoSubstream(); - struct ModuleInfo { - std::vector<StringRef> SourceFiles; - StringRef Obj; - StringRef Mod; - }; - msf::MSFBuilder &Msf; BumpPtrAllocator &Allocator; @@ -108,14 +103,13 @@ private: const DbiStreamHeader *Header; - StringMap<std::unique_ptr<ModuleInfo>> ModuleInfos; - std::vector<ModuleInfo *> ModuleInfoList; + StringMap<std::unique_ptr<ModInfoBuilder>> ModiMap; + std::vector<ModInfoBuilder *> ModiList; StringMap<uint32_t> SourceFileNames; - msf::WritableStreamRef NamesBuffer; - msf::MutableByteStream ModInfoBuffer; - msf::MutableByteStream FileInfoBuffer; + WritableBinaryStreamRef NamesBuffer; + MutableBinaryByteStream FileInfoBuffer; ArrayRef<SectionContrib> SectionContribs; ArrayRef<SecMapEntry> SectionMap; llvm::SmallVector<DebugStream, (int)DbgHeaderType::Max> DbgStreams; diff --git a/include/llvm/DebugInfo/PDB/Raw/EnumTables.h b/include/llvm/DebugInfo/PDB/Native/EnumTables.h index c018445630fe..c018445630fe 100644 --- a/include/llvm/DebugInfo/PDB/Raw/EnumTables.h +++ b/include/llvm/DebugInfo/PDB/Native/EnumTables.h diff --git a/include/llvm/DebugInfo/PDB/Native/Formatters.h b/include/llvm/DebugInfo/PDB/Native/Formatters.h new file mode 100644 index 000000000000..183f0ad8307e --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/Formatters.h @@ -0,0 +1,52 @@ +//===- Formatters.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_NATIVE_FORMATTERS_H +#define LLVM_DEBUGINFO_PDB_NATIVE_FORMATTERS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/FormatProviders.h" + +#define FORMAT_CASE(Value, Name) \ + case Value: \ + Stream << Name; \ + break; + +namespace llvm { +template <> struct format_provider<pdb::PDB_UniqueId> { + static void format(const pdb::PDB_UniqueId &V, llvm::raw_ostream &Stream, + StringRef Style) { + codeview::fmt_guid(V.Guid).format(Stream, Style); + } +}; + +template <> struct format_provider<pdb::PdbRaw_ImplVer> { + static void format(const pdb::PdbRaw_ImplVer &V, llvm::raw_ostream &Stream, + StringRef Style) { + switch (V) { + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC110, "VC110") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC140, "VC140") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC2, "VC2") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC4, "VC4") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC41, "VC41") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC50, "VC50") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC70, "VC70") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC70Dep, "VC70Dep") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC80, "VC80") + FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC98, "VC98") + } + } +}; +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/GlobalsStream.h b/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h index 175f093cf53c..dcea3d3be0ab 100644 --- a/include/llvm/DebugInfo/PDB/Raw/GlobalsStream.h +++ b/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h @@ -11,10 +11,10 @@ #define LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Error.h" namespace llvm { @@ -27,15 +27,15 @@ public: explicit GlobalsStream(std::unique_ptr<msf::MappedBlockStream> Stream); ~GlobalsStream(); Error commit(); - msf::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { + FixedStreamArray<support::ulittle32_t> getHashBuckets() const { return HashBuckets; } uint32_t getNumBuckets() const { return NumBuckets; } Error reload(); private: - msf::FixedStreamArray<support::ulittle32_t> HashBuckets; - msf::FixedStreamArray<PSHashRecord> HashRecords; + FixedStreamArray<support::ulittle32_t> HashBuckets; + FixedStreamArray<PSHashRecord> HashRecords; uint32_t NumBuckets; std::unique_ptr<msf::MappedBlockStream> Stream; }; diff --git a/include/llvm/DebugInfo/PDB/Raw/Hash.h b/include/llvm/DebugInfo/PDB/Native/Hash.h index 0340554d7b0b..0340554d7b0b 100644 --- a/include/llvm/DebugInfo/PDB/Raw/Hash.h +++ b/include/llvm/DebugInfo/PDB/Native/Hash.h diff --git a/include/llvm/DebugInfo/PDB/Native/HashTable.h b/include/llvm/DebugInfo/PDB/Native/HashTable.h new file mode 100644 index 000000000000..46eefa968e52 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/HashTable.h @@ -0,0 +1,106 @@ +//===- HashTable.h - PDB 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_HASHTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_HASHTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include <cstdint> +#include <utility> + +namespace llvm { +namespace pdb { + +class HashTableIterator; + +class HashTable { + friend class HashTableIterator; + struct Header { + support::ulittle32_t Size; + support::ulittle32_t Capacity; + }; + + typedef std::vector<std::pair<uint32_t, uint32_t>> BucketList; + +public: + HashTable(); + explicit HashTable(uint32_t Capacity); + + Error load(BinaryStreamReader &Stream); + + uint32_t calculateSerializedLength() const; + Error commit(BinaryStreamWriter &Writer) const; + + void clear(); + + uint32_t capacity() const; + uint32_t size() const; + + HashTableIterator begin() const; + HashTableIterator end() const; + HashTableIterator find(uint32_t K); + + void set(uint32_t K, uint32_t V); + void remove(uint32_t K); + uint32_t get(uint32_t K); + +protected: + bool isPresent(uint32_t K) const { return Present.test(K); } + bool isDeleted(uint32_t K) const { return Deleted.test(K); } + BucketList Buckets; + mutable SparseBitVector<> Present; + mutable SparseBitVector<> Deleted; + +private: + static uint32_t maxLoad(uint32_t capacity); + void grow(); + + static Error readSparseBitVector(BinaryStreamReader &Stream, + SparseBitVector<> &V); + static Error writeSparseBitVector(BinaryStreamWriter &Writer, + SparseBitVector<> &Vec); +}; + +class HashTableIterator + : public iterator_facade_base<HashTableIterator, std::forward_iterator_tag, + std::pair<uint32_t, uint32_t>> { + friend class HashTable; + HashTableIterator(const HashTable &Map, uint32_t Index, bool IsEnd); + +public: + HashTableIterator(const HashTable &Map); + + HashTableIterator &operator=(const HashTableIterator &R); + bool operator==(const HashTableIterator &R) const; + const std::pair<uint32_t, uint32_t> &operator*() const; + HashTableIterator &operator++(); + +private: + bool isEnd() const { return IsEnd; } + uint32_t index() const { return Index; } + + const HashTable *Map; + uint32_t Index; + bool IsEnd; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_HASHTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h b/include/llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h index fb00d6ad4bc7..fb00d6ad4bc7 100644 --- a/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h +++ b/include/llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/include/llvm/DebugInfo/PDB/Native/InfoStream.h index 6b8b94ff1a36..1c38c2b6194f 100644 --- a/include/llvm/DebugInfo/PDB/Raw/InfoStream.h +++ b/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -10,11 +10,12 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/StringMap.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/PDBTypes.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" @@ -32,10 +33,18 @@ public: Error reload(); + uint32_t getStreamSize() const; + PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; uint32_t getAge() const; PDB_UniqueId getGuid() const; + uint32_t getNamedStreamMapByteSize() const; + + PdbRaw_Features getFeatures() const; + ArrayRef<PdbRaw_FeatureSig> getFeatureSignatures() const; + + const NamedStreamMap &getNamedStreams() const; uint32_t getNamedStreamIndex(llvm::StringRef Name) const; iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; @@ -61,7 +70,12 @@ private: // universally unique. PDB_UniqueId Guid; - NameMap NamedStreams; + std::vector<PdbRaw_FeatureSig> FeatureSignatures; + PdbRaw_Features Features = PdbFeatureNone; + + uint32_t NamedStreamMapByteSize = 0; + + NamedStreamMap NamedStreams; }; } } diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h index cb60b1eb69bd..90c28a90d252 100644 --- a/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h @@ -13,22 +13,24 @@ #include "llvm/ADT/Optional.h" #include "llvm/Support/Error.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.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 { +class WritableBinaryStreamRef; + namespace msf { class MSFBuilder; -class StreamWriter; } namespace pdb { class PDBFile; +class NamedStreamMap; class InfoStreamBuilder { public: - InfoStreamBuilder(msf::MSFBuilder &Msf); + InfoStreamBuilder(msf::MSFBuilder &Msf, NamedStreamMap &NamedStreams); InfoStreamBuilder(const InfoStreamBuilder &) = delete; InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; @@ -36,25 +38,25 @@ public: void setSignature(uint32_t S); void setAge(uint32_t A); void setGuid(PDB_UniqueId G); + void addFeature(PdbRaw_FeatureSig Sig); - NameMapBuilder &getNamedStreamsBuilder(); - - uint32_t calculateSerializedLength() const; + uint32_t finalize(); Error finalizeMsfLayout(); Error commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const; + WritableBinaryStreamRef Buffer) const; private: msf::MSFBuilder &Msf; + std::vector<PdbRaw_FeatureSig> Features; PdbRaw_ImplVer Ver; uint32_t Sig; uint32_t Age; PDB_UniqueId Guid; - NameMapBuilder NamedStreams; + NamedStreamMap &NamedStreams; }; } } diff --git a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/include/llvm/DebugInfo/PDB/Native/ModInfo.h index bf5cf53b3313..d26d0d618449 100644 --- a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h +++ b/include/llvm/DebugInfo/PDB/Native/ModInfo.h @@ -11,9 +11,9 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include <cstdint> #include <vector> @@ -30,7 +30,7 @@ public: ModInfo(const ModInfo &Info); ~ModInfo(); - static Error initialize(msf::ReadableStreamRef Stream, ModInfo &Info); + static Error initialize(BinaryStreamRef Stream, ModInfo &Info); bool hasECInfo() const; uint16_t getTypeServerIndex() const; @@ -63,10 +63,8 @@ struct ModuleInfoEx { } // end namespace pdb -namespace msf { - template <> struct VarStreamArrayExtractor<pdb::ModInfo> { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, + Error operator()(BinaryStreamRef Stream, uint32_t &Length, pdb::ModInfo &Info) const { if (auto EC = pdb::ModInfo::initialize(Stream, Info)) return EC; @@ -75,8 +73,6 @@ template <> struct VarStreamArrayExtractor<pdb::ModInfo> { } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H diff --git a/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h b/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h new file mode 100644 index 000000000000..605fd2483c3b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h @@ -0,0 +1,74 @@ +//===- ModInfoBuilder.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_MODINFOBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <string> +#include <vector> + +namespace llvm { +class BinaryStreamWriter; + +namespace msf { +class MSFBuilder; +struct MSFLayout; +} +namespace pdb { + +class ModInfoBuilder { + friend class DbiStreamBuilder; + +public: + ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, msf::MSFBuilder &Msf); + + ModInfoBuilder(const ModInfoBuilder &) = delete; + ModInfoBuilder &operator=(const ModInfoBuilder &) = delete; + + void setObjFileName(StringRef Name); + void addSymbol(codeview::CVSymbol Symbol); + + uint16_t getStreamIndex() const; + StringRef getModuleName() const { return ModuleName; } + StringRef getObjFileName() const { return ObjFileName; } + + ArrayRef<std::string> source_files() const { + return makeArrayRef(SourceFiles); + } + + uint32_t calculateSerializedLength() const; + + void finalize(); + Error finalizeMsfLayout(); + + Error commit(BinaryStreamWriter &ModiWriter, const msf::MSFLayout &MsfLayout, + WritableBinaryStreamRef MsfBuffer); + +private: + void addSourceFile(StringRef Path); + msf::MSFBuilder &MSF; + + uint32_t SymbolByteSize = 0; + std::string ModuleName; + std::string ObjFileName; + std::vector<std::string> SourceFiles; + std::vector<codeview::CVSymbol> Symbols; + ModuleInfoHeader Layout; +}; + +} // end namespace pdb + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/include/llvm/DebugInfo/PDB/Native/ModStream.h index d5e7a6830d8d..d65e195dbb95 100644 --- a/include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ b/include/llvm/DebugInfo/PDB/Native/ModStream.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" namespace llvm { @@ -50,9 +50,9 @@ private: std::unique_ptr<msf::MappedBlockStream> Stream; codeview::CVSymbolArray SymbolsSubstream; - msf::ReadableStreamRef LinesSubstream; - msf::ReadableStreamRef C13LinesSubstream; - msf::ReadableStreamRef GlobalRefsSubstream; + BinaryStreamRef LinesSubstream; + BinaryStreamRef C13LinesSubstream; + BinaryStreamRef GlobalRefsSubstream; codeview::ModuleSubstreamArray LineInfo; }; diff --git a/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h b/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h new file mode 100644 index 000000000000..d4206503e7dc --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h @@ -0,0 +1,55 @@ +//===- NamedStreamMap.h - PDB Named Stream 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_PDBNAMEDSTREAMMAP_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEDSTREAMMAP_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { +class BinaryStreamReader; +class BinaryStreamWriter; + +namespace pdb { +class NamedStreamMapBuilder; +class NamedStreamMap { + struct FinalizationInfo { + uint32_t StringDataBytes = 0; + uint32_t SerializedLength = 0; + }; + friend NamedStreamMapBuilder; + +public: + NamedStreamMap(); + + Error load(BinaryStreamReader &Stream); + Error commit(BinaryStreamWriter &Writer) const; + uint32_t finalize(); + + uint32_t size() const; + bool get(StringRef Stream, uint32_t &StreamNo) const; + void set(StringRef Stream, uint32_t StreamNo); + void remove(StringRef Stream); + + iterator_range<StringMapConstIterator<uint32_t>> entries() const; + +private: + Optional<FinalizationInfo> FinalizedInfo; + HashTable FinalizedHashTable; + StringMap<uint32_t> Mapping; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEDSTREAMMAP_H diff --git a/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h new file mode 100644 index 000000000000..8eeaf3e0ea49 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h @@ -0,0 +1,35 @@ +//===- NativeCompilandSymbol.h - native impl for compiland syms -*- 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_NATIVE_NATIVECOMPILANDSYMBOL_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVECOMPILANDSYMBOL_H + +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" + +namespace llvm { +namespace pdb { + +class NativeCompilandSymbol : public NativeRawSymbol { +public: + NativeCompilandSymbol(NativeSession &Session, const ModuleInfoEx &MI); + PDB_SymType getSymTag() const override; + bool isEditAndContinueEnabled() const override; + uint32_t getLexicalParentId() const override; + std::string getLibraryName() const override; + std::string getName() const override; + +private: + ModuleInfoEx Module; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/NativeEnumModules.h b/include/llvm/DebugInfo/PDB/Native/NativeEnumModules.h new file mode 100644 index 000000000000..60a55ee50cc4 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeEnumModules.h @@ -0,0 +1,41 @@ +//==- NativeEnumModules.h - Native Module Enumerator impl --------*- 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_NATIVE_NATIVEENUMMODULES_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMMODULES_H + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +namespace llvm { +namespace pdb { + +class NativeSession; + +class NativeEnumModules : public IPDBEnumChildren<PDBSymbol> { +public: + explicit NativeEnumModules(NativeSession &Session, + ArrayRef<ModuleInfoEx> Modules, + uint32_t Index = 0); + + uint32_t getChildCount() const override; + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<PDBSymbol> getNext() override; + void reset() override; + NativeEnumModules *clone() const override; + +private: + NativeSession &Session; + ArrayRef<ModuleInfoEx> Modules; + uint32_t Index; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h new file mode 100644 index 000000000000..9516810539b6 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h @@ -0,0 +1,39 @@ +//===- NativeExeSymbol.h - native impl for PDBSymbolExe ---------*- 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_NATIVE_NATIVEEXESYMBOL_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEEXESYMBOL_H + +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +namespace llvm { +namespace pdb { + +class NativeExeSymbol : public NativeRawSymbol { +public: + NativeExeSymbol(NativeSession &Session); + + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type) const override; + + uint32_t getAge() const override; + std::string getSymbolsFileName() const override; + PDB_UniqueId getGuid() const override; + bool hasCTypes() const override; + bool hasPrivateSymbols() const override; + +private: + PDBFile &File; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h new file mode 100644 index 000000000000..cffb5d09d225 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -0,0 +1,208 @@ +//===- NativeRawSymbol.h - Native implementation of IPDBRawSymbol - 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_NATIVE_NATIVERAWSYMBOL_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVERAWSYMBOL_H + +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" + +namespace llvm { +namespace pdb { + +class NativeSession; + +class NativeRawSymbol : public IPDBRawSymbol { +public: + explicit NativeRawSymbol(NativeSession &PDBSession); + + void dump(raw_ostream &OS, int Indent) const override; + + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type) const override; + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr<IPDBEnumSymbols> + findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, + uint32_t RVA) const override; + std::unique_ptr<IPDBEnumSymbols> + findInlineFramesByRVA(uint32_t RVA) const override; + + void getDataBytes(llvm::SmallVector<uint8_t, 32> &Bytes) const override; + void getFrontEndVersion(VersionInfo &Version) const override; + void getBackEndVersion(VersionInfo &Version) const override; + PDB_MemberAccess getAccess() const override; + uint32_t getAddressOffset() const override; + uint32_t getAddressSection() const override; + uint32_t getAge() const override; + uint32_t getArrayIndexTypeId() const override; + uint32_t getBaseDataOffset() const override; + uint32_t getBaseDataSlot() const override; + uint32_t getBaseSymbolId() const override; + PDB_BuiltinType getBuiltinType() const override; + uint32_t getBitPosition() const override; + PDB_CallingConv getCallingConvention() const override; + uint32_t getClassParentId() const override; + std::string getCompilerName() const override; + uint32_t getCount() const override; + uint32_t getCountLiveRanges() const override; + PDB_Lang getLanguage() const override; + uint32_t getLexicalParentId() const override; + std::string getLibraryName() const override; + uint32_t getLiveRangeStartAddressOffset() const override; + uint32_t getLiveRangeStartAddressSection() const override; + uint32_t getLiveRangeStartRelativeVirtualAddress() const override; + codeview::RegisterId getLocalBasePointerRegisterId() const override; + uint32_t getLowerBoundId() const override; + uint32_t getMemorySpaceKind() const override; + std::string getName() const override; + uint32_t getNumberOfAcceleratorPointerTags() const override; + uint32_t getNumberOfColumns() const override; + uint32_t getNumberOfModifiers() const override; + uint32_t getNumberOfRegisterIndices() const override; + uint32_t getNumberOfRows() const override; + std::string getObjectFileName() const override; + uint32_t getOemId() const override; + uint32_t getOemSymbolId() const override; + uint32_t getOffsetInUdt() const override; + PDB_Cpu getPlatform() const override; + uint32_t getRank() const override; + codeview::RegisterId getRegisterId() const override; + uint32_t getRegisterType() const override; + uint32_t getRelativeVirtualAddress() const override; + uint32_t getSamplerSlot() const override; + uint32_t getSignature() const override; + uint32_t getSizeInUdt() const override; + uint32_t getSlot() const override; + std::string getSourceFileName() const override; + uint32_t getStride() const override; + uint32_t getSubTypeId() const override; + std::string getSymbolsFileName() const override; + uint32_t getSymIndexId() const override; + uint32_t getTargetOffset() const override; + uint32_t getTargetRelativeVirtualAddress() const override; + uint64_t getTargetVirtualAddress() const override; + uint32_t getTargetSection() const override; + uint32_t getTextureSlot() const override; + uint32_t getTimeStamp() const override; + uint32_t getToken() const override; + uint32_t getTypeId() const override; + uint32_t getUavSlot() const override; + std::string getUndecoratedName() const override; + uint32_t getUnmodifiedTypeId() const override; + uint32_t getUpperBoundId() const override; + Variant getValue() const override; + uint32_t getVirtualBaseDispIndex() const override; + uint32_t getVirtualBaseOffset() const override; + uint32_t getVirtualTableShapeId() const override; + std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override; + PDB_DataKind getDataKind() const override; + PDB_SymType getSymTag() const override; + PDB_UniqueId getGuid() const override; + int32_t getOffset() const override; + int32_t getThisAdjust() const override; + int32_t getVirtualBasePointerOffset() const override; + PDB_LocType getLocationType() const override; + PDB_Machine getMachineType() const override; + codeview::ThunkOrdinal getThunkOrdinal() const override; + uint64_t getLength() const override; + uint64_t getLiveRangeLength() const override; + uint64_t getVirtualAddress() const override; + PDB_UdtType getUdtKind() const override; + bool hasConstructor() const override; + bool hasCustomCallingConvention() const override; + bool hasFarReturn() const override; + bool isCode() const override; + bool isCompilerGenerated() const override; + bool isConstType() const override; + bool isEditAndContinueEnabled() const override; + bool isFunction() const override; + bool getAddressTaken() const override; + bool getNoStackOrdering() const override; + bool hasAlloca() const override; + bool hasAssignmentOperator() const override; + bool hasCTypes() const override; + bool hasCastOperator() const override; + bool hasDebugInfo() const override; + bool hasEH() const override; + bool hasEHa() const override; + bool hasInlAsm() const override; + bool hasInlineAttribute() const override; + bool hasInterruptReturn() const override; + bool hasFramePointer() const override; + bool hasLongJump() const override; + bool hasManagedCode() const override; + bool hasNestedTypes() const override; + bool hasNoInlineAttribute() const override; + bool hasNoReturnAttribute() const override; + bool hasOptimizedCodeDebugInfo() const override; + bool hasOverloadedOperator() const override; + bool hasSEH() const override; + bool hasSecurityChecks() const override; + bool hasSetJump() const override; + bool hasStrictGSCheck() const override; + bool isAcceleratorGroupSharedLocal() const override; + bool isAcceleratorPointerTagLiveRange() const override; + bool isAcceleratorStubFunction() const override; + bool isAggregated() const override; + bool isIntroVirtualFunction() const override; + bool isCVTCIL() const override; + bool isConstructorVirtualBase() const override; + bool isCxxReturnUdt() const override; + bool isDataAligned() const override; + bool isHLSLData() const override; + bool isHotpatchable() const override; + bool isIndirectVirtualBaseClass() const override; + bool isInterfaceUdt() const override; + bool isIntrinsic() const override; + bool isLTCG() const override; + bool isLocationControlFlowDependent() const override; + bool isMSILNetmodule() const override; + bool isMatrixRowMajor() const override; + bool isManagedCode() const override; + bool isMSILCode() const override; + bool isMultipleInheritance() const override; + bool isNaked() const override; + bool isNested() const override; + bool isOptimizedAway() const override; + bool isPacked() const override; + bool isPointerBasedOnSymbolValue() const override; + bool isPointerToDataMember() const override; + bool isPointerToMemberFunction() const override; + bool isPureVirtual() const override; + bool isRValueReference() const override; + bool isRefUdt() const override; + bool isReference() const override; + bool isRestrictedType() const override; + bool isReturnValue() const override; + bool isSafeBuffers() const override; + bool isScoped() const override; + bool isSdl() const override; + bool isSingleInheritance() const override; + bool isSplitted() const override; + bool isStatic() const override; + bool hasPrivateSymbols() const override; + bool isUnalignedType() const override; + bool isUnreached() const override; + bool isValueUdt() const override; + bool isVirtual() const override; + bool isVirtualBaseClass() const override; + bool isVirtualInheritance() const override; + bool isVolatileType() const override; + bool wasInlined() const override; + std::string getUnused() const override; + +protected: + NativeSession &Session; +}; + +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawSession.h b/include/llvm/DebugInfo/PDB/Native/NativeSession.h index 5a6c469fcc8e..e6da266f796d 100644 --- a/include/llvm/DebugInfo/PDB/Raw/RawSession.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -1,4 +1,4 @@ -//===- RawSession.h - Native implementation of IPDBSession ------*- C++ -*-===// +//===- NativeSession.h - Native implementation of IPDBSession ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,11 +19,11 @@ namespace llvm { namespace pdb { class PDBFile; -class RawSession : public IPDBSession { +class NativeSession : public IPDBSession { public: - RawSession(std::unique_ptr<PDBFile> PdbFile, - std::unique_ptr<BumpPtrAllocator> Allocator); - ~RawSession() override; + NativeSession(std::unique_ptr<PDBFile> PdbFile, + std::unique_ptr<BumpPtrAllocator> Allocator); + ~NativeSession() override; static Error createFromPdb(StringRef Path, std::unique_ptr<IPDBSession> &Session); diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/include/llvm/DebugInfo/PDB/Native/PDBFile.h index 29f5b2163d83..fbca62d6e9d9 100644 --- a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -13,9 +13,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" @@ -24,6 +23,8 @@ namespace llvm { +class BinaryStream; + namespace msf { class MappedBlockStream; } @@ -32,7 +33,7 @@ namespace pdb { class DbiStream; class GlobalsStream; class InfoStream; -class NameHashTable; +class StringTable; class PDBFileBuilder; class PublicsStream; class SymbolStream; @@ -42,10 +43,13 @@ class PDBFile : public msf::IMSFFile { friend PDBFileBuilder; public: - PDBFile(std::unique_ptr<msf::ReadableStream> PdbFileBuffer, + PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, BumpPtrAllocator &Allocator); ~PDBFile() override; + StringRef getFileDirectory() const; + StringRef getFilePath() const; + uint32_t getFreeBlockMapBlock() const; uint32_t getUnknown1() const; @@ -77,7 +81,7 @@ public: } const msf::MSFLayout &getMsfLayout() const { return ContainerLayout; } - const msf::ReadableStream &getMsfBuffer() const { return *Buffer; } + BinaryStreamRef getMsfBuffer() const { return *Buffer; } ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; @@ -91,7 +95,7 @@ public: Expected<TpiStream &> getPDBIpiStream(); Expected<PublicsStream &> getPDBPublicsStream(); Expected<SymbolStream &> getPDBSymbolStream(); - Expected<NameHashTable &> getStringTable(); + Expected<StringTable &> getStringTable(); BumpPtrAllocator &getAllocator() { return Allocator; } @@ -104,14 +108,16 @@ public: bool hasPDBTpiStream() const; bool hasStringTable(); - private: - Expected<std::unique_ptr<msf::MappedBlockStream>> safelyCreateIndexedStream( - const msf::MSFLayout &Layout, const msf::ReadableStream &MsfData, - uint32_t StreamIndex) const; +private: + Expected<std::unique_ptr<msf::MappedBlockStream>> + safelyCreateIndexedStream(const msf::MSFLayout &Layout, + BinaryStreamRef MsfData, + uint32_t StreamIndex) const; + std::string FilePath; BumpPtrAllocator &Allocator; - std::unique_ptr<msf::ReadableStream> Buffer; + std::unique_ptr<BinaryStream> Buffer; std::vector<uint32_t> FpmPages; msf::MSFLayout ContainerLayout; @@ -125,7 +131,7 @@ public: std::unique_ptr<SymbolStream> Symbols; std::unique_ptr<msf::MappedBlockStream> DirectoryStream; std::unique_ptr<msf::MappedBlockStream> StringTableStream; - std::unique_ptr<NameHashTable> StringTable; + std::unique_ptr<StringTable> Strings; }; } } diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h index 27fc4b53b649..3898af5afc9e 100644 --- a/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -13,8 +13,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -44,11 +46,13 @@ public: DbiStreamBuilder &getDbiBuilder(); TpiStreamBuilder &getTpiBuilder(); TpiStreamBuilder &getIpiBuilder(); + StringTableBuilder &getStringTableBuilder(); Error commit(StringRef Filename); private: - Expected<msf::MSFLayout> finalizeMsfLayout() const; + Error addNamedStream(StringRef Name, uint32_t Size); + Expected<msf::MSFLayout> finalizeMsfLayout(); BumpPtrAllocator &Allocator; @@ -57,6 +61,9 @@ private: std::unique_ptr<DbiStreamBuilder> Dbi; std::unique_ptr<TpiStreamBuilder> Tpi; std::unique_ptr<TpiStreamBuilder> Ipi; + + StringTableBuilder Strings; + NamedStreamMap NamedStreams; }; } } diff --git a/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h b/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h new file mode 100644 index 000000000000..d965e1008e95 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h @@ -0,0 +1,48 @@ +//===- PDBTypeServerHandler.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_PDBTYPESERVERHANDLER_H +#define LLVM_DEBUGINFO_PDB_PDBTYPESERVERHANDLER_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeServerHandler.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include <memory> +#include <string> + +namespace llvm { +namespace pdb { +class NativeSession; + +class PDBTypeServerHandler : public codeview::TypeServerHandler { +public: + PDBTypeServerHandler(bool RevisitAlways = false); + + void addSearchPath(StringRef Path); + Expected<bool> handle(codeview::TypeServer2Record &TS, + codeview::TypeVisitorCallbacks &Callbacks) override; + +private: + Expected<bool> handleInternal(PDBFile &File, + codeview::TypeVisitorCallbacks &Callbacks); + + bool RevisitAlways; + std::unique_ptr<NativeSession> Session; + SmallVector<SmallString<64>, 4> SearchPaths; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h index 577f2986ff24..4a541edd6a7b 100644 --- a/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h +++ b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h @@ -12,11 +12,10 @@ #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" - +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Error.h" namespace llvm { @@ -38,16 +37,16 @@ public: uint32_t getNumBuckets() const { return NumBuckets; } iterator_range<codeview::CVSymbolArray::Iterator> getSymbols(bool *HadError) const; - msf::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { + FixedStreamArray<support::ulittle32_t> getHashBuckets() const { return HashBuckets; } - msf::FixedStreamArray<support::ulittle32_t> getAddressMap() const { + FixedStreamArray<support::ulittle32_t> getAddressMap() const { return AddressMap; } - msf::FixedStreamArray<support::ulittle32_t> getThunkMap() const { + FixedStreamArray<support::ulittle32_t> getThunkMap() const { return ThunkMap; } - msf::FixedStreamArray<SectionOffset> getSectionOffsets() const { + FixedStreamArray<SectionOffset> getSectionOffsets() const { return SectionOffsets; } @@ -59,11 +58,11 @@ private: std::unique_ptr<msf::MappedBlockStream> Stream; uint32_t NumBuckets = 0; ArrayRef<uint8_t> Bitmap; - msf::FixedStreamArray<PSHashRecord> HashRecords; - msf::FixedStreamArray<support::ulittle32_t> HashBuckets; - msf::FixedStreamArray<support::ulittle32_t> AddressMap; - msf::FixedStreamArray<support::ulittle32_t> ThunkMap; - msf::FixedStreamArray<SectionOffset> SectionOffsets; + FixedStreamArray<PSHashRecord> HashRecords; + FixedStreamArray<support::ulittle32_t> HashBuckets; + FixedStreamArray<support::ulittle32_t> AddressMap; + FixedStreamArray<support::ulittle32_t> ThunkMap; + FixedStreamArray<SectionOffset> SectionOffsets; const HeaderInfo *Header; const GSIHashHeader *HashHdr; diff --git a/include/llvm/DebugInfo/PDB/Raw/RawConstants.h b/include/llvm/DebugInfo/PDB/Native/RawConstants.h index af114ff52491..f5d4df8feb2e 100644 --- a/include/llvm/DebugInfo/PDB/Raw/RawConstants.h +++ b/include/llvm/DebugInfo/PDB/Native/RawConstants.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H #define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include <cstdint> @@ -32,6 +33,21 @@ enum PdbRaw_ImplVer : uint32_t { PdbImplVC140 = 20140508, }; +enum class PdbRaw_FeatureSig : uint32_t { + VC110 = PdbImplVC110, + VC140 = PdbImplVC140, + NoTypeMerge = 0x4D544F4E, + MinimalDebugInfo = 0x494E494D, +}; + +enum PdbRaw_Features : uint32_t { + PdbFeatureNone = 0x0, + PdbFeatureContainsIdStream = 0x1, + PdbFeatureMinimalDebugInfo = 0x2, + PdbFeatureNoTypeMerging = 0x4, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PdbFeatureNoTypeMerging) +}; + enum PdbRaw_DbiVer : uint32_t { PdbDbiVC41 = 930803, PdbDbiV50 = 19960307, diff --git a/include/llvm/DebugInfo/PDB/Raw/RawError.h b/include/llvm/DebugInfo/PDB/Native/RawError.h index f96b8066bbe5..3624a7682e38 100644 --- a/include/llvm/DebugInfo/PDB/Raw/RawError.h +++ b/include/llvm/DebugInfo/PDB/Native/RawError.h @@ -28,6 +28,7 @@ enum class raw_error_code { duplicate_entry, no_entry, not_writable, + stream_too_long, invalid_tpi_hash, }; diff --git a/include/llvm/DebugInfo/PDB/Raw/RawTypes.h b/include/llvm/DebugInfo/PDB/Native/RawTypes.h index d404b3994dbc..1b2631efce70 100644 --- a/include/llvm/DebugInfo/PDB/Raw/RawTypes.h +++ b/include/llvm/DebugInfo/PDB/Native/RawTypes.h @@ -266,6 +266,10 @@ struct PDB_UniqueId { uint8_t Guid[16]; }; +inline bool operator==(const PDB_UniqueId &LHS, const PDB_UniqueId &RHS) { + return 0 == ::memcmp(LHS.Guid, RHS.Guid, sizeof(LHS.Guid)); +} + // The header preceeding the global TPI stream. // This corresponds to `HDR` in PDB/dbi/tpi.h. struct TpiStreamHeader { @@ -302,6 +306,15 @@ struct InfoStreamHeader { PDB_UniqueId Guid; }; +/// The header preceeding the /names stream. +struct StringTableHeader { + support::ulittle32_t Signature; + support::ulittle32_t HashVersion; + support::ulittle32_t ByteSize; +}; + +const uint32_t StringTableSignature = 0xEFFEEFFE; + } // namespace pdb } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h b/include/llvm/DebugInfo/PDB/Native/StringTable.h index 00d022d4d8e2..dd5e30e61827 100644 --- a/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h +++ b/include/llvm/DebugInfo/PDB/Native/StringTable.h @@ -1,4 +1,4 @@ -//===- NameHashTable.h - PDB Name Hash Table --------------------*- C++ -*-===// +//===- StringTable.h - PDB String Table -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,29 +7,30 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H -#define LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H +#ifndef LLVM_DEBUGINFO_PDB_RAW_STRINGTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_STRINGTABLE_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> #include <vector> namespace llvm { -namespace msf { -class StreamReader; -} +class BinaryStreamReader; + namespace pdb { -class NameHashTable { +class StringTable { public: - NameHashTable(); + StringTable(); + + Error load(BinaryStreamReader &Stream); - Error load(msf::StreamReader &Stream); + uint32_t getByteSize() const; uint32_t getNameCount() const { return NameCount; } uint32_t getHashVersion() const { return HashVersion; } @@ -38,17 +39,18 @@ public: StringRef getStringForID(uint32_t ID) const; uint32_t getIDForString(StringRef Str) const; - msf::FixedStreamArray<support::ulittle32_t> name_ids() const; + FixedStreamArray<support::ulittle32_t> name_ids() const; private: - msf::ReadableStreamRef NamesBuffer; - msf::FixedStreamArray<support::ulittle32_t> IDs; - uint32_t Signature; - uint32_t HashVersion; - uint32_t NameCount; + BinaryStreamRef NamesBuffer; + FixedStreamArray<support::ulittle32_t> IDs; + uint32_t ByteSize = 0; + uint32_t Signature = 0; + uint32_t HashVersion = 0; + uint32_t NameCount = 0; }; } // end namespace pdb } // end namespace llvm -#endif // LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H +#endif // LLVM_DEBUGINFO_PDB_RAW_STRINGTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h b/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h new file mode 100644 index 000000000000..dd0f40b1978d --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h @@ -0,0 +1,44 @@ +//===- StringTableBuilder.h - PDB String Table Builder ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file creates the "/names" stream. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include <vector> + +namespace llvm { +class BinaryStreamWriter; + +namespace pdb { + +class StringTableBuilder { +public: + // If string S does not exist in the string table, insert it. + // Returns the ID for S. + uint32_t insert(StringRef S); + + uint32_t finalize(); + Error commit(BinaryStreamWriter &Writer) const; + +private: + DenseMap<StringRef, uint32_t> Strings; + uint32_t StringSize = 1; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H diff --git a/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h index 41d5e6ad64a0..41d5e6ad64a0 100644 --- a/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h +++ b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiHashing.h b/include/llvm/DebugInfo/PDB/Native/TpiHashing.h index 67a4952fcdfe..dd2698c354a2 100644 --- a/include/llvm/DebugInfo/PDB/Raw/TpiHashing.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiHashing.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> @@ -57,7 +57,7 @@ private: class TpiHashVerifier : public codeview::TypeVisitorCallbacks { public: - TpiHashVerifier(msf::FixedStreamArray<support::ulittle32_t> &HashValues, + TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues, uint32_t NumHashBuckets) : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} @@ -83,7 +83,7 @@ private: utohexstr(codeview::TypeIndex::FirstNonSimpleIndex + Index)); } - msf::FixedStreamArray<support::ulittle32_t> HashValues; + FixedStreamArray<support::ulittle32_t> HashValues; codeview::CVType RawRecord; uint32_t NumHashBuckets; uint32_t Index = -1; diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/include/llvm/DebugInfo/PDB/Native/TpiStream.h index de21abe4c817..62dde0ef08b7 100644 --- a/include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -11,10 +11,11 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" @@ -45,11 +46,11 @@ public: uint32_t getHashKeySize() const; uint32_t NumHashBuckets() const; - msf::FixedStreamArray<support::ulittle32_t> getHashValues() const; - msf::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; - msf::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const; + FixedStreamArray<support::ulittle32_t> getHashValues() const; + FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; + HashTable &getHashAdjusters(); - iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const; + codeview::CVTypeRange types(bool *HadError) const; Error commit(); @@ -61,10 +62,10 @@ private: codeview::CVTypeArray TypeRecords; - std::unique_ptr<msf::ReadableStream> HashStream; - msf::FixedStreamArray<support::ulittle32_t> HashValues; - msf::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; - msf::FixedStreamArray<TypeIndexOffset> HashAdjustments; + std::unique_ptr<BinaryStream> HashStream; + FixedStreamArray<support::ulittle32_t> HashValues; + FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; + HashTable HashAdjusters; const TpiStreamHeader *Header; }; diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h index f9a642126f53..a29ed0b610d3 100644 --- a/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h @@ -12,31 +12,33 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/SequencedItemStream.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include <vector> namespace llvm { -namespace codeview { -class TypeRecord; -} -namespace msf { -class ByteStream; -class MSFBuilder; -struct MSFLayout; -class ReadableStreamRef; -class WritableStream; +class BinaryByteStream; +class WritableBinaryStreamRef; -template <> struct SequencedItemTraits<llvm::codeview::CVType> { +template <> struct BinaryItemTraits<llvm::codeview::CVType> { static size_t length(const codeview::CVType &Item) { return Item.length(); } static ArrayRef<uint8_t> bytes(const codeview::CVType &Item) { return Item.data(); } }; + +namespace codeview { +class TypeRecord; +} +namespace msf { +class MSFBuilder; +struct MSFLayout; } namespace pdb { class PDBFile; @@ -52,26 +54,30 @@ public: TpiStreamBuilder &operator=(const TpiStreamBuilder &) = delete; void setVersionHeader(PdbRaw_TpiVer Version); - void addTypeRecord(const codeview::CVType &Record); + void addTypeRecord(ArrayRef<uint8_t> Type, Optional<uint32_t> Hash); Error finalizeMsfLayout(); - Error commit(const msf::MSFLayout &Layout, const msf::WritableStream &Buffer); + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); - uint32_t calculateSerializedLength() const; + uint32_t calculateSerializedLength(); private: uint32_t calculateHashBufferSize() const; + uint32_t calculateIndexOffsetSize() const; Error finalize(); msf::MSFBuilder &Msf; BumpPtrAllocator &Allocator; + size_t TypeRecordBytes = 0; + Optional<PdbRaw_TpiVer> VerHeader; - std::vector<codeview::CVType> TypeRecords; - msf::SequencedItemStream<codeview::CVType> TypeRecordStream; + std::vector<ArrayRef<uint8_t>> TypeRecords; + std::vector<uint32_t> TypeHashes; + std::vector<TypeIndexOffset> TypeIndexOffsets; uint32_t HashStreamIndex = kInvalidStreamIndex; - std::unique_ptr<msf::ByteStream> HashValueStream; + std::unique_ptr<BinaryByteStream> HashValueStream; const TpiStreamHeader *Header; uint32_t Idx; diff --git a/include/llvm/DebugInfo/PDB/PDBExtras.h b/include/llvm/DebugInfo/PDB/PDBExtras.h index 5a7422d9e9e4..fc5787556a6d 100644 --- a/include/llvm/DebugInfo/PDB/PDBExtras.h +++ b/include/llvm/DebugInfo/PDB/PDBExtras.h @@ -30,8 +30,8 @@ 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_UniqueId &Guid); 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); diff --git a/include/llvm/DebugInfo/PDB/PDBSymDumper.h b/include/llvm/DebugInfo/PDB/PDBSymDumper.h index 095c33cfe8b5..c976935c48e0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymDumper.h +++ b/include/llvm/DebugInfo/PDB/PDBSymDumper.h @@ -54,6 +54,22 @@ public: virtual void dump(const PDBSymbolUnknown &Symbol); virtual void dump(const PDBSymbolUsingNamespace &Symbol); + virtual void dumpRight(const PDBSymbolTypeArray &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeBaseClass &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeBuiltin &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeCustom &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeDimension &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeEnum &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeFriend &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeFunctionArg &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeManaged &Symbol) {} + virtual void dumpRight(const PDBSymbolTypePointer &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeTypedef &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeUDT &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeVTable &Symbol) {} + virtual void dumpRight(const PDBSymbolTypeVTableShape &Symbol) {} + private: bool RequireImpl; }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index bf5118806540..b114b7afb0b0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -22,6 +22,23 @@ return RawSymbol->MethodName(); \ } +#define FORWARD_CONCRETE_SYMBOL_ID_METHOD_WITH_NAME(ConcreteType, PrivateName, \ + PublicName) \ + auto PublicName##Id() const->decltype(RawSymbol->PrivateName##Id()) { \ + return RawSymbol->PrivateName##Id(); \ + } \ + std::unique_ptr<ConcreteType> PublicName() const { \ + uint32_t Id = PublicName##Id(); \ + return getConcreteSymbolByIdHelper<ConcreteType>(Id); \ + } + +#define FORWARD_SYMBOL_ID_METHOD_WITH_NAME(PrivateName, PublicName) \ + FORWARD_CONCRETE_SYMBOL_ID_METHOD_WITH_NAME(PDBSymbol, PrivateName, \ + PublicName) + +#define FORWARD_SYMBOL_ID_METHOD(MethodName) \ + FORWARD_SYMBOL_ID_METHOD_WITH_NAME(MethodName, MethodName) + namespace llvm { class StringRef; @@ -29,6 +46,7 @@ class raw_ostream; namespace pdb { class IPDBRawSymbol; +class IPDBSession; #define DECLARE_PDB_SYMBOL_CONCRETE_TYPE(TagValue) \ static const PDB_SymType Tag = TagValue; \ @@ -44,6 +62,7 @@ class PDBSymbol { protected: PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol); + PDBSymbol(PDBSymbol &Symbol); public: static std::unique_ptr<PDBSymbol> @@ -56,7 +75,14 @@ public: /// unknown properties, but individual implementations of PDBSymbol may /// override the behavior to only dump known fields. virtual void dump(PDBSymDumper &Dumper) const = 0; + + /// For certain PDBSymbolTypes, dumps additional information for the type that + /// normally goes on the right side of the symbol. + virtual void dumpRight(PDBSymDumper &Dumper) const {} + void defaultDump(raw_ostream &OS, int Indent) const; + void dumpProperties() const; + void dumpChildStats() const; PDB_SymType getSymTag() const; uint32_t getSymIndexId() const; @@ -66,6 +92,8 @@ public: return Enumerator->getNext(); } + std::unique_ptr<PDBSymbol> clone() const; + template <typename T> std::unique_ptr<ConcreteSymbolEnumerator<T>> findAllChildren() const { auto BaseIter = RawSymbol->findChildren(T::Tag); @@ -91,8 +119,15 @@ public: std::unique_ptr<IPDBEnumSymbols> getChildStats(TagStats &Stats) const; protected: + std::unique_ptr<PDBSymbol> getSymbolByIdHelper(uint32_t Id) const; + + template <typename ConcreteType> + std::unique_ptr<ConcreteType> getConcreteSymbolByIdHelper(uint32_t Id) const { + return unique_dyn_cast_or_null<ConcreteType>(getSymbolByIdHelper(Id)); + } + const IPDBSession &Session; - const std::unique_ptr<IPDBRawSymbol> RawSymbol; + std::unique_ptr<IPDBRawSymbol> RawSymbol; }; } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h index d0ff62ca7c3f..d81da1eaa023 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h @@ -30,7 +30,7 @@ public: FORWARD_SYMBOL_METHOD(getAddressOffset) FORWARD_SYMBOL_METHOD(getAddressSection) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h index f1983b3f7bf5..26788017cf32 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h @@ -29,7 +29,7 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(isEditAndContinueEnabled) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLibraryName) FORWARD_SYMBOL_METHOD(getName) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h index bb4a78f68e2f..dba50c42cf81 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h @@ -46,7 +46,7 @@ public: FORWARD_SYMBOL_METHOD(isLTCG) FORWARD_SYMBOL_METHOD(isMSILNetmodule) FORWARD_SYMBOL_METHOD(getLanguage) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getPlatform) FORWARD_SYMBOL_METHOD(getSourceFileName) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h index a71a0ba2df58..7868f0459086 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h @@ -26,7 +26,7 @@ public: void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) std::string getValue() const; }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolData.h b/include/llvm/DebugInfo/PDB/PDBSymbolData.h index 36f32ab51c11..ad4285df4d44 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolData.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolData.h @@ -26,8 +26,6 @@ public: DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::Data) - std::unique_ptr<PDBSymbol> getType() const; - void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getAccess) @@ -35,14 +33,14 @@ public: FORWARD_SYMBOL_METHOD(getAddressSection) FORWARD_SYMBOL_METHOD(getAddressTaken) FORWARD_SYMBOL_METHOD(getBitPosition) - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(isCompilerGenerated) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getDataKind) FORWARD_SYMBOL_METHOD(isAggregated) FORWARD_SYMBOL_METHOD(isSplitted) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(getOffset) @@ -50,7 +48,7 @@ public: FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getSlot) FORWARD_SYMBOL_METHOD(getToken) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(getValue) FORWARD_SYMBOL_METHOD(getVirtualAddress) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h index 5b3f50d153eb..2c2d74665040 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h @@ -37,6 +37,8 @@ public: FORWARD_SYMBOL_METHOD(getSignature) FORWARD_SYMBOL_METHOD(getSymbolsFileName) + uint32_t getPointerByteSize() const; + private: void dumpChildren(raw_ostream &OS, StringRef Label, PDB_SymType ChildType, int Indent) const; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index 7170bcbe846c..c2f02ea6f126 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H #include "PDBSymbol.h" +#include "PDBSymbolTypeFunctionSig.h" #include "PDBTypes.h" namespace llvm { @@ -26,8 +27,8 @@ public: void dump(PDBSymDumper &Dumper) const override; - std::unique_ptr<PDBSymbolTypeFunctionSig> getSignature() const; - std::unique_ptr<PDBSymbolTypeUDT> getClassParent() const; + bool isDestructor() const; + std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> getArguments() const; DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::Function) @@ -35,7 +36,7 @@ public: FORWARD_SYMBOL_METHOD(getAccess) FORWARD_SYMBOL_METHOD(getAddressOffset) FORWARD_SYMBOL_METHOD(getAddressSection) - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(isCompilerGenerated) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(hasCustomCallingConvention) @@ -54,7 +55,7 @@ public: FORWARD_SYMBOL_METHOD(isNaked) FORWARD_SYMBOL_METHOD(isStatic) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocalBasePointerRegisterId) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) @@ -67,7 +68,8 @@ public: FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) FORWARD_SYMBOL_METHOD(getToken) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_CONCRETE_SYMBOL_ID_METHOD_WITH_NAME(PDBSymbolTypeFunctionSig, getType, + getSignature) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(getUndecoratedName) FORWARD_SYMBOL_METHOD(isVirtual) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h index 464389503bef..3341bd9b30fd 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h @@ -34,7 +34,7 @@ public: FORWARD_SYMBOL_METHOD(hasFarReturn) FORWARD_SYMBOL_METHOD(hasInterruptReturn) FORWARD_SYMBOL_METHOD(isStatic) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(hasNoInlineAttribute) FORWARD_SYMBOL_METHOD(hasNoReturnAttribute) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h index c2e3dd39be6c..6729838597c8 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h @@ -33,7 +33,7 @@ public: FORWARD_SYMBOL_METHOD(hasFarReturn) FORWARD_SYMBOL_METHOD(hasInterruptReturn) FORWARD_SYMBOL_METHOD(isStatic) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(hasNoInlineAttribute) FORWARD_SYMBOL_METHOD(hasNoReturnAttribute) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h index 3aeae10b47bc..c2b1c28c929e 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h @@ -32,7 +32,7 @@ public: FORWARD_SYMBOL_METHOD(hasCustomCallingConvention) FORWARD_SYMBOL_METHOD(hasFarReturn) FORWARD_SYMBOL_METHOD(hasInterruptReturn) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(hasNoInlineAttribute) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h index be0734445973..c9e6ee67c575 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h @@ -32,7 +32,7 @@ public: FORWARD_SYMBOL_METHOD(isCode) FORWARD_SYMBOL_METHOD(isFunction) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getLocationType) FORWARD_SYMBOL_METHOD(isManagedCode) FORWARD_SYMBOL_METHOD(isMSILCode) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h index 63f7a09fc881..614fad86caa8 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h @@ -30,12 +30,12 @@ public: FORWARD_SYMBOL_METHOD(getAccess) FORWARD_SYMBOL_METHOD(getAddressOffset) FORWARD_SYMBOL_METHOD(getAddressSection) - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(isIntroVirtualFunction) FORWARD_SYMBOL_METHOD(isStatic) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isPureVirtual) FORWARD_SYMBOL_METHOD(getRelativeVirtualAddress) @@ -44,7 +44,7 @@ public: FORWARD_SYMBOL_METHOD(getTargetVirtualAddress) FORWARD_SYMBOL_METHOD(getTargetSection) FORWARD_SYMBOL_METHOD(getThunkOrdinal) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVirtual) FORWARD_SYMBOL_METHOD(getVirtualAddress) diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h index 57db03661fb7..39b7d3b300ea 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h @@ -25,17 +25,16 @@ public: DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::ArrayType) - std::unique_ptr<PDBSymbol> getElementType() const; - void dump(PDBSymDumper &Dumper) const override; + void dumpRight(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getArrayIndexTypeId) + FORWARD_SYMBOL_ID_METHOD(getArrayIndexType) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getCount) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getRank) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD_WITH_NAME(getType, getElementType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h index aaa3ab7988d7..d607a3d81170 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h @@ -13,6 +13,9 @@ #include "PDBSymbol.h" #include "PDBTypes.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + namespace llvm { class raw_ostream; @@ -28,7 +31,7 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getAccess) - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(hasConstructor) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(hasAssignmentOperator) @@ -36,14 +39,14 @@ public: FORWARD_SYMBOL_METHOD(hasNestedTypes) FORWARD_SYMBOL_METHOD(isIndirectVirtualBaseClass) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getType) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) @@ -51,7 +54,7 @@ public: FORWARD_SYMBOL_METHOD(getVirtualBaseDispIndex) FORWARD_SYMBOL_METHOD(getVirtualBasePointerOffset) // FORWARD_SYMBOL_METHOD(getVirtualBaseTableType) - FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) + FORWARD_SYMBOL_ID_METHOD(getVirtualTableShape) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h index c8f59f1f140a..5b1863c42a04 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h @@ -30,7 +30,7 @@ public: FORWARD_SYMBOL_METHOD(getBuiltinType) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h index ade2887bac14..c5ae3c51162c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H #include "PDBSymbol.h" +#include "PDBSymbolTypeBuiltin.h" #include "PDBTypes.h" namespace llvm { @@ -27,25 +28,22 @@ public: void dump(PDBSymDumper &Dumper) const override; - std::unique_ptr<PDBSymbolTypeUDT> getClassParent() const; - std::unique_ptr<PDBSymbolTypeBuiltin> getUnderlyingType() const; - FORWARD_SYMBOL_METHOD(getBuiltinType) - FORWARD_SYMBOL_METHOD(getClassParentId) - FORWARD_SYMBOL_METHOD(getUnmodifiedTypeId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(hasConstructor) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(hasAssignmentOperator) FORWARD_SYMBOL_METHOD(hasCastOperator) FORWARD_SYMBOL_METHOD(hasNestedTypes) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_CONCRETE_SYMBOL_ID_METHOD_WITH_NAME(PDBSymbolTypeBuiltin, getType, + getUnderlyingType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h index 196d149ed2a2..24c13128111f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h @@ -27,9 +27,9 @@ public: void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(getName) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getType) }; } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h index 5561341d7e77..3855999c473f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h @@ -27,9 +27,9 @@ public: void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getClassParentId) - FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) + FORWARD_SYMBOL_ID_METHOD(getType) }; } // namespace llvm diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h index 516011ff8b3d..8de54e70701d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h @@ -25,22 +25,21 @@ public: DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::FunctionSig) - std::unique_ptr<PDBSymbol> getReturnType() const; std::unique_ptr<IPDBEnumSymbols> getArguments() const; - std::unique_ptr<PDBSymbol> getClassParent() const; void dump(PDBSymDumper &Dumper) const override; + void dumpRight(PDBSymDumper &Dumper) const override; void dumpArgList(raw_ostream &OS) const; FORWARD_SYMBOL_METHOD(getCallingConvention) - FORWARD_SYMBOL_METHOD(getClassParentId) - FORWARD_SYMBOL_METHOD(getUnmodifiedTypeId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) + FORWARD_SYMBOL_ID_METHOD(getUnmodifiedType) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getCount) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) // FORWARD_SYMBOL_METHOD(getObjectPointerType) FORWARD_SYMBOL_METHOD(getThisAdjust) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD_WITH_NAME(getType, getReturnType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index 7a57272adb79..c502d4e77afe 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -25,15 +25,14 @@ public: DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::PointerType) - std::unique_ptr<PDBSymbol> getPointeeType() const; - void dump(PDBSymDumper &Dumper) const override; + void dumpRight(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(isReference) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD_WITH_NAME(getType, getPointeeType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h index 5ed4f8d21d90..16c1d1b88c6d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h @@ -28,24 +28,24 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getBuiltinType) - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) FORWARD_SYMBOL_METHOD(hasConstructor) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(hasAssignmentOperator) FORWARD_SYMBOL_METHOD(hasCastOperator) FORWARD_SYMBOL_METHOD(hasNestedTypes) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) FORWARD_SYMBOL_METHOD(isPacked) FORWARD_SYMBOL_METHOD(isReference) FORWARD_SYMBOL_METHOD(isScoped) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getType) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) - FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) + FORWARD_SYMBOL_ID_METHOD(getVirtualTableShape) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index 1874dfef34f7..e9e7fe8c9865 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -10,7 +10,9 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H +#include "IPDBSession.h" #include "PDBSymbol.h" +#include "PDBSymbolTypeBaseClass.h" #include "PDBTypes.h" namespace llvm { @@ -18,24 +20,30 @@ namespace llvm { class raw_ostream; namespace pdb { + class PDBSymbolTypeUDT : public PDBSymbol { public: PDBSymbolTypeUDT(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> UDTSymbol); + std::unique_ptr<PDBSymbolTypeUDT> clone() const { + return getSession().getConcreteSymbolById<PDBSymbolTypeUDT>( + getSymIndexId()); + } + DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::UDT) void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getClassParentId) - FORWARD_SYMBOL_METHOD(getUnmodifiedTypeId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) + FORWARD_SYMBOL_ID_METHOD(getUnmodifiedType) FORWARD_SYMBOL_METHOD(hasConstructor) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(hasAssignmentOperator) FORWARD_SYMBOL_METHOD(hasCastOperator) FORWARD_SYMBOL_METHOD(hasNestedTypes) FORWARD_SYMBOL_METHOD(getLength) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) FORWARD_SYMBOL_METHOD(isNested) FORWARD_SYMBOL_METHOD(hasOverloadedOperator) @@ -43,7 +51,7 @@ public: FORWARD_SYMBOL_METHOD(isScoped) FORWARD_SYMBOL_METHOD(getUdtKind) FORWARD_SYMBOL_METHOD(isUnalignedType) - FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) + FORWARD_SYMBOL_ID_METHOD(getVirtualTableShape) FORWARD_SYMBOL_METHOD(isVolatileType) }; } diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h index baf7ab79d60e..e270c2b7eb95 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h @@ -27,10 +27,11 @@ public: void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getClassParentId) + FORWARD_SYMBOL_ID_METHOD(getClassParent) + FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(isConstType) - FORWARD_SYMBOL_METHOD(getLexicalParentId) - FORWARD_SYMBOL_METHOD(getTypeId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) + FORWARD_SYMBOL_ID_METHOD(getType) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h index 431fc1ac8625..8acaabea5bb8 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h @@ -29,7 +29,7 @@ public: FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_METHOD(getCount) - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(isUnalignedType) FORWARD_SYMBOL_METHOD(isVolatileType) }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h index a273fe159c12..70fbd5b84c34 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h @@ -27,7 +27,7 @@ public: void dump(PDBSymDumper &Dumper) const override; - FORWARD_SYMBOL_METHOD(getLexicalParentId) + FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_METHOD(getName) }; diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index 0d232f15d745..dd2fc4f2c55f 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -12,7 +12,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include <cstdint> #include <cstring> #include <functional> @@ -68,10 +68,10 @@ class PDBSymbolTypeDimension; class PDBSymbolUnknown; /// Specifies which PDB reader implementation is to be used. Only a value -/// of PDB_ReaderType::DIA is supported. +/// of PDB_ReaderType::DIA is currently supported, but Native is in the works. enum class PDB_ReaderType { DIA = 0, - Raw = 1, + Native = 1, }; /// An enumeration indicating the type of data contained in this table. diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMap.h b/include/llvm/DebugInfo/PDB/Raw/NameMap.h deleted file mode 100644 index de1163bc3079..000000000000 --- a/include/llvm/DebugInfo/PDB/Raw/NameMap.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- 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 msf { -class StreamReader; -class StreamWriter; -} -namespace pdb { -class NameMapBuilder; -class NameMap { - friend NameMapBuilder; - -public: - NameMap(); - - Error load(msf::StreamReader &Stream); - - 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 deleted file mode 100644 index f5244ac21808..000000000000 --- a/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- 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 msf { -class StreamWriter; -} -namespace pdb { -class NameMap; - -class NameMapBuilder { -public: - NameMapBuilder(); - - void addMapping(StringRef Name, uint32_t Mapping); - - Expected<std::unique_ptr<NameMap>> build(); - Error commit(msf::StreamWriter &Writer) const; - - 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/UDTLayout.h b/include/llvm/DebugInfo/PDB/UDTLayout.h new file mode 100644 index 000000000000..e3dcba50bd1a --- /dev/null +++ b/include/llvm/DebugInfo/PDB/UDTLayout.h @@ -0,0 +1,180 @@ +//===- UDTLayout.h - UDT layout info ----------------------------*- 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_UDTLAYOUT_H +#define LLVM_DEBUGINFO_PDB_UDTLAYOUT_H + +#include "PDBSymbol.h" +#include "PDBTypes.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" + +#include <list> +#include <memory> + +namespace llvm { + +class raw_ostream; + +namespace pdb { + +class PDBSymTypeBaseClass; +class PDBSymbolData; +class PDBSymbolTypeUDT; +class PDBSymbolTypeVTable; + +class ClassLayout; +class BaseClassLayout; +class StorageItemBase; +class UDTLayoutBase; + +class StorageItemBase { +public: + StorageItemBase(const UDTLayoutBase &Parent, const PDBSymbol &Symbol, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size); + virtual ~StorageItemBase() {} + + virtual uint32_t deepPaddingSize() const; + + const UDTLayoutBase &getParent() const { return Parent; } + StringRef getName() const { return Name; } + uint32_t getOffsetInParent() const { return OffsetInParent; } + uint32_t getSize() const { return SizeOf; } + const PDBSymbol &getSymbol() const { return Symbol; } + +protected: + const UDTLayoutBase &Parent; + const PDBSymbol &Symbol; + BitVector UsedBytes; + std::string Name; + uint32_t OffsetInParent = 0; + uint32_t SizeOf = 0; +}; + +class DataMemberLayoutItem : public StorageItemBase { +public: + DataMemberLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolData> DataMember); + + virtual uint32_t deepPaddingSize() const; + + const PDBSymbolData &getDataMember(); + bool hasUDTLayout() const; + const ClassLayout &getUDTLayout() const; + +private: + std::unique_ptr<PDBSymbolData> DataMember; + std::unique_ptr<ClassLayout> UdtLayout; +}; + +class VTableLayoutItem : public StorageItemBase { +public: + VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VTable); + ArrayRef<PDBSymbolFunc *> funcs() const { return VTableFuncs; } + + uint32_t getElementSize() const { return ElementSize; } + + void setFunction(uint32_t Index, PDBSymbolFunc &Func) { + VTableFuncs[Index] = &Func; + } + +private: + uint32_t ElementSize = 0; + std::unique_ptr<PDBSymbolTypeVTableShape> Shape; + std::unique_ptr<PDBSymbolTypeVTable> VTable; + std::vector<PDBSymbolFunc *> VTableFuncs; +}; + +class UDTLayoutBase { + template <typename T> using UniquePtrVector = std::vector<std::unique_ptr<T>>; + +public: + UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, + uint32_t Size); + + uint32_t shallowPaddingSize() const; + uint32_t deepPaddingSize() const; + + const BitVector &usedBytes() const { return UsedBytes; } + + uint32_t getClassSize() const { return SizeOf; } + + ArrayRef<std::unique_ptr<StorageItemBase>> layout_items() const { + return ChildStorage; + } + + VTableLayoutItem *findVTableAtOffset(uint32_t RelativeOffset); + + StringRef getUDTName() const { return Name; } + + ArrayRef<BaseClassLayout *> bases() const { return BaseClasses; } + ArrayRef<std::unique_ptr<PDBSymbolTypeBaseClass>> vbases() const { + return VirtualBases; + } + + ArrayRef<std::unique_ptr<PDBSymbolFunc>> funcs() const { return Funcs; } + + ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const { return Other; } + + const PDBSymbol &getSymbolBase() const { return SymbolBase; } + +protected: + void initializeChildren(const PDBSymbol &Sym); + + void addChildToLayout(std::unique_ptr<StorageItemBase> Child); + void addVirtualOverride(PDBSymbolFunc &Func); + void addVirtualIntro(PDBSymbolFunc &Func); + + const PDBSymbol &SymbolBase; + std::string Name; + uint32_t SizeOf = 0; + + BitVector UsedBytes; + UniquePtrVector<PDBSymbol> Other; + UniquePtrVector<PDBSymbolFunc> Funcs; + UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBases; + UniquePtrVector<StorageItemBase> ChildStorage; + std::vector<std::list<StorageItemBase *>> ChildrenPerByte; + std::vector<BaseClassLayout *> BaseClasses; + VTableLayoutItem *VTable = nullptr; +}; + +class ClassLayout : public UDTLayoutBase { +public: + explicit ClassLayout(const PDBSymbolTypeUDT &UDT); + explicit ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT); + + ClassLayout(ClassLayout &&Other) = default; + + const PDBSymbolTypeUDT &getClass() const { return UDT; } + +private: + std::unique_ptr<PDBSymbolTypeUDT> OwnedStorage; + const PDBSymbolTypeUDT &UDT; +}; + +class BaseClassLayout : public UDTLayoutBase, public StorageItemBase { +public: + BaseClassLayout(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBaseClass> Base); + + const PDBSymbolTypeBaseClass &getBase() const { return *Base; } + bool isVirtualBase() const { return IsVirtualBase; } + +private: + std::unique_ptr<PDBSymbolTypeBaseClass> Base; + bool IsVirtualBase; +}; +} +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_UDTLAYOUT_H diff --git a/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/include/llvm/DebugInfo/Symbolize/DIPrinter.h index 49f86eae01cf..ab82be3706d8 100644 --- a/include/llvm/DebugInfo/Symbolize/DIPrinter.h +++ b/include/llvm/DebugInfo/Symbolize/DIPrinter.h @@ -29,15 +29,18 @@ class DIPrinter { bool PrintFunctionNames; bool PrintPretty; int PrintSourceContext; + bool Verbose; void print(const DILineInfo &Info, bool Inlined); void printContext(const std::string &FileName, int64_t Line); public: DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true, - bool PrintPretty = false, int PrintSourceContext = 0) + bool PrintPretty = false, int PrintSourceContext = 0, + bool Verbose = false) : OS(OS), PrintFunctionNames(PrintFunctionNames), - PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext) {} + PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext), + Verbose(Verbose) {} DIPrinter &operator<<(const DILineInfo &Info); DIPrinter &operator<<(const DIInliningInfo &Info); diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index aa096478cd9e..7e7f7358938a 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -376,7 +376,7 @@ private: // Initializers may refer to functions declared (but not defined) in this // module. Build a materializer to clone decls on demand. auto Materializer = createLambdaMaterializer( - [this, &LD, &GVsM](Value *V) -> Value* { + [&LD, &GVsM](Value *V) -> Value* { if (auto *F = dyn_cast<Function>(V)) { // Decls in the original module just get cloned. if (F->isDeclaration()) @@ -419,7 +419,7 @@ private: // Build a resolver for the globals module and add it to the base layer. auto GVsResolver = createLambdaResolver( - [this, &LD, LMId](const std::string &Name) { + [this, &LD](const std::string &Name) { if (auto Sym = LD.StubsMgr->findStub(Name, false)) return Sym; if (auto Sym = LD.findSymbol(BaseLayer, Name, false)) @@ -499,8 +499,8 @@ private: M->setDataLayout(SrcM.getDataLayout()); ValueToValueMapTy VMap; - auto Materializer = createLambdaMaterializer([this, &LD, &LMId, &M, - &VMap](Value *V) -> Value * { + auto Materializer = createLambdaMaterializer([&LD, &LMId, + &M](Value *V) -> Value * { if (auto *GV = dyn_cast<GlobalVariable>(V)) return cloneGlobalVariableDecl(*M, *GV); @@ -546,12 +546,12 @@ private: // Create memory manager and symbol resolver. auto Resolver = createLambdaResolver( - [this, &LD, LMId](const std::string &Name) { + [this, &LD](const std::string &Name) { if (auto Sym = LD.findSymbol(BaseLayer, Name, false)) return Sym; return LD.ExternalSymbolResolver->findSymbolInLogicalDylib(Name); }, - [this, &LD](const std::string &Name) { + [&LD](const std::string &Name) { return LD.ExternalSymbolResolver->findSymbol(Name); }); diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h index b74988cce2fb..cbb40fad0223 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcError.h +++ b/include/llvm/ExecutionEngine/Orc/OrcError.h @@ -27,13 +27,15 @@ enum class OrcErrorCode : int { RemoteMProtectAddrUnrecognized, RemoteIndirectStubsOwnerDoesNotExist, RemoteIndirectStubsOwnerIdAlreadyInUse, + RPCConnectionClosed, + RPCCouldNotNegotiateFunction, RPCResponseAbandoned, UnexpectedRPCCall, UnexpectedRPCResponse, - UnknownRPCFunction + UnknownErrorCodeFromRemote }; -Error orcError(OrcErrorCode ErrCode); +std::error_code 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 8647db56cd2f..02f59d6a831a 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -18,6 +18,7 @@ #include "IndirectionUtils.h" #include "OrcRemoteTargetRPCAPI.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include <system_error> #define DEBUG_TYPE "orc-remote" diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index 506330fe3a5e..a61ff102be0b 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -132,7 +132,7 @@ private: Error setProtections(void *block, unsigned Flags) { auto I = Allocs.find(block); if (I == Allocs.end()) - return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized); + return errorCodeToError(orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized)); return errorCodeToError( sys::Memory::protectMappedMemory(I->second, Flags)); } @@ -198,7 +198,8 @@ private: Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I != Allocators.end()) - return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse); + return errorCodeToError( + orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse)); DEBUG(dbgs() << " Created allocator " << Id << "\n"); Allocators[Id] = Allocator(); return Error::success(); @@ -207,7 +208,8 @@ private: Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I != IndirectStubsOwners.end()) - return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse); + return errorCodeToError( + orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse)); DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n"); IndirectStubsOwners[Id] = ISBlockOwnerList(); return Error::success(); @@ -224,7 +226,8 @@ private: Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I == Allocators.end()) - return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); + return errorCodeToError( + orcError(OrcErrorCode::RemoteAllocatorDoesNotExist)); Allocators.erase(I); DEBUG(dbgs() << " Destroyed allocator " << Id << "\n"); return Error::success(); @@ -233,7 +236,8 @@ private: Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I == IndirectStubsOwners.end()) - return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); + return errorCodeToError( + orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist)); IndirectStubsOwners.erase(I); return Error::success(); } @@ -246,7 +250,8 @@ private: auto StubOwnerItr = IndirectStubsOwners.find(Id); if (StubOwnerItr == IndirectStubsOwners.end()) - return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); + return errorCodeToError( + orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist)); typename TargetT::IndirectStubsInfo IS; if (auto Err = @@ -361,7 +366,8 @@ private: uint64_t Size, uint32_t Align) { auto I = Allocators.find(Id); if (I == Allocators.end()) - return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); + return errorCodeToError( + orcError(OrcErrorCode::RemoteAllocatorDoesNotExist)); auto &Allocator = I->second; void *LocalAllocAddr = nullptr; if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align)) @@ -380,7 +386,8 @@ private: JITTargetAddress Addr, uint32_t Flags) { auto I = Allocators.find(Id); if (I == Allocators.end()) - return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); + return errorCodeToError( + orcError(OrcErrorCode::RemoteAllocatorDoesNotExist)); auto &Allocator = I->second; void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr)); DEBUG(dbgs() << " Allocator " << Id << " set permissions on " << LocalAddr diff --git a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h index 359a9d81b22b..84a037b2f998 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h +++ b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h @@ -12,6 +12,7 @@ #include "OrcError.h" #include "llvm/Support/thread.h" +#include <map> #include <mutex> #include <sstream> @@ -114,6 +115,35 @@ public: static const char* getName() { return "std::string"; } }; +template <> +class RPCTypeName<Error> { +public: + static const char* getName() { return "Error"; } +}; + +template <typename T> +class RPCTypeName<Expected<T>> { +public: + static const char* getName() { + std::lock_guard<std::mutex> Lock(NameMutex); + if (Name.empty()) + raw_string_ostream(Name) << "Expected<" + << RPCTypeNameSequence<T>() + << ">"; + return Name.data(); + } + +private: + static std::mutex NameMutex; + static std::string Name; +}; + +template <typename T> +std::mutex RPCTypeName<Expected<T>>::NameMutex; + +template <typename T> +std::string RPCTypeName<Expected<T>>::Name; + template <typename T1, typename T2> class RPCTypeName<std::pair<T1, T2>> { public: @@ -243,8 +273,10 @@ class SequenceSerialization<ChannelT, ArgT> { public: template <typename CArgT> - static Error serialize(ChannelT &C, const CArgT &CArg) { - return SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg); + static Error serialize(ChannelT &C, CArgT &&CArg) { + return SerializationTraits<ChannelT, ArgT, + typename std::decay<CArgT>::type>:: + serialize(C, std::forward<CArgT>(CArg)); } template <typename CArgT> @@ -258,19 +290,21 @@ class SequenceSerialization<ChannelT, ArgT, ArgTs...> { public: template <typename CArgT, typename... CArgTs> - static Error serialize(ChannelT &C, const CArgT &CArg, - const CArgTs&... CArgs) { + static Error serialize(ChannelT &C, CArgT &&CArg, + CArgTs &&... CArgs) { if (auto Err = - SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg)) + SerializationTraits<ChannelT, ArgT, typename std::decay<CArgT>::type>:: + serialize(C, std::forward<CArgT>(CArg))) return Err; if (auto Err = SequenceTraits<ChannelT>::emitSeparator(C)) return Err; - return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, CArgs...); + return SequenceSerialization<ChannelT, ArgTs...>:: + serialize(C, std::forward<CArgTs>(CArgs)...); } template <typename CArgT, typename... CArgTs> static Error deserialize(ChannelT &C, CArgT &CArg, - CArgTs&... CArgs) { + CArgTs &... CArgs) { if (auto Err = SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg)) return Err; @@ -281,8 +315,9 @@ public: }; template <typename ChannelT, typename... ArgTs> -Error serializeSeq(ChannelT &C, const ArgTs &... Args) { - return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, Args...); +Error serializeSeq(ChannelT &C, ArgTs &&... Args) { + return SequenceSerialization<ChannelT, typename std::decay<ArgTs>::type...>:: + serialize(C, std::forward<ArgTs>(Args)...); } template <typename ChannelT, typename... ArgTs> @@ -290,6 +325,196 @@ Error deserializeSeq(ChannelT &C, ArgTs &... Args) { return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, Args...); } +template <typename ChannelT> +class SerializationTraits<ChannelT, Error> { +public: + + using WrappedErrorSerializer = + std::function<Error(ChannelT &C, const ErrorInfoBase&)>; + + using WrappedErrorDeserializer = + std::function<Error(ChannelT &C, Error &Err)>; + + template <typename ErrorInfoT, typename SerializeFtor, + typename DeserializeFtor> + static void registerErrorType(std::string Name, SerializeFtor Serialize, + DeserializeFtor Deserialize) { + assert(!Name.empty() && + "The empty string is reserved for the Success value"); + + const std::string *KeyName = nullptr; + { + // We're abusing the stability of std::map here: We take a reference to the + // key of the deserializers map to save us from duplicating the string in + // the serializer. This should be changed to use a stringpool if we switch + // to a map type that may move keys in memory. + std::lock_guard<std::mutex> Lock(DeserializersMutex); + auto I = + Deserializers.insert(Deserializers.begin(), + std::make_pair(std::move(Name), + std::move(Deserialize))); + KeyName = &I->first; + } + + { + assert(KeyName != nullptr && "No keyname pointer"); + std::lock_guard<std::mutex> Lock(SerializersMutex); + // FIXME: Move capture Serialize once we have C++14. + Serializers[ErrorInfoT::classID()] = + [KeyName, Serialize](ChannelT &C, const ErrorInfoBase &EIB) -> Error { + assert(EIB.dynamicClassID() == ErrorInfoT::classID() && + "Serializer called for wrong error type"); + if (auto Err = serializeSeq(C, *KeyName)) + return Err; + return Serialize(C, static_cast<const ErrorInfoT&>(EIB)); + }; + } + } + + static Error serialize(ChannelT &C, Error &&Err) { + std::lock_guard<std::mutex> Lock(SerializersMutex); + if (!Err) + return serializeSeq(C, std::string()); + + return handleErrors(std::move(Err), + [&C](const ErrorInfoBase &EIB) { + auto SI = Serializers.find(EIB.dynamicClassID()); + if (SI == Serializers.end()) + return serializeAsStringError(C, EIB); + return (SI->second)(C, EIB); + }); + } + + static Error deserialize(ChannelT &C, Error &Err) { + std::lock_guard<std::mutex> Lock(DeserializersMutex); + + std::string Key; + if (auto Err = deserializeSeq(C, Key)) + return Err; + + if (Key.empty()) { + ErrorAsOutParameter EAO(&Err); + Err = Error::success(); + return Error::success(); + } + + auto DI = Deserializers.find(Key); + assert(DI != Deserializers.end() && "No deserializer for error type"); + return (DI->second)(C, Err); + } + +private: + + static Error serializeAsStringError(ChannelT &C, const ErrorInfoBase &EIB) { + assert(EIB.dynamicClassID() != StringError::classID() && + "StringError serialization not registered"); + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + EIB.log(ErrMsgStream); + } + return serialize(C, make_error<StringError>(std::move(ErrMsg), + inconvertibleErrorCode())); + } + + static std::mutex SerializersMutex; + static std::mutex DeserializersMutex; + static std::map<const void*, WrappedErrorSerializer> Serializers; + static std::map<std::string, WrappedErrorDeserializer> Deserializers; +}; + +template <typename ChannelT> +std::mutex SerializationTraits<ChannelT, Error>::SerializersMutex; + +template <typename ChannelT> +std::mutex SerializationTraits<ChannelT, Error>::DeserializersMutex; + +template <typename ChannelT> +std::map<const void*, + typename SerializationTraits<ChannelT, Error>::WrappedErrorSerializer> +SerializationTraits<ChannelT, Error>::Serializers; + +template <typename ChannelT> +std::map<std::string, + typename SerializationTraits<ChannelT, Error>::WrappedErrorDeserializer> +SerializationTraits<ChannelT, Error>::Deserializers; + +template <typename ChannelT> +void registerStringError() { + static bool AlreadyRegistered = false; + if (!AlreadyRegistered) { + SerializationTraits<ChannelT, Error>:: + template registerErrorType<StringError>( + "StringError", + [](ChannelT &C, const StringError &SE) { + return serializeSeq(C, SE.getMessage()); + }, + [](ChannelT &C, Error &Err) { + ErrorAsOutParameter EAO(&Err); + std::string Msg; + if (auto E2 = deserializeSeq(C, Msg)) + return E2; + Err = + make_error<StringError>(std::move(Msg), + orcError( + OrcErrorCode::UnknownErrorCodeFromRemote)); + return Error::success(); + }); + AlreadyRegistered = true; + } +} + +/// SerializationTraits for Expected<T1> from an Expected<T2>. +template <typename ChannelT, typename T1, typename T2> +class SerializationTraits<ChannelT, Expected<T1>, Expected<T2>> { +public: + + static Error serialize(ChannelT &C, Expected<T2> &&ValOrErr) { + if (ValOrErr) { + if (auto Err = serializeSeq(C, true)) + return Err; + return SerializationTraits<ChannelT, T1, T2>::serialize(C, *ValOrErr); + } + if (auto Err = serializeSeq(C, false)) + return Err; + return serializeSeq(C, ValOrErr.takeError()); + } + + static Error deserialize(ChannelT &C, Expected<T2> &ValOrErr) { + ExpectedAsOutParameter<T2> EAO(&ValOrErr); + bool HasValue; + if (auto Err = deserializeSeq(C, HasValue)) + return Err; + if (HasValue) + return SerializationTraits<ChannelT, T1, T2>::deserialize(C, *ValOrErr); + Error Err = Error::success(); + if (auto E2 = deserializeSeq(C, Err)) + return E2; + ValOrErr = std::move(Err); + return Error::success(); + } +}; + +/// SerializationTraits for Expected<T1> from a T2. +template <typename ChannelT, typename T1, typename T2> +class SerializationTraits<ChannelT, Expected<T1>, T2> { +public: + + static Error serialize(ChannelT &C, T2 &&Val) { + return serializeSeq(C, Expected<T2>(std::forward<T2>(Val))); + } +}; + +/// SerializationTraits for Expected<T1> from an Error. +template <typename ChannelT, typename T> +class SerializationTraits<ChannelT, Expected<T>, Error> { +public: + + static Error serialize(ChannelT &C, Error &&Err) { + return serializeSeq(C, Expected<T>(std::move(Err))); + } +}; + /// SerializationTraits default specialization for std::pair. template <typename ChannelT, typename T1, typename T2> class SerializationTraits<ChannelT, std::pair<T1, T2>> { diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h index 37e2e66e5af4..6212f64ff319 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCUtils.h +++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h @@ -26,27 +26,115 @@ #include "llvm/ExecutionEngine/Orc/OrcError.h" #include "llvm/ExecutionEngine/Orc/RPCSerialization.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 rpc { +/// Base class of all fatal RPC errors (those that necessarily result in the +/// termination of the RPC session). +class RPCFatalError : public ErrorInfo<RPCFatalError> { +public: + static char ID; +}; + +/// RPCConnectionClosed is returned from RPC operations if the RPC connection +/// has already been closed due to either an error or graceful disconnection. +class ConnectionClosed : public ErrorInfo<ConnectionClosed> { +public: + static char ID; + std::error_code convertToErrorCode() const override; + void log(raw_ostream &OS) const override; +}; + +/// BadFunctionCall is returned from handleOne when the remote makes a call with +/// an unrecognized function id. +/// +/// This error is fatal because Orc RPC needs to know how to parse a function +/// call to know where the next call starts, and if it doesn't recognize the +/// function id it cannot parse the call. +template <typename FnIdT, typename SeqNoT> +class BadFunctionCall + : public ErrorInfo<BadFunctionCall<FnIdT, SeqNoT>, RPCFatalError> { +public: + static char ID; + + BadFunctionCall(FnIdT FnId, SeqNoT SeqNo) + : FnId(std::move(FnId)), SeqNo(std::move(SeqNo)) {} + + std::error_code convertToErrorCode() const override { + return orcError(OrcErrorCode::UnexpectedRPCCall); + } + + void log(raw_ostream &OS) const override { + OS << "Call to invalid RPC function id '" << FnId << "' with " + "sequence number " << SeqNo; + } + +private: + FnIdT FnId; + SeqNoT SeqNo; +}; + +template <typename FnIdT, typename SeqNoT> +char BadFunctionCall<FnIdT, SeqNoT>::ID = 0; + +/// InvalidSequenceNumberForResponse is returned from handleOne when a response +/// call arrives with a sequence number that doesn't correspond to any in-flight +/// function call. +/// +/// This error is fatal because Orc RPC needs to know how to parse the rest of +/// the response call to know where the next call starts, and if it doesn't have +/// a result parser for this sequence number it can't do that. +template <typename SeqNoT> +class InvalidSequenceNumberForResponse + : public ErrorInfo<InvalidSequenceNumberForResponse<SeqNoT>, RPCFatalError> { +public: + static char ID; + + InvalidSequenceNumberForResponse(SeqNoT SeqNo) + : SeqNo(std::move(SeqNo)) {} + + std::error_code convertToErrorCode() const override { + return orcError(OrcErrorCode::UnexpectedRPCCall); + }; + + void log(raw_ostream &OS) const override { + OS << "Response has unknown sequence number " << SeqNo; + } +private: + SeqNoT SeqNo; +}; + +template <typename SeqNoT> +char InvalidSequenceNumberForResponse<SeqNoT>::ID = 0; + +/// This non-fatal error will be passed to asynchronous result handlers in place +/// of a result if the connection goes down before a result returns, or if the +/// function to be called cannot be negotiated with the remote. +class ResponseAbandoned : public ErrorInfo<ResponseAbandoned> { +public: + static char ID; + + std::error_code convertToErrorCode() const override; + void log(raw_ostream &OS) const override; +}; + +/// This error is returned if the remote does not have a handler installed for +/// the given RPC function. +class CouldNotNegotiate : public ErrorInfo<CouldNotNegotiate> { +public: + static char ID; + + CouldNotNegotiate(std::string Signature); + std::error_code convertToErrorCode() const override; + void log(raw_ostream &OS) const override; + const std::string &getSignature() const { return Signature; } +private: + std::string Signature; +}; + template <typename DerivedFunc, typename FnT> class Function; // RPC Function class. @@ -82,16 +170,6 @@ std::mutex Function<DerivedFunc, RetT(ArgTs...)>::NameMutex; template <typename DerivedFunc, typename RetT, typename... ArgTs> std::string Function<DerivedFunc, RetT(ArgTs...)>::Name; -/// Provides a typedef for a tuple containing the decayed argument types. -template <typename T> class FunctionArgsTuple; - -template <typename RetT, typename... ArgTs> -class FunctionArgsTuple<RetT(ArgTs...)> { -public: - using Type = std::tuple<typename std::decay< - typename std::remove_reference<ArgTs>::type>::type...>; -}; - /// Allocates RPC function ids during autonegotiation. /// Specializations of this class must provide four members: /// @@ -196,6 +274,16 @@ public: #endif // _MSC_VER +/// Provides a typedef for a tuple containing the decayed argument types. +template <typename T> class FunctionArgsTuple; + +template <typename RetT, typename... ArgTs> +class FunctionArgsTuple<RetT(ArgTs...)> { +public: + using Type = std::tuple<typename std::decay< + typename std::remove_reference<ArgTs>::type>::type...>; +}; + // ResultTraits provides typedefs and utilities specific to the return type // of functions. template <typename RetT> class ResultTraits { @@ -274,43 +362,132 @@ template <> class ResultTraits<Error> : public ResultTraits<void> {}; template <typename RetT> class ResultTraits<Expected<RetT>> : public ResultTraits<RetT> {}; +// Determines whether an RPC function's defined error return type supports +// error return value. +template <typename T> +class SupportsErrorReturn { +public: + static const bool value = false; +}; + +template <> +class SupportsErrorReturn<Error> { +public: + static const bool value = true; +}; + +template <typename T> +class SupportsErrorReturn<Expected<T>> { +public: + static const bool value = true; +}; + +// RespondHelper packages return values based on whether or not the declared +// RPC function return type supports error returns. +template <bool FuncSupportsErrorReturn> +class RespondHelper; + +// RespondHelper specialization for functions that support error returns. +template <> +class RespondHelper<true> { +public: + + // Send Expected<T>. + template <typename WireRetT, typename HandlerRetT, typename ChannelT, + typename FunctionIdT, typename SequenceNumberT> + static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId, + SequenceNumberT SeqNo, + Expected<HandlerRetT> ResultOrErr) { + if (!ResultOrErr && ResultOrErr.template errorIsA<RPCFatalError>()) + return ResultOrErr.takeError(); + + // Open the response message. + if (auto Err = C.startSendMessage(ResponseId, SeqNo)) + return Err; + + // Serialize the result. + if (auto Err = + SerializationTraits<ChannelT, WireRetT, + Expected<HandlerRetT>>::serialize( + C, std::move(ResultOrErr))) + return Err; + + // Close the response message. + return C.endSendMessage(); + } + + template <typename ChannelT, typename FunctionIdT, typename SequenceNumberT> + static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId, + SequenceNumberT SeqNo, Error Err) { + if (Err && Err.isA<RPCFatalError>()) + return Err; + if (auto Err2 = C.startSendMessage(ResponseId, SeqNo)) + return Err2; + if (auto Err2 = serializeSeq(C, std::move(Err))) + return Err2; + return C.endSendMessage(); + } + +}; + +// RespondHelper specialization for functions that do not support error returns. +template <> +class RespondHelper<false> { +public: + + template <typename WireRetT, typename HandlerRetT, typename ChannelT, + typename FunctionIdT, typename SequenceNumberT> + static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId, + SequenceNumberT SeqNo, + Expected<HandlerRetT> ResultOrErr) { + if (auto Err = ResultOrErr.takeError()) + return Err; + + // Open the response message. + if (auto Err = C.startSendMessage(ResponseId, SeqNo)) + return Err; + + // Serialize the result. + if (auto Err = + SerializationTraits<ChannelT, WireRetT, HandlerRetT>::serialize( + C, *ResultOrErr)) + return Err; + + // Close the response message. + return C.endSendMessage(); + } + + template <typename ChannelT, typename FunctionIdT, typename SequenceNumberT> + static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId, + SequenceNumberT SeqNo, Error Err) { + if (Err) + return Err; + if (auto Err2 = C.startSendMessage(ResponseId, SeqNo)) + return Err2; + return C.endSendMessage(); + } + +}; + + // Send a response of the given wire return type (WireRetT) over the // channel, with the given sequence number. template <typename WireRetT, typename HandlerRetT, typename ChannelT, typename FunctionIdT, typename SequenceNumberT> -static Error respond(ChannelT &C, const FunctionIdT &ResponseId, - SequenceNumberT SeqNo, Expected<HandlerRetT> ResultOrErr) { - // If this was an error bail out. - // FIXME: Send an "error" message to the client if this is not a channel - // failure? - if (auto Err = ResultOrErr.takeError()) - return Err; - - // Open the response message. - if (auto Err = C.startSendMessage(ResponseId, SeqNo)) - return Err; - - // Serialize the result. - if (auto Err = - SerializationTraits<ChannelT, WireRetT, HandlerRetT>::serialize( - C, *ResultOrErr)) - return Err; - - // Close the response message. - return C.endSendMessage(); +Error respond(ChannelT &C, const FunctionIdT &ResponseId, + SequenceNumberT SeqNo, Expected<HandlerRetT> ResultOrErr) { + return RespondHelper<SupportsErrorReturn<WireRetT>::value>:: + template sendResult<WireRetT>(C, ResponseId, SeqNo, std::move(ResultOrErr)); } // Send an empty response message on the given channel to indicate that // the handler ran. template <typename WireRetT, typename ChannelT, typename FunctionIdT, typename SequenceNumberT> -static Error respond(ChannelT &C, const FunctionIdT &ResponseId, - SequenceNumberT SeqNo, Error Err) { - if (Err) - return Err; - if (auto Err2 = C.startSendMessage(ResponseId, SeqNo)) - return Err2; - return C.endSendMessage(); +Error respond(ChannelT &C, const FunctionIdT &ResponseId, SequenceNumberT SeqNo, + Error Err) { + return RespondHelper<SupportsErrorReturn<WireRetT>::value>:: + sendResult(C, ResponseId, SeqNo, std::move(Err)); } // Converts a given type to the equivalent error return type. @@ -339,6 +516,29 @@ public: using Type = Error; }; +// Traits class that strips the response function from the list of handler +// arguments. +template <typename FnT> class AsyncHandlerTraits; + +template <typename ResultT, typename... ArgTs> +class AsyncHandlerTraits<Error(std::function<Error(Expected<ResultT>)>, ArgTs...)> { +public: + using Type = Error(ArgTs...); + using ResultType = Expected<ResultT>; +}; + +template <typename... ArgTs> +class AsyncHandlerTraits<Error(std::function<Error(Error)>, ArgTs...)> { +public: + using Type = Error(ArgTs...); + using ResultType = Error; +}; + +template <typename ResponseHandlerT, typename... ArgTs> +class AsyncHandlerTraits<Error(ResponseHandlerT, ArgTs...)> : + public AsyncHandlerTraits<Error(typename std::decay<ResponseHandlerT>::type, + ArgTs...)> {}; + // This template class provides utilities related to RPC function handlers. // The base case applies to non-function types (the template class is // specialized for function types) and inherits from the appropriate @@ -358,15 +558,20 @@ public: // Return type of the handler. using ReturnType = RetT; - // A std::tuple wrapping the handler arguments. - using ArgStorage = typename FunctionArgsTuple<RetT(ArgTs...)>::Type; - // Call the given handler with the given arguments. - template <typename HandlerT> + template <typename HandlerT, typename... TArgTs> static typename WrappedHandlerReturn<RetT>::Type - unpackAndRun(HandlerT &Handler, ArgStorage &Args) { + unpackAndRun(HandlerT &Handler, std::tuple<TArgTs...> &Args) { return unpackAndRunHelper(Handler, Args, - llvm::index_sequence_for<ArgTs...>()); + llvm::index_sequence_for<TArgTs...>()); + } + + // Call the given handler with the given arguments. + template <typename HandlerT, typename ResponderT, typename... TArgTs> + static Error unpackAndRunAsync(HandlerT &Handler, ResponderT &Responder, + std::tuple<TArgTs...> &Args) { + return unpackAndRunAsyncHelper(Handler, Responder, Args, + llvm::index_sequence_for<TArgTs...>()); } // Call the given handler with the given arguments. @@ -379,11 +584,11 @@ public: return Error::success(); } - template <typename HandlerT> + template <typename HandlerT, typename... TArgTs> static typename std::enable_if< !std::is_void<typename HandlerTraits<HandlerT>::ReturnType>::value, typename HandlerTraits<HandlerT>::ReturnType>::type - run(HandlerT &Handler, ArgTs... Args) { + run(HandlerT &Handler, TArgTs... Args) { return Handler(std::move(Args)...); } @@ -408,15 +613,31 @@ private: C, std::get<Indexes>(Args)...); } - template <typename HandlerT, size_t... Indexes> + template <typename HandlerT, typename ArgTuple, size_t... Indexes> static typename WrappedHandlerReturn< typename HandlerTraits<HandlerT>::ReturnType>::Type - unpackAndRunHelper(HandlerT &Handler, ArgStorage &Args, + unpackAndRunHelper(HandlerT &Handler, ArgTuple &Args, llvm::index_sequence<Indexes...>) { return run(Handler, std::move(std::get<Indexes>(Args))...); } + + + template <typename HandlerT, typename ResponderT, typename ArgTuple, + size_t... Indexes> + static typename WrappedHandlerReturn< + typename HandlerTraits<HandlerT>::ReturnType>::Type + unpackAndRunAsyncHelper(HandlerT &Handler, ResponderT &Responder, + ArgTuple &Args, + llvm::index_sequence<Indexes...>) { + return run(Handler, Responder, std::move(std::get<Indexes>(Args))...); + } }; +// Handler traits for free functions. +template <typename RetT, typename... ArgTs> +class HandlerTraits<RetT(*)(ArgTs...)> + : public HandlerTraits<RetT(ArgTs...)> {}; + // Handler traits for class methods (especially call operators for lambdas). template <typename Class, typename RetT, typename... ArgTs> class HandlerTraits<RetT (Class::*)(ArgTs...)> @@ -471,7 +692,7 @@ public: // Create an error instance representing an abandoned response. static Error createAbandonedResponseError() { - return orcError(OrcErrorCode::RPCResponseAbandoned); + return make_error<ResponseAbandoned>(); } }; @@ -493,7 +714,7 @@ public: return Err; if (auto Err = C.endReceiveMessage()) return Err; - return Handler(Result); + return Handler(std::move(Result)); } // Abandon this response by calling the handler with an 'abandoned response' @@ -538,6 +759,72 @@ private: HandlerT Handler; }; +template <typename ChannelT, typename FuncRetT, typename HandlerT> +class ResponseHandlerImpl<ChannelT, Expected<FuncRetT>, HandlerT> + : public ResponseHandler<ChannelT> { +public: + ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {} + + // Handle the result by deserializing it from the channel then passing it + // to the user defined handler. + Error handleResponse(ChannelT &C) override { + using HandlerArgType = typename ResponseHandlerArg< + typename HandlerTraits<HandlerT>::Type>::ArgType; + HandlerArgType Result((typename HandlerArgType::value_type())); + + if (auto Err = + SerializationTraits<ChannelT, Expected<FuncRetT>, + HandlerArgType>::deserialize(C, Result)) + return Err; + if (auto Err = C.endReceiveMessage()) + return Err; + return Handler(std::move(Result)); + } + + // Abandon this response by calling the handler with an 'abandoned response' + // error. + void abandon() override { + if (auto Err = Handler(this->createAbandonedResponseError())) { + // Handlers should not fail when passed an abandoned response error. + report_fatal_error(std::move(Err)); + } + } + +private: + HandlerT Handler; +}; + +template <typename ChannelT, typename HandlerT> +class ResponseHandlerImpl<ChannelT, Error, HandlerT> + : public ResponseHandler<ChannelT> { +public: + ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {} + + // Handle the result by deserializing it from the channel then passing it + // to the user defined handler. + Error handleResponse(ChannelT &C) override { + Error Result = Error::success(); + if (auto Err = + SerializationTraits<ChannelT, Error, Error>::deserialize(C, Result)) + return Err; + if (auto Err = C.endReceiveMessage()) + return Err; + return Handler(std::move(Result)); + } + + // Abandon this response by calling the handler with an 'abandoned response' + // error. + void abandon() override { + if (auto Err = Handler(this->createAbandonedResponseError())) { + // Handlers should not fail when passed an abandoned response error. + report_fatal_error(std::move(Err)); + } + } + +private: + HandlerT Handler; +}; + // Create a ResponseHandler from a given user handler. template <typename ChannelT, typename FuncRetT, typename HandlerT> std::unique_ptr<ResponseHandler<ChannelT>> createResponseHandler(HandlerT H) { @@ -758,8 +1045,13 @@ public: auto NegotiateId = FnIdAllocator.getNegotiateId(); RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId; Handlers[NegotiateId] = wrapHandler<OrcRPCNegotiate>( - [this](const std::string &Name) { return handleNegotiate(Name); }, - LaunchPolicy()); + [this](const std::string &Name) { return handleNegotiate(Name); }); + } + + + /// Negotiate a function id for Func with the other end of the channel. + template <typename Func> Error negotiateFunction(bool Retry = false) { + return getRemoteFunctionId<Func>(true, Retry).takeError(); } /// Append a call Func, does not call send on the channel. @@ -777,14 +1069,12 @@ public: // Look up the function ID. FunctionIdT FnId; - if (auto FnIdOrErr = getRemoteFunctionId<Func>()) + if (auto FnIdOrErr = getRemoteFunctionId<Func>(LazyAutoNegotiation, false)) FnId = *FnIdOrErr; else { - // This isn't a channel error so we don't want to abandon other pending - // responses, but we still need to run the user handler with an error to - // let them know the call failed. - if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction))) - report_fatal_error(std::move(Err)); + // Negotiation failed. Notify the handler then return the negotiate-failed + // error. + cantFail(Handler(make_error<ResponseAbandoned>())); return FnIdOrErr.takeError(); } @@ -807,20 +1097,20 @@ public: // Open the function call message. if (auto Err = C.startSendMessage(FnId, SeqNo)) { abandonPendingResponses(); - return joinErrors(std::move(Err), C.endSendMessage()); + return Err; } // Serialize the call arguments. if (auto Err = detail::HandlerTraits<typename Func::Type>::serializeArgs( C, Args...)) { abandonPendingResponses(); - return joinErrors(std::move(Err), C.endSendMessage()); + return Err; } // Close the function call messagee. if (auto Err = C.endSendMessage()) { abandonPendingResponses(); - return std::move(Err); + return Err; } return Error::success(); @@ -839,8 +1129,10 @@ public: Error handleOne() { FunctionIdT FnId; SequenceNumberT SeqNo; - if (auto Err = C.startReceiveMessage(FnId, SeqNo)) + if (auto Err = C.startReceiveMessage(FnId, SeqNo)) { + abandonPendingResponses(); return Err; + } if (FnId == ResponseId) return handleResponse(SeqNo); auto I = Handlers.find(FnId); @@ -848,7 +1140,8 @@ public: return I->second(C, SeqNo); // else: No handler found. Report error to client? - return orcError(OrcErrorCode::UnexpectedRPCCall); + return make_error<BadFunctionCall<FunctionIdT, SequenceNumberT>>(FnId, + SeqNo); } /// Helper for handling setter procedures - this method returns a functor that @@ -887,10 +1180,25 @@ public: SequenceNumberMgr.reset(); } + /// Remove the handler for the given function. + /// A handler must currently be registered for this function. + template <typename Func> + void removeHandler() { + auto IdItr = LocalFunctionIds.find(Func::getPrototype()); + assert(IdItr != LocalFunctionIds.end() && + "Function does not have a registered handler"); + auto HandlerItr = Handlers.find(IdItr->second); + assert(HandlerItr != Handlers.end() && + "Function does not have a registered handler"); + Handlers.erase(HandlerItr); + } + + /// Clear all handlers. + void clearHandlers() { + Handlers.clear(); + } + protected: - // The LaunchPolicy type allows a launch policy to be specified when adding - // a function handler. See addHandlerImpl. - using LaunchPolicy = std::function<Error(std::function<Error()>)>; FunctionIdT getInvalidFunctionId() const { return FnIdAllocator.getInvalidId(); @@ -899,7 +1207,7 @@ protected: /// Add the given handler to the handler map and make it available for /// autonegotiation and execution. template <typename Func, typename HandlerT> - void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) { + void addHandlerImpl(HandlerT Handler) { static_assert(detail::RPCArgTypeCheck< CanDeserializeCheck, typename Func::Type, @@ -908,8 +1216,22 @@ protected: FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>(); LocalFunctionIds[Func::getPrototype()] = NewFnId; - Handlers[NewFnId] = - wrapHandler<Func>(std::move(Handler), std::move(Launch)); + Handlers[NewFnId] = wrapHandler<Func>(std::move(Handler)); + } + + template <typename Func, typename HandlerT> + void addAsyncHandlerImpl(HandlerT Handler) { + + static_assert(detail::RPCArgTypeCheck< + CanDeserializeCheck, typename Func::Type, + typename detail::AsyncHandlerTraits< + typename detail::HandlerTraits<HandlerT>::Type + >::Type>::value, + ""); + + FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>(); + LocalFunctionIds[Func::getPrototype()] = NewFnId; + Handlers[NewFnId] = wrapAsyncHandler<Func>(std::move(Handler)); } Error handleResponse(SequenceNumberT SeqNo) { @@ -929,7 +1251,8 @@ protected: // Unlock the pending results map to prevent recursive lock. Lock.unlock(); abandonPendingResponses(); - return orcError(OrcErrorCode::UnexpectedRPCResponse); + return make_error< + InvalidSequenceNumberForResponse<SequenceNumberT>>(SeqNo); } } @@ -951,41 +1274,39 @@ protected: return I->second; } - // Find the remote FunctionId for the given function, which must be in the - // RemoteFunctionIds map. - template <typename Func> Expected<FunctionIdT> getRemoteFunctionId() { - // Try to find the id for the given function. - auto I = RemoteFunctionIds.find(Func::getPrototype()); + // Find the remote FunctionId for the given function. + template <typename Func> + Expected<FunctionIdT> getRemoteFunctionId(bool NegotiateIfNotInMap, + bool NegotiateIfInvalid) { + bool DoNegotiate; - // If we have it in the map, return it. - if (I != RemoteFunctionIds.end()) - return I->second; + // Check if we already have a function id... + auto I = RemoteFunctionIds.find(Func::getPrototype()); + if (I != RemoteFunctionIds.end()) { + // If it's valid there's nothing left to do. + if (I->second != getInvalidFunctionId()) + return I->second; + DoNegotiate = NegotiateIfInvalid; + } else + DoNegotiate = NegotiateIfNotInMap; - // Otherwise, if we have auto-negotiation enabled, try to negotiate it. - if (LazyAutoNegotiation) { + // We don't have a function id for Func yet, but we're allowed to try to + // negotiate one. + if (DoNegotiate) { auto &Impl = static_cast<ImplT &>(*this); if (auto RemoteIdOrErr = - Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) { - auto &RemoteId = *RemoteIdOrErr; - - // If autonegotiation indicates that the remote end doesn't support this - // function, return an unknown function error. - if (RemoteId == getInvalidFunctionId()) - return orcError(OrcErrorCode::UnknownRPCFunction); - - // Autonegotiation succeeded and returned a valid id. Update the map and - // return the id. - RemoteFunctionIds[Func::getPrototype()] = RemoteId; - return RemoteId; - } else { - // Autonegotiation failed. Return the error. + Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) { + RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr; + if (*RemoteIdOrErr == getInvalidFunctionId()) + return make_error<CouldNotNegotiate>(Func::getPrototype()); + return *RemoteIdOrErr; + } else return RemoteIdOrErr.takeError(); - } } - // No key was available in the map and autonegotiation wasn't enabled. - // Return an unknown function error. - return orcError(OrcErrorCode::UnknownRPCFunction); + // No key was available in the map and we weren't allowed to try to + // negotiate one, so return an unknown function error. + return make_error<CouldNotNegotiate>(Func::getPrototype()); } using WrappedHandlerFn = std::function<Error(ChannelT &, SequenceNumberT)>; @@ -993,12 +1314,15 @@ protected: // Wrap the given user handler in the necessary argument-deserialization code, // result-serialization code, and call to the launch policy (if present). template <typename Func, typename HandlerT> - WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) { - return [this, Handler, Launch](ChannelT &Channel, - SequenceNumberT SeqNo) mutable -> Error { + WrappedHandlerFn wrapHandler(HandlerT Handler) { + return [this, Handler](ChannelT &Channel, + SequenceNumberT SeqNo) mutable -> Error { // Start by deserializing the arguments. - auto Args = std::make_shared< - typename detail::HandlerTraits<HandlerT>::ArgStorage>(); + using ArgsTuple = + typename detail::FunctionArgsTuple< + typename detail::HandlerTraits<HandlerT>::Type>::Type; + auto Args = std::make_shared<ArgsTuple>(); + if (auto Err = detail::HandlerTraits<typename Func::Type>::deserializeArgs( Channel, *Args)) @@ -1013,22 +1337,49 @@ protected: if (auto Err = Channel.endReceiveMessage()) return Err; - // Build the handler/responder. - auto Responder = [this, Handler, Args, &Channel, - SeqNo]() mutable -> Error { - using HTraits = detail::HandlerTraits<HandlerT>; - using FuncReturn = typename Func::ReturnType; - return detail::respond<FuncReturn>( - Channel, ResponseId, SeqNo, HTraits::unpackAndRun(Handler, *Args)); - }; - - // If there is an explicit launch policy then use it to launch the - // handler. - if (Launch) - return Launch(std::move(Responder)); - - // Otherwise run the handler on the listener thread. - return Responder(); + using HTraits = detail::HandlerTraits<HandlerT>; + using FuncReturn = typename Func::ReturnType; + return detail::respond<FuncReturn>(Channel, ResponseId, SeqNo, + HTraits::unpackAndRun(Handler, *Args)); + }; + } + + // Wrap the given user handler in the necessary argument-deserialization code, + // result-serialization code, and call to the launch policy (if present). + template <typename Func, typename HandlerT> + WrappedHandlerFn wrapAsyncHandler(HandlerT Handler) { + return [this, Handler](ChannelT &Channel, + SequenceNumberT SeqNo) mutable -> Error { + // Start by deserializing the arguments. + using AHTraits = detail::AsyncHandlerTraits< + typename detail::HandlerTraits<HandlerT>::Type>; + using ArgsTuple = + typename detail::FunctionArgsTuple<typename AHTraits::Type>::Type; + auto Args = std::make_shared<ArgsTuple>(); + + if (auto Err = + detail::HandlerTraits<typename Func::Type>::deserializeArgs( + Channel, *Args)) + return Err; + + // 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)Args; + + // End receieve message, unlocking the channel for reading. + if (auto Err = Channel.endReceiveMessage()) + return Err; + + using HTraits = detail::HandlerTraits<HandlerT>; + using FuncReturn = typename Func::ReturnType; + auto Responder = + [this, SeqNo](typename AHTraits::ResultType RetVal) -> Error { + return detail::respond<FuncReturn>(C, ResponseId, SeqNo, + std::move(RetVal)); + }; + + return HTraits::unpackAndRunAsync(Handler, Responder, *Args); }; } @@ -1068,66 +1419,31 @@ public: MultiThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation) : BaseClass(C, LazyAutoNegotiation) {} - /// The LaunchPolicy type allows a launch policy to be specified when adding - /// a function handler. See addHandler. - using LaunchPolicy = typename BaseClass::LaunchPolicy; - /// Add a handler for the given RPC function. /// This installs the given handler functor for the given RPC Function, and /// makes the RPC function available for negotiation/calling from the remote. - /// - /// The optional LaunchPolicy argument can be used to control how the handler - /// is run when called: - /// - /// * If no LaunchPolicy is given, the handler code will be run on the RPC - /// handler thread that is reading from the channel. This handler cannot - /// make blocking RPC calls (since it would be blocking the thread used to - /// get the result), but can make non-blocking calls. - /// - /// * If a LaunchPolicy is given, the user's handler will be wrapped in a - /// call to serialize and send the result, and the resulting functor (with - /// type 'Error()' will be passed to the LaunchPolicy. The user can then - /// choose to add the wrapped handler to a work queue, spawn a new thread, - /// or anything else. template <typename Func, typename HandlerT> - void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) { - return this->template addHandlerImpl<Func>(std::move(Handler), - std::move(Launch)); + void addHandler(HandlerT Handler) { + return this->template addHandlerImpl<Func>(std::move(Handler)); } /// Add a class-method as a handler. template <typename Func, typename ClassT, typename RetT, typename... ArgTs> - void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...), - LaunchPolicy Launch = LaunchPolicy()) { + void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) { addHandler<Func>( - detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method), - Launch); + detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method)); } - /// Negotiate a function id for Func with the other end of the channel. - template <typename Func> Error negotiateFunction(bool Retry = false) { - using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate; - - // Check if we already have a function id... - auto I = this->RemoteFunctionIds.find(Func::getPrototype()); - if (I != this->RemoteFunctionIds.end()) { - // If it's valid there's nothing left to do. - if (I->second != this->getInvalidFunctionId()) - return Error::success(); - // If it's invalid and we can't re-attempt negotiation, throw an error. - if (!Retry) - return orcError(OrcErrorCode::UnknownRPCFunction); - } + template <typename Func, typename HandlerT> + void addAsyncHandler(HandlerT Handler) { + return this->template addAsyncHandlerImpl<Func>(std::move(Handler)); + } - // We don't have a function id for Func yet, call the remote to try to - // negotiate one. - if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) { - this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr; - if (*RemoteIdOrErr == this->getInvalidFunctionId()) - return orcError(OrcErrorCode::UnknownRPCFunction); - return Error::success(); - } else - return RemoteIdOrErr.takeError(); + /// Add a class-method as a handler. + template <typename Func, typename ClassT, typename RetT, typename... ArgTs> + void addAsyncHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) { + addAsyncHandler<Func>( + detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method)); } /// Return type for non-blocking call primitives. @@ -1159,7 +1475,6 @@ public: return Error::success(); }, Args...)) { - this->abandonPendingResponses(); RTraits::consumeAbandoned(FutureResult.get()); return std::move(Err); } @@ -1191,15 +1506,9 @@ public: typename AltRetT = typename Func::ReturnType> typename detail::ResultTraits<AltRetT>::ErrorReturnType callB(const ArgTs &... Args) { - if (auto FutureResOrErr = callNB<Func>(Args...)) { - if (auto Err = this->C.send()) { - this->abandonPendingResponses(); - detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned( - std::move(FutureResOrErr->get())); - return std::move(Err); - } + if (auto FutureResOrErr = callNB<Func>(Args...)) return FutureResOrErr->get(); - } else + else return FutureResOrErr.takeError(); } @@ -1224,16 +1533,13 @@ private: SingleThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>, ChannelT, FunctionIdT, SequenceNumberT>; - using LaunchPolicy = typename BaseClass::LaunchPolicy; - public: SingleThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation) : BaseClass(C, LazyAutoNegotiation) {} template <typename Func, typename HandlerT> void addHandler(HandlerT Handler) { - return this->template addHandlerImpl<Func>(std::move(Handler), - LaunchPolicy()); + return this->template addHandlerImpl<Func>(std::move(Handler)); } template <typename Func, typename ClassT, typename RetT, typename... ArgTs> @@ -1242,30 +1548,16 @@ public: detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method)); } - /// Negotiate a function id for Func with the other end of the channel. - template <typename Func> Error negotiateFunction(bool Retry = false) { - using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate; - - // Check if we already have a function id... - auto I = this->RemoteFunctionIds.find(Func::getPrototype()); - if (I != this->RemoteFunctionIds.end()) { - // If it's valid there's nothing left to do. - if (I->second != this->getInvalidFunctionId()) - return Error::success(); - // If it's invalid and we can't re-attempt negotiation, throw an error. - if (!Retry) - return orcError(OrcErrorCode::UnknownRPCFunction); - } + template <typename Func, typename HandlerT> + void addAsyncHandler(HandlerT Handler) { + return this->template addAsyncHandlerImpl<Func>(std::move(Handler)); + } - // We don't have a function id for Func yet, call the remote to try to - // negotiate one. - if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) { - this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr; - if (*RemoteIdOrErr == this->getInvalidFunctionId()) - return orcError(OrcErrorCode::UnknownRPCFunction); - return Error::success(); - } else - return RemoteIdOrErr.takeError(); + /// Add a class-method as a handler. + template <typename Func, typename ClassT, typename RetT, typename... ArgTs> + void addAsyncHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) { + addAsyncHandler<Func>( + detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method)); } template <typename Func, typename... ArgTs, @@ -1287,7 +1579,6 @@ public: return Error::success(); }, Args...)) { - this->abandonPendingResponses(); detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned( std::move(Result)); return std::move(Err); @@ -1295,7 +1586,6 @@ public: while (!ReceivedResponse) { if (auto Err = this->handleOne()) { - this->abandonPendingResponses(); detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned( std::move(Result)); return std::move(Err); @@ -1306,24 +1596,40 @@ public: } }; +/// Asynchronous dispatch for a function on an RPC endpoint. +template <typename RPCClass, typename Func> +class RPCAsyncDispatch { +public: + RPCAsyncDispatch(RPCClass &Endpoint) : Endpoint(Endpoint) {} + + template <typename HandlerT, typename... ArgTs> + Error operator()(HandlerT Handler, const ArgTs &... Args) const { + return Endpoint.template appendCallAsync<Func>(std::move(Handler), Args...); + } + +private: + RPCClass &Endpoint; +}; + +/// Construct an asynchronous dispatcher from an RPC endpoint and a Func. +template <typename Func, typename RPCEndpointT> +RPCAsyncDispatch<RPCEndpointT, Func> rpcAsyncDispatch(RPCEndpointT &Endpoint) { + return RPCAsyncDispatch<RPCEndpointT, Func>(Endpoint); +} + /// \brief Allows a set of asynchrounous calls to be dispatched, and then /// waited on as a group. -template <typename RPCClass> class ParallelCallGroup { +class ParallelCallGroup { public: - /// \brief Construct a parallel call group for the given RPC. - ParallelCallGroup(RPCClass &RPC) : RPC(RPC), NumOutstandingCalls(0) {} - + ParallelCallGroup() = default; ParallelCallGroup(const ParallelCallGroup &) = delete; ParallelCallGroup &operator=(const ParallelCallGroup &) = delete; /// \brief Make as asynchronous call. - /// - /// Does not issue a send call to the RPC's channel. The channel may use this - /// to batch up subsequent calls. A send will automatically be sent when wait - /// is called. - template <typename Func, typename HandlerT, typename... ArgTs> - Error appendCall(HandlerT Handler, const ArgTs &... Args) { + template <typename AsyncDispatcher, typename HandlerT, typename... ArgTs> + Error call(const AsyncDispatcher &AsyncDispatch, HandlerT Handler, + const ArgTs &... Args) { // Increment the count of outstanding calls. This has to happen before // we invoke the call, as the handler may (depending on scheduling) // be run immediately on another thread, and we don't want the decrement @@ -1346,38 +1652,21 @@ public: return Err; }; - return RPC.template appendCallAsync<Func>(std::move(WrappedHandler), - Args...); - } - - /// \brief Make an asynchronous call. - /// - /// The same as appendCall, but also calls send on the channel immediately. - /// Prefer appendCall if you are about to issue a "wait" call shortly, as - /// this may allow the channel to better batch the calls. - template <typename Func, typename HandlerT, typename... ArgTs> - Error call(HandlerT Handler, const ArgTs &... Args) { - if (auto Err = appendCall(std::move(Handler), Args...)) - return Err; - return RPC.sendAppendedCalls(); + return AsyncDispatch(std::move(WrappedHandler), Args...); } /// \brief Blocks until all calls have been completed and their return value /// handlers run. - Error wait() { - if (auto Err = RPC.sendAppendedCalls()) - return Err; + void wait() { std::unique_lock<std::mutex> Lock(M); while (NumOutstandingCalls > 0) CV.wait(Lock); - return Error::success(); } private: - RPCClass &RPC; std::mutex M; std::condition_variable CV; - uint32_t NumOutstandingCalls; + uint32_t NumOutstandingCalls = 0; }; /// @brief Convenience class for grouping RPC Functions into APIs that can be diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h index 0588d2228598..babcc7f26aab 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h @@ -1,4 +1,4 @@ -//===- ObjectLinkingLayer.h - Add object files to a JIT process -*- C++ -*-===// +//===-- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// Contains the definition for the object layer of the JIT. +// Contains the definition for an RTDyld-based, in-process object linking layer. // //===----------------------------------------------------------------------===// -#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H -#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H +#ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" @@ -35,7 +35,7 @@ namespace llvm { namespace orc { -class ObjectLinkingLayerBase { +class RTDyldObjectLinkingLayerBase { protected: /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. /// @@ -87,7 +87,7 @@ public: class DoNothingOnNotifyLoaded { public: template <typename ObjSetT, typename LoadResult> - void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &, + void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &, const LoadResult &) {} }; @@ -98,7 +98,7 @@ public: /// symbols queried. All objects added to this layer can see each other's /// symbols. template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded> -class ObjectLinkingLayer : public ObjectLinkingLayerBase { +class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { public: /// @brief Functor for receiving finalization notifications. typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor; @@ -227,7 +227,7 @@ public: /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, /// and NotifyFinalized functors. - ObjectLinkingLayer( + RTDyldObjectLinkingLayer( NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) : NotifyLoaded(std::move(NotifyLoaded)), @@ -359,4 +359,4 @@ private: } // end namespace orc } // end namespace llvm -#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H +#endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/RawByteChannel.h b/include/llvm/ExecutionEngine/Orc/RawByteChannel.h index 3b6c84eb1965..52a546f7c6eb 100644 --- a/include/llvm/ExecutionEngine/Orc/RawByteChannel.h +++ b/include/llvm/ExecutionEngine/Orc/RawByteChannel.h @@ -48,7 +48,11 @@ public: template <typename FunctionIdT, typename SequenceIdT> Error startSendMessage(const FunctionIdT &FnId, const SequenceIdT &SeqNo) { writeLock.lock(); - return serializeSeq(*this, FnId, SeqNo); + if (auto Err = serializeSeq(*this, FnId, SeqNo)) { + writeLock.unlock(); + return Err; + } + return Error::success(); } /// Notify the channel that we're ending a message send. @@ -63,7 +67,11 @@ public: template <typename FunctionIdT, typename SequenceNumberT> Error startReceiveMessage(FunctionIdT &FnId, SequenceNumberT &SeqNo) { readLock.lock(); - return deserializeSeq(*this, FnId, SeqNo); + if (auto Err = deserializeSeq(*this, FnId, SeqNo)) { + readLock.unlock(); + return Err; + } + return Error::success(); } /// Notify the channel that we're ending a message receive. @@ -113,11 +121,19 @@ class SerializationTraits<ChannelT, bool, bool, RawByteChannel, ChannelT>::value>::type> { public: static Error serialize(ChannelT &C, bool V) { - return C.appendBytes(reinterpret_cast<const char *>(&V), 1); + uint8_t Tmp = V ? 1 : 0; + if (auto Err = + C.appendBytes(reinterpret_cast<const char *>(&Tmp), 1)) + return Err; + return Error::success(); } static Error deserialize(ChannelT &C, bool &V) { - return C.readBytes(reinterpret_cast<char *>(&V), 1); + uint8_t Tmp = 0; + if (auto Err = C.readBytes(reinterpret_cast<char *>(&Tmp), 1)) + return Err; + V = Tmp != 0; + return Error::success(); } }; @@ -134,10 +150,12 @@ public: } }; -template <typename ChannelT> -class SerializationTraits<ChannelT, std::string, const char *, - typename std::enable_if<std::is_base_of< - RawByteChannel, ChannelT>::value>::type> { +template <typename ChannelT, typename T> +class SerializationTraits<ChannelT, std::string, T, + typename std::enable_if< + std::is_base_of<RawByteChannel, ChannelT>::value && + (std::is_same<T, const char*>::value || + std::is_same<T, char*>::value)>::type> { public: static Error serialize(RawByteChannel &C, const char *S) { return SerializationTraits<ChannelT, std::string, StringRef>::serialize(C, diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h index d8b280a66f18..6fc1dd2f285a 100644 --- a/include/llvm/IR/Argument.h +++ b/include/llvm/IR/Argument.h @@ -21,127 +21,110 @@ namespace llvm { -template <typename NodeTy> class SymbolTableListTraits; - -/// \brief LLVM Argument representation -/// /// This class represents an incoming formal argument to a Function. A formal /// argument, since it is ``formal'', does not contain an actual value but /// instead represents the type, argument number, and attributes of an argument /// for a specific function. When used in the body of said function, the /// argument of course represents the value of the actual argument that the /// function was called with. -class Argument : public Value, public ilist_node<Argument> { +class Argument : public Value { virtual void anchor(); Function *Parent; + unsigned ArgNo; - friend class SymbolTableListTraits<Argument>; + friend class Function; void setParent(Function *parent); public: - /// \brief Constructor. - /// - /// If \p F is specified, the argument is inserted at the end of the argument - /// list for \p F. - explicit Argument(Type *Ty, const Twine &Name = "", Function *F = nullptr); + /// Argument constructor. + explicit Argument(Type *Ty, const Twine &Name = "", Function *F = nullptr, + unsigned ArgNo = 0); inline const Function *getParent() const { return Parent; } inline Function *getParent() { return Parent; } - /// \brief Return the index of this formal argument in its containing - /// function. + /// Return the index of this formal argument in its containing function. /// /// For example in "void foo(int a, float b)" a is 0 and b is 1. - unsigned getArgNo() const; + unsigned getArgNo() const { + assert(Parent && "can't get number of unparented arg"); + return ArgNo; + } - /// \brief Return true if this argument has the nonnull attribute on it in - /// its containing function. Also returns true if at least one byte is known - /// to be dereferenceable and the pointer is in addrspace(0). + /// Return true if this argument has the nonnull attribute. Also returns true + /// if at least one byte is known to be dereferenceable and the pointer is in + /// addrspace(0). bool hasNonNullAttr() const; - /// \brief If this argument has the dereferenceable attribute on it in its - /// containing function, return the number of bytes known to be - /// dereferenceable. Otherwise, zero is returned. + /// If this argument has the dereferenceable attribute, return the number of + /// bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableBytes() const; - /// \brief If this argument has the dereferenceable_or_null attribute on - /// it in its containing function, return the number of bytes known to be - /// dereferenceable. Otherwise, zero is returned. + /// If this argument has the dereferenceable_or_null attribute, return the + /// number of bytes known to be dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableOrNullBytes() const; - /// \brief Return true if this argument has the byval attribute on it in its - /// containing function. + /// Return true if this argument has the byval attribute. bool hasByValAttr() const; - /// \brief Return true if this argument has the swiftself attribute. + /// Return true if this argument has the swiftself attribute. bool hasSwiftSelfAttr() const; - /// \brief Return true if this argument has the swifterror attribute. + /// Return true if this argument has the swifterror attribute. bool hasSwiftErrorAttr() const; - /// \brief Return true if this argument has the byval attribute or inalloca - /// attribute on it in its containing function. These attributes both - /// represent arguments being passed by value. + /// Return true if this argument has the byval attribute or inalloca + /// attribute. These attributes represent arguments being passed by value. bool hasByValOrInAllocaAttr() const; - /// \brief If this is a byval or inalloca argument, return its alignment. + /// If this is a byval or inalloca argument, return its alignment. unsigned getParamAlignment() const; - /// \brief Return true if this argument has the nest attribute on it in its - /// containing function. + /// Return true if this argument has the nest attribute. bool hasNestAttr() const; - /// \brief Return true if this argument has the noalias attribute on it in its - /// containing function. + /// Return true if this argument has the noalias attribute. bool hasNoAliasAttr() const; - /// \brief Return true if this argument has the nocapture attribute on it in - /// its containing function. + /// Return true if this argument has the nocapture attribute. bool hasNoCaptureAttr() const; - /// \brief Return true if this argument has the sret attribute on it in its - /// containing function. + /// Return true if this argument has the sret attribute. bool hasStructRetAttr() const; - /// \brief Return true if this argument has the returned attribute on it in - /// its containing function. + /// Return true if this argument has the returned attribute. bool hasReturnedAttr() const; - /// \brief Return true if this argument has the readonly or readnone attribute - /// on it in its containing function. + /// Return true if this argument has the readonly or readnone attribute. bool onlyReadsMemory() const; - /// \brief Return true if this argument has the inalloca attribute on it in - /// its containing function. + /// Return true if this argument has the inalloca attribute. bool hasInAllocaAttr() const; - /// \brief Return true if this argument has the zext attribute on it in its - /// containing function. + /// Return true if this argument has the zext attribute. bool hasZExtAttr() const; - /// \brief Return true if this argument has the sext attribute on it in its - /// containing function. + /// Return true if this argument has the sext attribute. bool hasSExtAttr() const; - /// \brief Add a Attribute to an argument. - void addAttr(AttributeSet AS); + /// Add attributes to an argument. + void addAttr(AttributeList AS); void addAttr(Attribute::AttrKind Kind) { - addAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + addAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind)); } - /// \brief Remove a Attribute from an argument. - void removeAttr(AttributeSet AS); + /// Remove attributes from an argument. + void removeAttr(AttributeList AS); void removeAttr(Attribute::AttrKind Kind) { - removeAttr(AttributeSet::get(getContext(), getArgNo() + 1, Kind)); + removeAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind)); } - /// \brief Checks if an argument has a given attribute. + /// Check if an argument has a given attribute. bool hasAttribute(Attribute::AttrKind Kind) const; - /// \brief Method for support type inquiry through isa, cast, and - /// dyn_cast. + /// Method for support type inquiry through isa, cast, and dyn_cast. static inline bool classof(const Value *V) { return V->getValueID() == ArgumentVal; } diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 15783858dd32..121f57a433ac 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -1,4 +1,4 @@ -//===-- llvm/Attributes.h - Container for Attributes ------------*- C++ -*-===// +//===- llvm/Attributes.h - Container for Attributes -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,22 +18,24 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" -#include "llvm/Support/Compiler.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm-c/Types.h" #include <bitset> #include <cassert> +#include <cstdint> #include <map> #include <string> +#include <utility> namespace llvm { class AttrBuilder; class AttributeImpl; -class AttributeSetImpl; +class AttributeListImpl; class AttributeSetNode; -class Constant; template<typename T> struct DenseMapInfo; class Function; class LLVMContext; @@ -73,11 +75,12 @@ public: }; private: - AttributeImpl *pImpl; + AttributeImpl *pImpl = nullptr; + Attribute(AttributeImpl *A) : pImpl(A) {} public: - Attribute() : pImpl(nullptr) {} + Attribute() = default; //===--------------------------------------------------------------------===// // Attribute Construction @@ -194,13 +197,91 @@ inline Attribute unwrap(LLVMAttributeRef Attr) { //===----------------------------------------------------------------------===// /// \class +/// This class holds the attributes for a particular argument, parameter, +/// function, or return value. It is an immutable value type that is cheap to +/// copy. Adding and removing enum attributes is intended to be fast, but adding +/// and removing string or integer attributes involves a FoldingSet lookup. +class AttributeSet { + // TODO: Extract AvailableAttrs from AttributeSetNode and store them here. + // This will allow an efficient implementation of addAttribute and + // removeAttribute for enum attrs. + + /// Private implementation pointer. + AttributeSetNode *SetNode = nullptr; + + friend AttributeListImpl; + template <typename Ty> friend struct DenseMapInfo; + +private: + explicit AttributeSet(AttributeSetNode *ASN) : SetNode(ASN) {} + +public: + /// AttributeSet is a trivially copyable value type. + AttributeSet() = default; + AttributeSet(const AttributeSet &) = default; + ~AttributeSet() = default; + + static AttributeSet get(LLVMContext &C, const AttrBuilder &B); + static AttributeSet get(LLVMContext &C, ArrayRef<Attribute> Attrs); + + bool operator==(const AttributeSet &O) { return SetNode == O.SetNode; } + bool operator!=(const AttributeSet &O) { return !(*this == O); } + + unsigned getNumAttributes() const; + + bool hasAttributes() const { return SetNode != nullptr; } + + bool hasAttribute(Attribute::AttrKind Kind) const; + bool hasAttribute(StringRef Kind) const; + + Attribute getAttribute(Attribute::AttrKind Kind) const; + Attribute getAttribute(StringRef Kind) const; + + unsigned getAlignment() const; + unsigned getStackAlignment() const; + uint64_t getDereferenceableBytes() const; + uint64_t getDereferenceableOrNullBytes() const; + std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; + std::string getAsString(bool InAttrGrp = false) const; + + typedef const Attribute *iterator; + iterator begin() const; + iterator end() const; +}; + +//===----------------------------------------------------------------------===// +/// \class +/// \brief Provide DenseMapInfo for AttributeSet. +template <> struct DenseMapInfo<AttributeSet> { + static inline AttributeSet getEmptyKey() { + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<void *>::NumLowBitsAvailable; + return AttributeSet(reinterpret_cast<AttributeSetNode *>(Val)); + } + + static inline AttributeSet getTombstoneKey() { + uintptr_t Val = static_cast<uintptr_t>(-2); + Val <<= PointerLikeTypeTraits<void *>::NumLowBitsAvailable; + return AttributeSet(reinterpret_cast<AttributeSetNode *>(Val)); + } + + static unsigned getHashValue(AttributeSet AS) { + return (unsigned((uintptr_t)AS.SetNode) >> 4) ^ + (unsigned((uintptr_t)AS.SetNode) >> 9); + } + + static bool isEqual(AttributeSet LHS, AttributeSet RHS) { return LHS == RHS; } +}; + +//===----------------------------------------------------------------------===// +/// \class /// \brief This class holds the attributes for a function, its return value, and /// its parameters. You access the attributes for each of them via an index into -/// the AttributeSet object. The function attributes are at index -/// `AttributeSet::FunctionIndex', the return value is at index -/// `AttributeSet::ReturnIndex', and the attributes for the parameters start at +/// the AttributeList object. The function attributes are at index +/// `AttributeList::FunctionIndex', the return value is at index +/// `AttributeList::ReturnIndex', and the attributes for the parameters start at /// index `1'. -class AttributeSet { +class AttributeList { public: enum AttrIndex : unsigned { ReturnIndex = 0U, @@ -209,115 +290,137 @@ public: private: friend class AttrBuilder; - friend class AttributeSetImpl; + friend class AttributeListImpl; + friend class AttributeSet; friend class AttributeSetNode; + template <typename Ty> friend struct DenseMapInfo; /// \brief The attributes that we are managing. This can be null to represent /// the empty attributes list. - AttributeSetImpl *pImpl; - - /// \brief The attributes for the specified index are returned. - AttributeSetNode *getAttributes(unsigned Index) const; - - /// \brief Create an AttributeSet with the specified parameters in it. - static AttributeSet get(LLVMContext &C, - ArrayRef<std::pair<unsigned, Attribute> > Attrs); - static AttributeSet get(LLVMContext &C, - ArrayRef<std::pair<unsigned, - AttributeSetNode*> > Attrs); + AttributeListImpl *pImpl = nullptr; - static AttributeSet getImpl(LLVMContext &C, - ArrayRef<std::pair<unsigned, - AttributeSetNode*> > Attrs); +public: + /// \brief Create an AttributeList with the specified parameters in it. + static AttributeList get(LLVMContext &C, + ArrayRef<std::pair<unsigned, Attribute>> Attrs); + static AttributeList + get(LLVMContext &C, ArrayRef<std::pair<unsigned, AttributeSet>> Attrs); + + /// \brief Create an AttributeList from attribute sets for a function, its + /// return value, and all of its arguments. + static AttributeList get(LLVMContext &C, AttributeSet FnAttrs, + AttributeSet RetAttrs, + ArrayRef<AttributeSet> ArgAttrs); + + static AttributeList + getImpl(LLVMContext &C, + ArrayRef<std::pair<unsigned, AttributeSet>> Attrs); - explicit AttributeSet(AttributeSetImpl *LI) : pImpl(LI) {} +private: + explicit AttributeList(AttributeListImpl *LI) : pImpl(LI) {} public: - AttributeSet() : pImpl(nullptr) {} + AttributeList() = default; //===--------------------------------------------------------------------===// - // AttributeSet Construction and Mutation + // AttributeList Construction and Mutation //===--------------------------------------------------------------------===// - /// \brief Return an AttributeSet with the specified parameters in it. - static AttributeSet get(LLVMContext &C, ArrayRef<AttributeSet> Attrs); - static AttributeSet get(LLVMContext &C, unsigned Index, - ArrayRef<Attribute::AttrKind> Kinds); - static AttributeSet get(LLVMContext &C, unsigned Index, - ArrayRef<StringRef> Kind); - static AttributeSet get(LLVMContext &C, unsigned Index, const AttrBuilder &B); + /// \brief Return an AttributeList with the specified parameters in it. + static AttributeList get(LLVMContext &C, ArrayRef<AttributeList> Attrs); + static AttributeList get(LLVMContext &C, unsigned Index, + ArrayRef<Attribute::AttrKind> Kinds); + static AttributeList get(LLVMContext &C, unsigned Index, + ArrayRef<StringRef> Kind); + static AttributeList get(LLVMContext &C, unsigned Index, + const AttrBuilder &B); /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Kind) const; + AttributeList addAttribute(LLVMContext &C, unsigned Index, + Attribute::AttrKind Kind) const; /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, - StringRef Value = StringRef()) const; + AttributeList addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, + StringRef Value = StringRef()) const; /// Add an attribute to the attribute set at the given indices. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, ArrayRef<unsigned> Indices, - Attribute A) const; + AttributeList addAttribute(LLVMContext &C, ArrayRef<unsigned> Indices, + Attribute A) const; /// \brief Add attributes to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttributes(LLVMContext &C, unsigned Index, - AttributeSet Attrs) const; + AttributeList addAttributes(LLVMContext &C, unsigned Index, + AttributeList Attrs) const; + + AttributeList addAttributes(LLVMContext &C, unsigned Index, + AttributeSet AS) const; + + AttributeList addAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &B) const; /// \brief Remove the specified attribute at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Kind) const; + AttributeList removeAttribute(LLVMContext &C, unsigned Index, + Attribute::AttrKind Kind) const; /// \brief Remove the specified attribute at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - StringRef Kind) const; + AttributeList removeAttribute(LLVMContext &C, unsigned Index, + StringRef Kind) const; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttributes(LLVMContext &C, unsigned Index, - AttributeSet Attrs) const; + AttributeList removeAttributes(LLVMContext &C, unsigned Index, + AttributeList Attrs) const; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the /// new list. - AttributeSet removeAttributes(LLVMContext &C, unsigned Index, - const AttrBuilder &Attrs) const; + AttributeList removeAttributes(LLVMContext &C, unsigned Index, + const AttrBuilder &Attrs) const; + + /// \brief Remove all attributes at the specified index from this + /// attribute list. Because attribute lists are immutable, this returns the + /// new list. + AttributeList removeAttributes(LLVMContext &C, unsigned Index) const; /// \brief Add the dereferenceable attribute to the attribute set at the given /// index. Because attribute sets are immutable, this returns a new set. - AttributeSet addDereferenceableAttr(LLVMContext &C, unsigned Index, - uint64_t Bytes) const; + AttributeList addDereferenceableAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; /// \brief Add the dereferenceable_or_null attribute to the attribute set at /// the given index. Because attribute sets are immutable, this returns a new /// set. - AttributeSet addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index, - uint64_t Bytes) const; + AttributeList addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; /// Add the allocsize attribute to the attribute set at the given index. /// Because attribute sets are immutable, this returns a new set. - AttributeSet addAllocSizeAttr(LLVMContext &C, unsigned Index, - unsigned ElemSizeArg, - const Optional<unsigned> &NumElemsArg); + AttributeList addAllocSizeAttr(LLVMContext &C, unsigned Index, + unsigned ElemSizeArg, + const Optional<unsigned> &NumElemsArg); //===--------------------------------------------------------------------===// - // AttributeSet Accessors + // AttributeList Accessors //===--------------------------------------------------------------------===// /// \brief Retrieve the LLVM context. LLVMContext &getContext() const; /// \brief The attributes for the specified index are returned. - AttributeSet getParamAttributes(unsigned Index) const; + AttributeSet getAttributes(unsigned Index) const; + + /// \brief The attributes for the argument or parameter at the given index are + /// returned. + AttributeSet getParamAttributes(unsigned ArgNo) const; /// \brief The attributes for the ret value are returned. AttributeSet getRetAttributes() const; @@ -334,14 +437,17 @@ public: /// \brief Return true if attribute exists at the given index. bool hasAttributes(unsigned Index) const; - /// \brief Equivalent to hasAttribute(AttributeSet::FunctionIndex, Kind) but + /// \brief Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but /// may be faster. bool hasFnAttribute(Attribute::AttrKind Kind) const; - /// \brief Equivalent to hasAttribute(AttributeSet::FunctionIndex, Kind) but + /// \brief Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but /// may be faster. bool hasFnAttribute(StringRef Kind) const; + /// \brief Equivalent to hasAttribute(ArgNo + 1, Kind). + bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const; + /// \brief Return true if the specified attribute is set for at least one /// parameter or for the return value. If Index is not nullptr, the index /// of a parameter with the specified attribute is provided. @@ -380,15 +486,11 @@ public: iterator end(unsigned Slot) const; /// operator==/!= - Provide equality predicates. - bool operator==(const AttributeSet &RHS) const { - return pImpl == RHS.pImpl; - } - bool operator!=(const AttributeSet &RHS) const { - return pImpl != RHS.pImpl; - } + bool operator==(const AttributeList &RHS) const { return pImpl == RHS.pImpl; } + bool operator!=(const AttributeList &RHS) const { return pImpl != RHS.pImpl; } //===--------------------------------------------------------------------===// - // AttributeSet Introspection + // AttributeList Introspection //===--------------------------------------------------------------------===// /// \brief Return a raw pointer that uniquely identifies this attribute list. @@ -410,30 +512,35 @@ public: unsigned getSlotIndex(unsigned Slot) const; /// \brief Return the attributes at the given slot. - AttributeSet getSlotAttributes(unsigned Slot) const; + AttributeList getSlotAttributes(unsigned Slot) const; void dump() const; }; //===----------------------------------------------------------------------===// /// \class -/// \brief Provide DenseMapInfo for AttributeSet. -template<> struct DenseMapInfo<AttributeSet> { - static inline AttributeSet getEmptyKey() { +/// \brief Provide DenseMapInfo for AttributeList. +template <> struct DenseMapInfo<AttributeList> { + static inline AttributeList getEmptyKey() { uintptr_t Val = static_cast<uintptr_t>(-1); Val <<= PointerLikeTypeTraits<void*>::NumLowBitsAvailable; - return AttributeSet(reinterpret_cast<AttributeSetImpl*>(Val)); + return AttributeList(reinterpret_cast<AttributeListImpl *>(Val)); } - static inline AttributeSet getTombstoneKey() { + + static inline AttributeList getTombstoneKey() { uintptr_t Val = static_cast<uintptr_t>(-2); Val <<= PointerLikeTypeTraits<void*>::NumLowBitsAvailable; - return AttributeSet(reinterpret_cast<AttributeSetImpl*>(Val)); + return AttributeList(reinterpret_cast<AttributeListImpl *>(Val)); } - static unsigned getHashValue(AttributeSet AS) { + + static unsigned getHashValue(AttributeList AS) { return (unsigned((uintptr_t)AS.pImpl) >> 4) ^ (unsigned((uintptr_t)AS.pImpl) >> 9); } - static bool isEqual(AttributeSet LHS, AttributeSet RHS) { return LHS == RHS; } + + static bool isEqual(AttributeList LHS, AttributeList RHS) { + return LHS == RHS; + } }; //===----------------------------------------------------------------------===// @@ -445,22 +552,19 @@ template<> struct DenseMapInfo<AttributeSet> { class AttrBuilder { std::bitset<Attribute::EndAttrKinds> Attrs; std::map<std::string, std::string> TargetDepAttrs; - uint64_t Alignment; - uint64_t StackAlignment; - uint64_t DerefBytes; - uint64_t DerefOrNullBytes; - uint64_t AllocSizeArgs; + uint64_t Alignment = 0; + uint64_t StackAlignment = 0; + uint64_t DerefBytes = 0; + uint64_t DerefOrNullBytes = 0; + uint64_t AllocSizeArgs = 0; public: - AttrBuilder() - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0), AllocSizeArgs(0) {} - AttrBuilder(const Attribute &A) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0), AllocSizeArgs(0) { + AttrBuilder() = default; + AttrBuilder(const Attribute &A) { addAttribute(A); } - AttrBuilder(AttributeSet AS, unsigned Idx); + AttrBuilder(AttributeList AS, unsigned Idx); + AttrBuilder(AttributeSet AS); void clear(); @@ -477,7 +581,7 @@ public: AttrBuilder &removeAttribute(Attribute::AttrKind Val); /// \brief Remove the attributes from the builder. - AttrBuilder &removeAttributes(AttributeSet A, uint64_t Index); + AttrBuilder &removeAttributes(AttributeList A, uint64_t WithoutIndex); /// \brief Remove the target-dependent attribute to the builder. AttrBuilder &removeAttribute(StringRef A); @@ -507,7 +611,7 @@ public: /// \brief Return true if the builder has any attribute that's in the /// specified attribute. - bool hasAttributes(AttributeSet A, uint64_t Index) const; + bool hasAttributes(AttributeList A, uint64_t Index) const; /// \brief Return true if the builder has an alignment attribute. bool hasAlignmentAttr() const; @@ -562,8 +666,8 @@ public: typedef std::pair<std::string, std::string> td_type; typedef std::map<std::string, std::string>::iterator td_iterator; typedef std::map<std::string, std::string>::const_iterator td_const_iterator; - typedef llvm::iterator_range<td_iterator> td_range; - typedef llvm::iterator_range<td_const_iterator> td_const_range; + typedef iterator_range<td_iterator> td_range; + typedef iterator_range<td_const_iterator> td_const_range; td_iterator td_begin() { return TargetDepAttrs.begin(); } td_iterator td_end() { return TargetDepAttrs.end(); } @@ -600,4 +704,4 @@ void mergeAttributesForInlining(Function &Caller, const Function &Callee); } // end llvm namespace -#endif +#endif // LLVM_IR_ATTRIBUTES_H diff --git a/include/llvm/IR/BasicBlock.h b/include/llvm/IR/BasicBlock.h index 93dbd573ee16..bd210e1abf31 100644 --- a/include/llvm/IR/BasicBlock.h +++ b/include/llvm/IR/BasicBlock.h @@ -105,27 +105,35 @@ public: /// /// Note: this is undefined behavior if the block does not have a parent. const Module *getModule() const; - Module *getModule(); + Module *getModule() { + return const_cast<Module *>( + static_cast<const BasicBlock *>(this)->getModule()); + } /// \brief Returns the terminator instruction if the block is well formed or /// null if the block is not well formed. - TerminatorInst *getTerminator(); - const TerminatorInst *getTerminator() const; + const TerminatorInst *getTerminator() const LLVM_READONLY; + TerminatorInst *getTerminator() { + return const_cast<TerminatorInst *>( + static_cast<const BasicBlock *>(this)->getTerminator()); + } /// \brief Returns the call instruction calling @llvm.experimental.deoptimize /// prior to the terminating return instruction of this basic block, if such a /// call is present. Otherwise, returns null. - CallInst *getTerminatingDeoptimizeCall(); - const CallInst *getTerminatingDeoptimizeCall() const { - return const_cast<BasicBlock *>(this)->getTerminatingDeoptimizeCall(); + const CallInst *getTerminatingDeoptimizeCall() const; + CallInst *getTerminatingDeoptimizeCall() { + return const_cast<CallInst *>( + static_cast<const BasicBlock *>(this)->getTerminatingDeoptimizeCall()); } /// \brief Returns the call instruction marked 'musttail' prior to the /// terminating return instruction of this basic block, if such a call is /// present. Otherwise, returns null. - CallInst *getTerminatingMustTailCall(); - const CallInst *getTerminatingMustTailCall() const { - return const_cast<BasicBlock *>(this)->getTerminatingMustTailCall(); + const CallInst *getTerminatingMustTailCall() const; + CallInst *getTerminatingMustTailCall() { + return const_cast<CallInst *>( + static_cast<const BasicBlock *>(this)->getTerminatingMustTailCall()); } /// \brief Returns a pointer to the first instruction in this block that is @@ -134,32 +142,36 @@ public: /// When adding instructions to the beginning of the basic block, they should /// be added before the returned value, not before the first instruction, /// which might be PHI. Returns 0 is there's no non-PHI instruction. - Instruction* getFirstNonPHI(); - const Instruction* getFirstNonPHI() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHI(); + const Instruction* getFirstNonPHI() const; + Instruction* getFirstNonPHI() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHI()); } /// \brief Returns a pointer to the first instruction in this block that is not /// a PHINode or a debug intrinsic. - Instruction* getFirstNonPHIOrDbg(); - const Instruction* getFirstNonPHIOrDbg() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbg(); + const Instruction* getFirstNonPHIOrDbg() const; + Instruction* getFirstNonPHIOrDbg() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHIOrDbg()); } /// \brief Returns a pointer to the first instruction in this block that is not /// a PHINode, a debug intrinsic, or a lifetime intrinsic. - Instruction* getFirstNonPHIOrDbgOrLifetime(); - const Instruction* getFirstNonPHIOrDbgOrLifetime() const { - return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbgOrLifetime(); + const Instruction* getFirstNonPHIOrDbgOrLifetime() const; + Instruction* getFirstNonPHIOrDbgOrLifetime() { + return const_cast<Instruction *>( + static_cast<const BasicBlock *>(this)->getFirstNonPHIOrDbgOrLifetime()); } /// \brief Returns an iterator to the first instruction in this block that is /// suitable for inserting a non-PHI instruction. /// /// In particular, it skips all PHIs and LandingPad instructions. - iterator getFirstInsertionPt(); - const_iterator getFirstInsertionPt() const { - return const_cast<BasicBlock*>(this)->getFirstInsertionPt(); + const_iterator getFirstInsertionPt() const; + iterator getFirstInsertionPt() { + return static_cast<const BasicBlock *>(this) + ->getFirstInsertionPt().getNonConst(); } /// \brief Unlink 'this' from the containing function, but do not delete it. @@ -188,9 +200,10 @@ public: /// \brief Return the predecessor of this block if it has a single predecessor /// block. Otherwise return a null pointer. - BasicBlock *getSinglePredecessor(); - const BasicBlock *getSinglePredecessor() const { - return const_cast<BasicBlock*>(this)->getSinglePredecessor(); + const BasicBlock *getSinglePredecessor() const; + BasicBlock *getSinglePredecessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getSinglePredecessor()); } /// \brief Return the predecessor of this block if it has a unique predecessor @@ -199,27 +212,30 @@ public: /// Note that unique predecessor doesn't mean single edge, there can be /// multiple edges from the unique predecessor to this block (for example a /// switch statement with multiple cases having the same destination). - BasicBlock *getUniquePredecessor(); - const BasicBlock *getUniquePredecessor() const { - return const_cast<BasicBlock*>(this)->getUniquePredecessor(); + const BasicBlock *getUniquePredecessor() const; + BasicBlock *getUniquePredecessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getUniquePredecessor()); } /// \brief Return the successor of this block if it has a single successor. /// Otherwise return a null pointer. /// /// This method is analogous to getSinglePredecessor above. - BasicBlock *getSingleSuccessor(); - const BasicBlock *getSingleSuccessor() const { - return const_cast<BasicBlock*>(this)->getSingleSuccessor(); + const BasicBlock *getSingleSuccessor() const; + BasicBlock *getSingleSuccessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getSingleSuccessor()); } /// \brief Return the successor of this block if it has a unique successor. /// Otherwise return a null pointer. /// /// This method is analogous to getUniquePredecessor above. - BasicBlock *getUniqueSuccessor(); - const BasicBlock *getUniqueSuccessor() const { - return const_cast<BasicBlock*>(this)->getUniqueSuccessor(); + const BasicBlock *getUniqueSuccessor() const; + BasicBlock *getUniqueSuccessor() { + return const_cast<BasicBlock *>( + static_cast<const BasicBlock *>(this)->getUniqueSuccessor()); } //===--------------------------------------------------------------------===// @@ -321,8 +337,11 @@ public: bool isLandingPad() const; /// \brief Return the landingpad instruction associated with the landing pad. - LandingPadInst *getLandingPadInst(); const LandingPadInst *getLandingPadInst() const; + LandingPadInst *getLandingPadInst() { + return const_cast<LandingPadInst *>( + static_cast<const BasicBlock *>(this)->getLandingPadInst()); + } private: /// \brief Increment the internal refcount of the number of BlockAddresses diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index b02c89474146..79f59557a5d6 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -65,11 +65,9 @@ protected: explicit CallSiteBase(ValTy *II) { *this = get(II); } private: - /// CallSiteBase::get - This static method is sort of like a constructor. It - /// will create an appropriate call site for a Call or Invoke instruction, but - /// it can also create a null initialized CallSiteBase object for something - /// which is NOT a call site. - /// + /// This static method is like a constructor. It will create an appropriate + /// call site for a Call or Invoke instruction, but it can also create a null + /// initialized CallSiteBase object for something which is NOT a call site. static CallSiteBase get(ValTy *V) { if (InstrTy *II = dyn_cast<InstrTy>(V)) { if (II->getOpcode() == Instruction::Call) @@ -81,38 +79,47 @@ private: } public: - /// isCall - true if a CallInst is enclosed. - /// Note that !isCall() does not mean it is an InvokeInst enclosed, - /// it also could signify a NULL Instruction pointer. + /// Return true if a CallInst is enclosed. Note that !isCall() does not mean + /// an InvokeInst is enclosed. It may also signify a NULL instruction pointer. bool isCall() const { return I.getInt(); } - /// isInvoke - true if a InvokeInst is enclosed. - /// + /// Return true if a InvokeInst is enclosed. bool isInvoke() const { return getInstruction() && !I.getInt(); } InstrTy *getInstruction() const { return I.getPointer(); } InstrTy *operator->() const { return I.getPointer(); } explicit operator bool() const { return I.getPointer(); } - /// Get the basic block containing the call site + /// Get the basic block containing the call site. BBTy* getParent() const { return getInstruction()->getParent(); } - /// getCalledValue - Return the pointer to function that is being called. - /// + /// Return the pointer to function that is being called. ValTy *getCalledValue() const { assert(getInstruction() && "Not a call or invoke instruction!"); return *getCallee(); } - /// getCalledFunction - Return the function being called if this is a direct - /// call, otherwise return null (if it's an indirect call). - /// + /// Return the function being called if this is a direct call, otherwise + /// return null (if it's an indirect call). FunTy *getCalledFunction() const { return dyn_cast<FunTy>(getCalledValue()); } - /// setCalledFunction - Set the callee to the specified value. - /// + /// Return true if the callsite is an indirect call. + bool isIndirectCall() const { + Value *V = getCalledValue(); + if (!V) + return false; + if (isa<FunTy>(V) || isa<Constant>(V)) + return false; + if (CallInst *CI = dyn_cast<CallInst>(getInstruction())) { + if (CI->isInlineAsm()) + return false; + } + return true; + } + + /// Set the callee to the specified value. void setCalledFunction(Value *V) { assert(getInstruction() && "Not a call or invoke instruction!"); *getCallee() = V; @@ -129,8 +136,7 @@ public: return static_cast<Intrinsic::ID>(0); } - /// isCallee - Determine whether the passed iterator points to the - /// callee operand's Use. + /// Determine whether the passed iterator points to the callee operand's Use. bool isCallee(Value::const_user_iterator UI) const { return isCallee(&UI.getUse()); } @@ -138,24 +144,23 @@ public: /// Determine whether this Use is the callee operand's Use. bool isCallee(const Use *U) const { return getCallee() == U; } - /// \brief Determine whether the passed iterator points to an argument - /// operand. + /// Determine whether the passed iterator points to an argument operand. bool isArgOperand(Value::const_user_iterator UI) const { return isArgOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to an argument operand. + /// Determine whether the passed use points to an argument operand. bool isArgOperand(const Use *U) const { assert(getInstruction() == U->getUser()); return arg_begin() <= U && U < arg_end(); } - /// \brief Determine whether the passed iterator points to a bundle operand. + /// Determine whether the passed iterator points to a bundle operand. bool isBundleOperand(Value::const_user_iterator UI) const { return isBundleOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to a bundle operand. + /// Determine whether the passed use points to a bundle operand. bool isBundleOperand(const Use *U) const { assert(getInstruction() == U->getUser()); if (!hasOperandBundles()) @@ -165,12 +170,12 @@ public: OperandNo < getBundleOperandsEndIndex(); } - /// \brief Determine whether the passed iterator points to a data operand. + /// Determine whether the passed iterator points to a data operand. bool isDataOperand(Value::const_user_iterator UI) const { return isDataOperand(&UI.getUse()); } - /// \brief Determine whether the passed use points to a data operand. + /// Determine whether the passed use points to a data operand. bool isDataOperand(const Use *U) const { return data_operands_begin() <= U && U < data_operands_end(); } @@ -200,8 +205,8 @@ public: return U - arg_begin(); } - /// arg_iterator - The type of iterator to use when looping over actual - /// arguments at this call site. + /// The type of iterator to use when looping over actual arguments at this + /// call site. typedef IterTy arg_iterator; iterator_range<IterTy> args() const { @@ -210,8 +215,7 @@ public: bool arg_empty() const { return arg_end() == arg_begin(); } unsigned arg_size() const { return unsigned(arg_end() - arg_begin()); } - /// Given a value use iterator, returns the data operand that corresponds to - /// it. + /// Given a value use iterator, return the data operand corresponding to it. /// Iterator must actually correspond to a data operand. unsigned getDataOperandNo(Value::const_user_iterator UI) const { return getDataOperandNo(&UI.getUse()); @@ -253,21 +257,19 @@ public: return std::distance(data_operands_begin(), data_operands_end()); } - /// getType - Return the type of the instruction that generated this call site - /// + /// Return the type of the instruction that generated this call site. Type *getType() const { return (*this)->getType(); } - /// getCaller - Return the caller function for this call site - /// + /// Return the caller function for this call site. FunTy *getCaller() const { return (*this)->getParent()->getParent(); } - /// \brief Tests if this call site must be tail call optimized. Only a - /// CallInst can be tail call optimized. + /// Tests if this call site must be tail call optimized. Only a CallInst can + /// be tail call optimized. bool isMustTailCall() const { return isCall() && cast<CallInst>(getInstruction())->isMustTailCall(); } - /// \brief Tests if this call site is marked as a tail call. + /// Tests if this call site is marked as a tail call. bool isTailCall() const { return isCall() && cast<CallInst>(getInstruction())->isTailCall(); } @@ -303,11 +305,11 @@ public: return false; } - /// getCallingConv/setCallingConv - get or set the calling convention of the - /// call. + /// Get the calling convention of the call. CallingConv::ID getCallingConv() const { CALLSITE_DELEGATE_GETTER(getCallingConv()); } + /// Set the calling convention of the call. void setCallingConv(CallingConv::ID CC) { CALLSITE_DELEGATE_SETTER(setCallingConv(CC)); } @@ -320,12 +322,12 @@ public: CALLSITE_DELEGATE_SETTER(mutateFunctionType(Ty)); } - /// getAttributes/setAttributes - get or set the parameter attributes of - /// the call. - AttributeSet getAttributes() const { + /// Get the parameter attributes of the call. + AttributeList getAttributes() const { CALLSITE_DELEGATE_GETTER(getAttributes()); } - void setAttributes(AttributeSet PAL) { + /// Set the parameter attributes of the call. + void setAttributes(AttributeList PAL) { CALLSITE_DELEGATE_SETTER(setAttributes(PAL)); } @@ -345,19 +347,24 @@ public: CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); } - /// \brief Return true if this function has the given attribute. + /// Return true if this function has the given attribute. bool hasFnAttr(Attribute::AttrKind Kind) const { CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } - /// \brief Return true if this function has the given attribute. + /// Return true if this function has the given attribute. bool hasFnAttr(StringRef Kind) const { CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } - /// \brief Return true if the call or the callee has the given attribute. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(paramHasAttr(i, Kind)); + /// Return true if this return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(hasRetAttr(Kind)); + } + + /// Return true if the call or the callee has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(paramHasAttr(ArgNo, Kind)); } Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -368,8 +375,8 @@ public: CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); } - /// \brief Return true if the data operand at index \p i directly or - /// indirectly has the attribute \p A. + /// Return true if the data operand at index \p i directly or indirectly has + /// the attribute \p A. /// /// Normal call or invoke arguments have per operand attributes, as specified /// in the attribute set attached to this instruction, while operand bundle @@ -379,37 +386,36 @@ public: CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, Kind)); } - /// @brief Extract the alignment for a call or parameter (0=unknown). + /// Extract the alignment for a call or parameter (0=unknown). uint16_t getParamAlignment(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getParamAlignment(i)); } - /// @brief Extract the number of dereferenceable bytes for a call or - /// parameter (0=unknown). + /// Extract the number of dereferenceable bytes for a call or parameter + /// (0=unknown). uint64_t getDereferenceableBytes(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getDereferenceableBytes(i)); } - /// @brief Extract the number of dereferenceable_or_null bytes for a call or + /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(uint16_t i) const { CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i)); } - /// @brief Determine if the parameter or return value is marked with NoAlias + /// Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { CALLSITE_DELEGATE_GETTER(doesNotAlias(n)); } - /// \brief Return true if the call should not be treated as a call to a - /// builtin. + /// Return true if the call should not be treated as a call to a builtin. bool isNoBuiltin() const { CALLSITE_DELEGATE_GETTER(isNoBuiltin()); } - /// @brief Return true if the call should not be inlined. + /// Return true if the call should not be inlined. bool isNoInline() const { CALLSITE_DELEGATE_GETTER(isNoInline()); } @@ -417,7 +423,7 @@ public: CALLSITE_DELEGATE_SETTER(setIsNoInline(Value)); } - /// @brief Determine if the call does not access memory. + /// Determine if the call does not access memory. bool doesNotAccessMemory() const { CALLSITE_DELEGATE_GETTER(doesNotAccessMemory()); } @@ -425,7 +431,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotAccessMemory()); } - /// @brief Determine if the call does not access or only reads memory. + /// Determine if the call does not access or only reads memory. bool onlyReadsMemory() const { CALLSITE_DELEGATE_GETTER(onlyReadsMemory()); } @@ -433,7 +439,7 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory()); } - /// @brief Determine if the call does not access or only writes memory. + /// Determine if the call does not access or only writes memory. bool doesNotReadMemory() const { CALLSITE_DELEGATE_GETTER(doesNotReadMemory()); } @@ -441,7 +447,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory()); } - /// @brief Determine if the call can access memmory only using pointers based + /// Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { CALLSITE_DELEGATE_GETTER(onlyAccessesArgMemory()); @@ -450,7 +456,7 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyAccessesArgMemory()); } - /// @brief Determine if the call cannot return. + /// Determine if the call cannot return. bool doesNotReturn() const { CALLSITE_DELEGATE_GETTER(doesNotReturn()); } @@ -458,7 +464,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotReturn()); } - /// @brief Determine if the call cannot unwind. + /// Determine if the call cannot unwind. bool doesNotThrow() const { CALLSITE_DELEGATE_GETTER(doesNotThrow()); } @@ -466,7 +472,7 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotThrow()); } - /// @brief Determine if the call can be duplicated. + /// Determine if the call can be duplicated. bool cannotDuplicate() const { CALLSITE_DELEGATE_GETTER(cannotDuplicate()); } @@ -474,7 +480,7 @@ public: CALLSITE_DELEGATE_GETTER(setCannotDuplicate()); } - /// @brief Determine if the call is convergent. + /// Determine if the call is convergent. bool isConvergent() const { CALLSITE_DELEGATE_GETTER(isConvergent()); } @@ -546,31 +552,31 @@ public: cast<InvokeInst>(II)->getOperandBundlesAsDefs(Defs); } - /// @brief Determine whether this data operand is not captured. + /// Determine whether this data operand is not captured. bool doesNotCapture(unsigned OpNo) const { return dataOperandHasImpliedAttr(OpNo + 1, Attribute::NoCapture); } - /// @brief Determine whether this argument is passed by value. + /// Determine whether this argument is passed by value. bool isByValArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::ByVal); + return paramHasAttr(ArgNo, Attribute::ByVal); } - /// @brief Determine whether this argument is passed in an alloca. + /// Determine whether this argument is passed in an alloca. bool isInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::InAlloca); + return paramHasAttr(ArgNo, Attribute::InAlloca); } - /// @brief Determine whether this argument is passed by value or in an alloca. + /// Determine whether this argument is passed by value or in an alloca. bool isByValOrInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo + 1, Attribute::ByVal) || - paramHasAttr(ArgNo + 1, Attribute::InAlloca); + return paramHasAttr(ArgNo, Attribute::ByVal) || + paramHasAttr(ArgNo, Attribute::InAlloca); } - /// @brief Determine if there are is an inalloca argument. Only the last - /// argument can have the inalloca attribute. + /// Determine if there are is an inalloca argument. Only the last argument can + /// have the inalloca attribute. bool hasInAllocaArgument() const { - return paramHasAttr(arg_size(), Attribute::InAlloca); + return !arg_empty() && paramHasAttr(arg_size() - 1, Attribute::InAlloca); } bool doesNotAccessMemory(unsigned OpNo) const { @@ -582,11 +588,16 @@ public: dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); } - /// @brief Return true if the return value is known to be not null. + bool doesNotReadMemory(unsigned OpNo) const { + return dataOperandHasImpliedAttr(OpNo + 1, Attribute::WriteOnly) || + dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); + } + + /// Return true if the return value is known to be not null. /// This may be because it has the nonnull attribute, or because at least /// one byte is dereferenceable and the pointer is in addrspace(0). bool isReturnNonNull() const { - if (paramHasAttr(0, Attribute::NonNull)) + if (hasRetAttr(Attribute::NonNull)) return true; else if (getDereferenceableBytes(0) > 0 && getType()->getPointerAddressSpace() == 0) @@ -595,8 +606,8 @@ public: return false; } - /// hasArgument - Returns true if this CallSite passes the given Value* as an - /// argument to the called function. + /// Returns true if this CallSite passes the given Value* as an argument to + /// the called function. bool hasArgument(const Value *Arg) const { for (arg_iterator AI = this->arg_begin(), E = this->arg_end(); AI != E; ++AI) @@ -661,7 +672,7 @@ template <> struct DenseMapInfo<CallSite> { } }; -/// ImmutableCallSite - establish a view to a call site for examination +/// Establish a view to a call site for examination. class ImmutableCallSite : public CallSiteBase<> { public: ImmutableCallSite() = default; diff --git a/include/llvm/IR/Comdat.h b/include/llvm/IR/Comdat.h index f4a391c31ae2..fa87093ca50a 100644 --- a/include/llvm/IR/Comdat.h +++ b/include/llvm/IR/Comdat.h @@ -1,4 +1,4 @@ -//===-- llvm/IR/Comdat.h - Comdat definitions -------------------*- C++ -*-===// +//===- llvm/IR/Comdat.h - Comdat definitions --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -51,8 +51,8 @@ private: Comdat(); // Points to the map in Module. - StringMapEntry<Comdat> *Name; - SelectionKind SK; + StringMapEntry<Comdat> *Name = nullptr; + SelectionKind SK = Any; }; inline raw_ostream &operator<<(raw_ostream &OS, const Comdat &C) { diff --git a/include/llvm/IR/Constant.h b/include/llvm/IR/Constant.h index 99c970ebb633..3b3694e7e60d 100644 --- a/include/llvm/IR/Constant.h +++ b/include/llvm/IR/Constant.h @@ -152,12 +152,13 @@ public: /// hanging off of the globals. void removeDeadConstantUsers() const; - Constant *stripPointerCasts() { + const Constant *stripPointerCasts() const { return cast<Constant>(Value::stripPointerCasts()); } - const Constant *stripPointerCasts() const { - return const_cast<Constant*>(this)->stripPointerCasts(); + Constant *stripPointerCasts() { + return const_cast<Constant*>( + static_cast<const Constant *>(this)->stripPointerCasts()); } }; diff --git a/include/llvm/IR/ConstantRange.h b/include/llvm/IR/ConstantRange.h index 27a9b1364448..6d704666933f 100644 --- a/include/llvm/IR/ConstantRange.h +++ b/include/llvm/IR/ConstantRange.h @@ -45,9 +45,6 @@ class MDNode; class ConstantRange { APInt Lower, Upper; - // If we have move semantics, pass APInts by value and move them into place. - typedef APInt APIntMoveTy; - public: /// Initialize a full (the default) or empty set for the specified bit width. /// @@ -55,12 +52,12 @@ public: /// Initialize a range to hold the single specified value. /// - ConstantRange(APIntMoveTy Value); + ConstantRange(APInt Value); /// @brief Initialize a range of values explicitly. This will assert out if /// Lower==Upper and Lower != Min or Max value for its type. It will also /// assert out if the two APInt's are not the same bit width. - ConstantRange(APIntMoveTy Lower, APIntMoveTy Upper); + ConstantRange(APInt Lower, APInt Upper); /// Produce the smallest range such that all values that may satisfy the given /// predicate with any value contained within Other is contained in the @@ -184,6 +181,10 @@ public: /// APInt getSetSize() const; + /// Compare set size of this range with the range CR. + /// + bool isSizeStrictlySmallerThanOf(const ConstantRange &CR) const; + /// Return the largest unsigned value contained in the ConstantRange. /// APInt getUnsignedMax() const; diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index cbefa3f05dfc..ad83b21c7bf3 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -138,7 +138,7 @@ public: static Constant *get(Type* Ty, const APInt& V); /// Return the constant as an APInt value reference. This allows clients to - /// obtain a copy of the value, with all its precision in tact. + /// obtain a full-precision copy of the value. /// @brief Return the constant's value. inline const APInt &getValue() const { return Val; diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h index 48cb7fe5df6f..69bd5c847a8d 100644 --- a/include/llvm/IR/DIBuilder.h +++ b/include/llvm/IR/DIBuilder.h @@ -105,13 +105,17 @@ namespace llvm { /// out into. /// \param Kind The kind of debug information to generate. /// \param DWOId The DWOId if this is a split skeleton compile unit. + /// \param SplitDebugInlining Whether to emit inline debug info. + /// \param DebugInfoForProfiling Whether to emit extra debug info for + /// profile collection. DICompileUnit * createCompileUnit(unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), DICompileUnit::DebugEmissionKind Kind = DICompileUnit::DebugEmissionKind::FullDebug, - uint64_t DWOId = 0, bool SplitDebugInlining = true); + uint64_t DWOId = 0, bool SplitDebugInlining = true, + bool DebugInfoForProfiling = false); /// Create a file descriptor to hold debugging information for a file. /// \param Filename File name. @@ -164,12 +168,15 @@ namespace llvm { DIDerivedType *createQualifiedType(unsigned Tag, DIType *FromTy); /// Create debugging information entry for a pointer. - /// \param PointeeTy Type pointed by this pointer. - /// \param SizeInBits Size. - /// \param AlignInBits Alignment. (optional) - /// \param Name Pointer type name. (optional) + /// \param PointeeTy Type pointed by this pointer. + /// \param SizeInBits Size. + /// \param AlignInBits Alignment. (optional) + /// \param DWARFAddressSpace DWARF address space. (optional) + /// \param Name Pointer type name. (optional) DIDerivedType *createPointerType(DIType *PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits = 0, + Optional<unsigned> DWARFAddressSpace = + None, StringRef Name = ""); /// Create debugging information entry for a pointer to member. @@ -186,7 +193,9 @@ namespace llvm { /// style reference or rvalue reference type. DIDerivedType *createReferenceType(unsigned Tag, DIType *RTy, uint64_t SizeInBits = 0, - uint32_t AlignInBits = 0); + uint32_t AlignInBits = 0, + Optional<unsigned> DWARFAddressSpace = + None); /// Create debugging information entry for a typedef. /// \param Ty Original type. @@ -431,13 +440,6 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, unsigned CC = 0); - /// Create an external type reference. - /// \param Tag Dwarf TAG. - /// \param File File in which the type is defined. - /// \param UniqueIdentifier A unique identifier for the type. - DICompositeType *createExternalTypeRef(unsigned Tag, DIFile *File, - StringRef UniqueIdentifier); - /// Create a new DIType* with "artificial" flag set. DIType *createArtificialType(DIType *Ty); diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index 6f37669f9768..1930d48577d4 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -104,6 +104,7 @@ private: /// Defaults to false. bool BigEndian; + unsigned AllocaAddrSpace; unsigned StackNaturalAlign; enum ManglingModeT { @@ -118,8 +119,19 @@ private: SmallVector<unsigned char, 8> LegalIntWidths; - /// \brief Primitive type alignment data. - SmallVector<LayoutAlignElem, 16> Alignments; + /// \brief Primitive type alignment data. This is sorted by type and bit + /// width during construction. + typedef SmallVector<LayoutAlignElem, 16> AlignmentsTy; + AlignmentsTy Alignments; + + AlignmentsTy::const_iterator + findAlignmentLowerBound(AlignTypeEnum AlignType, uint32_t BitWidth) const { + return const_cast<DataLayout *>(this)->findAlignmentLowerBound(AlignType, + BitWidth); + } + + AlignmentsTy::iterator + findAlignmentLowerBound(AlignTypeEnum AlignType, uint32_t BitWidth); /// \brief The string representation used to create this DataLayout std::string StringRepresentation; @@ -134,14 +146,6 @@ private: PointersTy::iterator findPointerLowerBound(uint32_t AddressSpace); - /// This member is a signal that a requested alignment type and bit width were - /// not found in the SmallVector. - static const LayoutAlignElem InvalidAlignmentElem; - - /// This member is a signal that a requested pointer type and bit width were - /// not found in the DenseSet. - static const PointerAlignElem InvalidPointerElem; - // The StructType -> StructLayout map. mutable void *LayoutMap; @@ -159,22 +163,6 @@ private: /// Internal helper method that returns requested alignment for type. unsigned getAlignment(Type *Ty, bool abi_or_pref) const; - /// \brief Valid alignment predicate. - /// - /// Predicate that tests a LayoutAlignElem reference returned by get() against - /// InvalidAlignmentElem. - bool validAlignment(const LayoutAlignElem &align) const { - return &align != &InvalidAlignmentElem; - } - - /// \brief Valid pointer predicate. - /// - /// Predicate that tests a PointerAlignElem reference returned by get() - /// against \c InvalidPointerElem. - bool validPointer(const PointerAlignElem &align) const { - return &align != &InvalidPointerElem; - } - /// Parses a target data specification string. Assert if the string is /// malformed. void parseSpecifier(StringRef LayoutDescription); @@ -199,6 +187,7 @@ public: clear(); StringRepresentation = DL.StringRepresentation; BigEndian = DL.isBigEndian(); + AllocaAddrSpace = DL.AllocaAddrSpace; StackNaturalAlign = DL.StackNaturalAlign; ManglingMode = DL.ManglingMode; LegalIntWidths = DL.LegalIntWidths; @@ -254,6 +243,7 @@ public: } unsigned getStackAlignment() const { return StackNaturalAlign; } + unsigned getAllocaAddrSpace() const { return AllocaAddrSpace; } bool hasMicrosoftFastStdCallMangling() const { return ManglingMode == MM_WinCOFFX86; diff --git a/include/llvm/IR/DebugInfoFlags.def b/include/llvm/IR/DebugInfoFlags.def index 87f3dc9dbdd3..7ea6346998fe 100644 --- a/include/llvm/IR/DebugInfoFlags.def +++ b/include/llvm/IR/DebugInfoFlags.def @@ -34,7 +34,8 @@ HANDLE_DI_FLAG((1 << 11), Vector) HANDLE_DI_FLAG((1 << 12), StaticMember) HANDLE_DI_FLAG((1 << 13), LValueReference) HANDLE_DI_FLAG((1 << 14), RValueReference) -HANDLE_DI_FLAG((1 << 15), ExternalTypeRef) +// 15 was formerly ExternalTypeRef, but this was never used. +HANDLE_DI_FLAG((1 << 15), Reserved) HANDLE_DI_FLAG((1 << 16), SingleInheritance) HANDLE_DI_FLAG((2 << 16), MultipleInheritance) HANDLE_DI_FLAG((3 << 16), VirtualInheritance) diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 187855225c50..8a924b40143a 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -629,7 +629,6 @@ public: bool isStaticMember() const { return getFlags() & FlagStaticMember; } bool isLValueReference() const { return getFlags() & FlagLValueReference; } bool isRValueReference() const { return getFlags() & FlagRValueReference; } - bool isExternalTypeRef() const { return getFlags() & FlagExternalTypeRef; } static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { @@ -710,37 +709,45 @@ class DIDerivedType : public DIType { friend class LLVMContextImpl; friend class MDNode; + /// \brief The DWARF address space of the memory pointed to or referenced by a + /// pointer or reference type respectively. + Optional<unsigned> DWARFAddressSpace; + DIDerivedType(LLVMContext &C, StorageType Storage, unsigned Tag, unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, ArrayRef<Metadata *> Ops) + uint64_t OffsetInBits, Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, ArrayRef<Metadata *> Ops) : DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits, - AlignInBits, OffsetInBits, Flags, Ops) {} + AlignInBits, OffsetInBits, Flags, Ops), + DWARFAddressSpace(DWARFAddressSpace) {} ~DIDerivedType() = default; static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, DIFile *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, - Metadata *ExtraData, StorageType Storage, - bool ShouldCreate = true) { + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, Metadata *ExtraData, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, - Flags, ExtraData, Storage, ShouldCreate); + DWARFAddressSpace, Flags, ExtraData, Storage, ShouldCreate); } static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, - Metadata *ExtraData, StorageType Storage, - bool ShouldCreate = true); + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, + DIFlags Flags, Metadata *ExtraData, + StorageType Storage, bool ShouldCreate = true); TempDIDerivedType cloneImpl() const { return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), getScope(), getBaseType(), getSizeInBits(), - getAlignInBits(), getOffsetInBits(), getFlags(), - getExtraData()); + getAlignInBits(), getOffsetInBits(), + getDWARFAddressSpace(), getFlags(), getExtraData()); } public: @@ -748,24 +755,32 @@ public: (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, DIFlags Flags, + uint64_t OffsetInBits, + Optional<unsigned> DWARFAddressSpace, DIFlags Flags, Metadata *ExtraData = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, ExtraData)) + AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, + ExtraData)) DEFINE_MDNODE_GET(DIDerivedType, (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, - DIFlags Flags, Metadata *ExtraData = nullptr), + Optional<unsigned> DWARFAddressSpace, DIFlags Flags, + Metadata *ExtraData = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, ExtraData)) + AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, + ExtraData)) TempDIDerivedType clone() const { return cloneImpl(); } - //// Get the base type this is derived from. + /// Get the base type this is derived from. DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } Metadata *getRawBaseType() const { return getOperand(3); } + /// \returns The DWARF address space of the memory pointed to or referenced by + /// a pointer or reference type respectively. + Optional<unsigned> getDWARFAddressSpace() const { return DWARFAddressSpace; } + /// Get extra data associated with this derived type. /// /// Class type for pointer-to-members, objective-c property node for ivars, @@ -1044,15 +1059,17 @@ private: unsigned EmissionKind; uint64_t DWOId; bool SplitDebugInlining; + bool DebugInfoForProfiling; DICompileUnit(LLVMContext &C, StorageType Storage, unsigned SourceLanguage, bool IsOptimized, unsigned RuntimeVersion, unsigned EmissionKind, uint64_t DWOId, bool SplitDebugInlining, - ArrayRef<Metadata *> Ops) + bool DebugInfoForProfiling, ArrayRef<Metadata *> Ops) : DIScope(C, DICompileUnitKind, Storage, dwarf::DW_TAG_compile_unit, Ops), SourceLanguage(SourceLanguage), IsOptimized(IsOptimized), RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind), - DWOId(DWOId), SplitDebugInlining(SplitDebugInlining) { + DWOId(DWOId), SplitDebugInlining(SplitDebugInlining), + DebugInfoForProfiling(DebugInfoForProfiling) { assert(Storage != Uniqued); } ~DICompileUnit() = default; @@ -1065,15 +1082,16 @@ private: DIScopeArray RetainedTypes, DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, - uint64_t DWOId, bool SplitDebugInlining, StorageType Storage, - bool ShouldCreate = true) { + uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, getCanonicalMDString(Context, SplitDebugFilename), EmissionKind, EnumTypes.get(), RetainedTypes.get(), GlobalVariables.get(), ImportedEntities.get(), Macros.get(), - DWOId, SplitDebugInlining, Storage, ShouldCreate); + DWOId, SplitDebugInlining, DebugInfoForProfiling, Storage, + ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, @@ -1082,7 +1100,8 @@ private: unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, - StorageType Storage, bool ShouldCreate = true); + bool DebugInfoForProfiling, StorageType Storage, + bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary(getContext(), getSourceLanguage(), getFile(), @@ -1090,7 +1109,8 @@ private: getRuntimeVersion(), getSplitDebugFilename(), getEmissionKind(), getEnumTypes(), getRetainedTypes(), getGlobalVariables(), getImportedEntities(), - getMacros(), DWOId, getSplitDebugInlining()); + getMacros(), DWOId, getSplitDebugInlining(), + getDebugInfoForProfiling()); } public: @@ -1105,10 +1125,11 @@ public: DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, DIGlobalVariableExpressionArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, - uint64_t DWOId, bool SplitDebugInlining), + uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, - GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining)) + GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, + DebugInfoForProfiling)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, @@ -1116,10 +1137,11 @@ public: MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, - bool SplitDebugInlining), + bool SplitDebugInlining, bool DebugInfoForProfiling), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, - GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining)) + GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, + DebugInfoForProfiling)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1129,6 +1151,7 @@ public: DebugEmissionKind getEmissionKind() const { return (DebugEmissionKind)EmissionKind; } + bool getDebugInfoForProfiling() const { return DebugInfoForProfiling; } StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } StringRef getSplitDebugFilename() const { return getStringOperand(3); } @@ -1246,6 +1269,28 @@ class DILocation : public MDNode { static_cast<Metadata *>(InlinedAt), Storage, ShouldCreate); } + /// With a given unsigned int \p U, use up to 13 bits to represent it. + /// old_bit 1~5 --> new_bit 1~5 + /// old_bit 6~12 --> new_bit 7~13 + /// new_bit_6 is 0 if higher bits (7~13) are all 0 + static unsigned getPrefixEncodingFromUnsigned(unsigned U) { + U &= 0xfff; + return U > 0x1f ? (((U & 0xfe0) << 1) | (U & 0x1f) | 0x20) : U; + } + + /// Reverse transformation as getPrefixEncodingFromUnsigned. + static unsigned getUnsignedFromPrefixEncoding(unsigned U) { + return (U & 0x20) ? (((U >> 1) & 0xfe0) | (U & 0x1f)) : (U & 0x1f); + } + + /// Returns the next component stored in discriminator. + static unsigned getNextComponentInDiscriminator(unsigned D) { + if ((D & 1) == 0) + return D >> ((D & 0x40) ? 14 : 7); + else + return D >> 1; + } + TempDILocation cloneImpl() const { // Get the raw scope/inlinedAt since it is possible to invoke this on // a DILocation containing temporary metadata. @@ -1307,10 +1352,48 @@ public: /// /// DWARF discriminators distinguish identical file locations between /// instructions that are on different basic blocks. + /// + /// There are 3 components stored in discriminator, from lower bits: + /// + /// Base discriminator: assigned by AddDiscriminators pass to identify IRs + /// that are defined by the same source line, but + /// different basic blocks. + /// Duplication factor: assigned by optimizations that will scale down + /// the execution frequency of the original IR. + /// Copy Identifier: assigned by optimizations that clones the IR. + /// Each copy of the IR will be assigned an identifier. + /// + /// Encoding: + /// + /// The above 3 components are encoded into a 32bit unsigned integer in + /// order. If the lowest bit is 1, the current component is empty, and the + /// next component will start in the next bit. Otherwise, the the current + /// component is non-empty, and its content starts in the next bit. The + /// length of each components is either 5 bit or 12 bit: if the 7th bit + /// is 0, the bit 2~6 (5 bits) are used to represent the component; if the + /// 7th bit is 1, the bit 2~6 (5 bits) and 8~14 (7 bits) are combined to + /// represent the component. + inline unsigned getDiscriminator() const; /// Returns a new DILocation with updated \p Discriminator. - inline DILocation *cloneWithDiscriminator(unsigned Discriminator) const; + inline const DILocation *cloneWithDiscriminator(unsigned Discriminator) const; + + /// Returns a new DILocation with updated base discriminator \p BD. + inline const DILocation *setBaseDiscriminator(unsigned BD) const; + + /// Returns the duplication factor stored in the discriminator. + inline unsigned getDuplicationFactor() const; + + /// Returns the copy identifier stored in the discriminator. + inline unsigned getCopyIdentifier() const; + + /// Returns the base discriminator stored in the discriminator. + inline unsigned getBaseDiscriminator() const; + + /// Returns a new DILocation with duplication factor \p DF encoded in the + /// discriminator. + inline const DILocation *cloneWithDuplicationFactor(unsigned DF) const; /// When two instructions are combined into a single instruction we also /// need to combine the original locations into a single location. @@ -1333,6 +1416,30 @@ public: return nullptr; } + /// Returns the base discriminator for a given encoded discriminator \p D. + static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { + if ((D & 1) == 0) + return getUnsignedFromPrefixEncoding(D >> 1); + else + return 0; + } + + /// Returns the duplication factor for a given encoded discriminator \p D. + static unsigned getDuplicationFactorFromDiscriminator(unsigned D) { + D = getNextComponentInDiscriminator(D); + if (D == 0 || (D & 1)) + return 1; + else + return getUnsignedFromPrefixEncoding(D >> 1); + } + + /// Returns the copy identifier for a given encoded discriminator \p D. + static unsigned getCopyIdentifierFromDiscriminator(unsigned D) { + return getUnsignedFromPrefixEncoding(getNextComponentInDiscriminator( + getNextComponentInDiscriminator(D))); + } + + Metadata *getRawScope() const { return getOperand(0); } Metadata *getRawInlinedAt() const { if (getNumOperands() == 2) @@ -1343,6 +1450,7 @@ public: static bool classof(const Metadata *MD) { return MD->getMetadataID() == DILocationKind; } + }; /// Subprogram description. @@ -1676,7 +1784,8 @@ unsigned DILocation::getDiscriminator() const { return 0; } -DILocation *DILocation::cloneWithDiscriminator(unsigned Discriminator) const { +const DILocation * +DILocation::cloneWithDiscriminator(unsigned Discriminator) const { DIScope *Scope = getScope(); // Skip all parent DILexicalBlockFile that already have a discriminator // assigned. We do not want to have nested DILexicalBlockFiles that have @@ -1692,6 +1801,42 @@ DILocation *DILocation::cloneWithDiscriminator(unsigned Discriminator) const { getInlinedAt()); } +unsigned DILocation::getBaseDiscriminator() const { + return getBaseDiscriminatorFromDiscriminator(getDiscriminator()); +} + +unsigned DILocation::getDuplicationFactor() const { + return getDuplicationFactorFromDiscriminator(getDiscriminator()); +} + +unsigned DILocation::getCopyIdentifier() const { + return getCopyIdentifierFromDiscriminator(getDiscriminator()); +} + +const DILocation *DILocation::setBaseDiscriminator(unsigned D) const { + if (D == 0) + return this; + else + return cloneWithDiscriminator(getPrefixEncodingFromUnsigned(D) << 1); +} + +const DILocation *DILocation::cloneWithDuplicationFactor(unsigned DF) const { + DF *= getDuplicationFactor(); + if (DF <= 1) + return this; + + unsigned BD = getBaseDiscriminator(); + unsigned CI = getCopyIdentifier() << (DF > 0x1f ? 14 : 7); + unsigned D = CI | (getPrefixEncodingFromUnsigned(DF) << 1); + + if (BD == 0) + D = (D << 1) | 1; + else + D = (D << (BD > 0x1f ? 14 : 7)) | (getPrefixEncodingFromUnsigned(BD) << 1); + + return cloneWithDiscriminator(D); +} + class DINamespace : public DIScope { friend class LLVMContextImpl; friend class MDNode; @@ -1918,7 +2063,7 @@ protected: DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Line, ArrayRef<Metadata *> Ops, uint32_t AlignInBits = 0) : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), - AlignInBits(AlignInBits) {} + AlignInBits(AlignInBits) {} ~DIVariable() = default; public: @@ -2108,7 +2253,7 @@ public: /// Retrieve the details of this fragment expression. static Optional<FragmentInfo> getFragmentInfo(expr_op_iterator Start, - expr_op_iterator End); + expr_op_iterator End); /// Retrieve the details of this fragment expression. Optional<FragmentInfo> getFragmentInfo() const { diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index a93c180df1b5..458c3cf29b0d 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -69,6 +69,11 @@ enum DiagnosticKind { DK_OptimizationFailure, DK_FirstRemark = DK_OptimizationRemark, DK_LastRemark = DK_OptimizationFailure, + DK_MachineOptimizationRemark, + DK_MachineOptimizationRemarkMissed, + DK_MachineOptimizationRemarkAnalysis, + DK_FirstMachineRemark = DK_MachineOptimizationRemark, + DK_LastMachineRemark = DK_MachineOptimizationRemarkAnalysis, DK_MIRParser, DK_PGOProfile, DK_Unsupported, @@ -342,19 +347,34 @@ private: const Twine &Msg; }; -/// Common features for diagnostics with an associated DebugLoc -class DiagnosticInfoWithDebugLocBase : public DiagnosticInfo { +class DiagnosticLocation { + StringRef Filename; + unsigned Line = 0; + unsigned Column = 0; public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + DiagnosticLocation() {} + DiagnosticLocation(const DebugLoc &DL); + DiagnosticLocation(const DISubprogram *SP); + + bool isValid() const { return !Filename.empty(); } + StringRef getFilename() const { return Filename; } + unsigned getLine() const { return Line; } + unsigned getColumn() const { return Column; } +}; + +/// Common features for diagnostics with an associated location. +class DiagnosticInfoWithLocationBase : public DiagnosticInfo { +public: + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. - DiagnosticInfoWithDebugLocBase(enum DiagnosticKind Kind, + DiagnosticInfoWithLocationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const Function &Fn, - const DebugLoc &DLoc) - : DiagnosticInfo(Kind, Severity), Fn(Fn), DLoc(DLoc) {} + const DiagnosticLocation &Loc) + : DiagnosticInfo(Kind, Severity), Fn(Fn), Loc(Loc) {} /// Return true if location information is available for this diagnostic. - bool isLocationAvailable() const; + bool isLocationAvailable() const { return Loc.isValid(); } /// Return a string with the location information for this diagnostic /// in the format "file:line:col". If location information is not available, @@ -366,18 +386,19 @@ public: void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const; const Function &getFunction() const { return Fn; } - const DebugLoc &getDebugLoc() const { return DLoc; } + DiagnosticLocation getLocation() const { return Loc; } private: /// Function where this diagnostic is triggered. const Function &Fn; /// Debug location where this diagnostic is triggered. - DebugLoc DLoc; + DiagnosticLocation Loc; }; -/// Common features for diagnostics dealing with optimization remarks. -class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithDebugLocBase { +/// \brief Common features for diagnostics dealing with optimization remarks +/// that are used by both IR and MIR passes. +class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithLocationBase { public: /// \brief Used to set IsVerbose via the stream interface. struct setIsVerbose {}; @@ -394,66 +415,29 @@ public: StringRef Key; std::string Val; // If set, the debug location corresponding to the value. - DebugLoc DLoc; + DiagnosticLocation Loc; explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {} - Argument(StringRef Key, Value *V); - Argument(StringRef Key, Type *T); + Argument(StringRef Key, const Value *V); + Argument(StringRef Key, const Type *T); Argument(StringRef Key, int N); Argument(StringRef Key, unsigned N); Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {} }; /// \p PassName is the name of the pass emitting this diagnostic. \p - /// RemarkName is a textual identifier for the remark. \p Fn is the function - /// where the diagnostic is being emitted. \p DLoc is the location information - /// to use in the diagnostic. If line table information is available, the - /// diagnostic will include the source code location. \p CodeRegion is IR - /// value (currently basic block) that the optimization operates on. This is - /// currently used to provide run-time hotness information with PGO. - DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, - enum DiagnosticSeverity Severity, - const char *PassName, StringRef RemarkName, - const Function &Fn, const DebugLoc &DLoc, - Value *CodeRegion = nullptr) - : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc), - PassName(PassName), RemarkName(RemarkName), CodeRegion(CodeRegion) {} - - /// \brief This is ctor variant allows a pass to build an optimization remark - /// from an existing remark. - /// - /// This is useful when a transformation pass (e.g LV) wants to emit a remark - /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis - /// remark. The string \p Prepend will be emitted before the original - /// message. - DiagnosticInfoOptimizationBase(const char *PassName, StringRef Prepend, - const DiagnosticInfoOptimizationBase &Orig) - : DiagnosticInfoWithDebugLocBase((DiagnosticKind)Orig.getKind(), - Orig.getSeverity(), Orig.getFunction(), - Orig.getDebugLoc()), - PassName(PassName), RemarkName(Orig.RemarkName), - CodeRegion(Orig.getCodeRegion()) { - *this << Prepend; - std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); - } - - /// Legacy interface. - /// \p PassName is the name of the pass emitting this diagnostic. - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is - /// the location information to use in the diagnostic. If line table + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Fn is the function where the diagnostic is being emitted. + /// \p Loc is the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code - /// location. \p Msg is the message to show. Note that this class does not - /// copy this message, so this reference must be valid for the whole life time - /// of the diagnostic. + /// location. DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, - const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoWithDebugLocBase(Kind, Severity, Fn, DLoc), - PassName(PassName), Hotness(Hotness) { - Args.push_back(Argument(Msg.str())); - } + const char *PassName, StringRef RemarkName, + const Function &Fn, + const DiagnosticLocation &Loc) + : DiagnosticInfoWithLocationBase(Kind, Severity, Fn, Loc), + PassName(PassName), RemarkName(RemarkName) {} DiagnosticInfoOptimizationBase &operator<<(StringRef S); DiagnosticInfoOptimizationBase &operator<<(Argument A); @@ -475,33 +459,45 @@ public: Optional<uint64_t> getHotness() const { return Hotness; } void setHotness(Optional<uint64_t> H) { Hotness = H; } - Value *getCodeRegion() const { return CodeRegion; } - bool isVerbose() const { return IsVerbose; } static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() >= DK_FirstRemark && - DI->getKind() <= DK_LastRemark; + return (DI->getKind() >= DK_FirstRemark && + DI->getKind() <= DK_LastRemark) || + (DI->getKind() >= DK_FirstMachineRemark && + DI->getKind() <= DK_LastMachineRemark); } -private: + bool isPassed() const { + return (getKind() == DK_OptimizationRemark || + getKind() == DK_MachineOptimizationRemark); + } + + bool isMissed() const { + return (getKind() == DK_OptimizationRemarkMissed || + getKind() == DK_MachineOptimizationRemarkMissed); + } + + bool isAnalysis() const { + return (getKind() == DK_OptimizationRemarkAnalysis || + getKind() == DK_MachineOptimizationRemarkAnalysis); + } + +protected: /// Name of the pass that triggers this report. If this matches the /// regular expression given in -Rpass=regexp, then the remark will /// be emitted. const char *PassName; - /// Textual identifier for the remark. Can be used by external tools reading - /// the YAML output file for optimization remarks to identify the remark. + /// Textual identifier for the remark (single-word, camel-case). Can be used + /// by external tools reading the YAML output file for optimization remarks to + /// identify the remark. StringRef RemarkName; /// If profile information is available, this is the number of times the /// corresponding code was executed in a profile instrumentation run. Optional<uint64_t> Hotness; - /// The IR value (currently basic block) that the optimization operates on. - /// This is currently used to provide run-time hotness information with PGO. - Value *CodeRegion; - /// Arguments collected via the streaming interface. SmallVector<Argument, 4> Args; @@ -516,106 +512,186 @@ private: friend struct yaml::MappingTraits<DiagnosticInfoOptimizationBase *>; }; -/// Diagnostic information for applied optimization remarks. -class OptimizationRemark : public DiagnosticInfoOptimizationBase { +/// \brief Common features for diagnostics dealing with optimization remarks +/// that are used by IR passes. +class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase { public: - /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass=, then the - /// diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the - /// diagnostic. If line table information is available, the diagnostic - /// will include the source code location. \p Msg is the message to show. - /// Note that this class does not copy this message, so this reference - /// must be valid for the whole life time of the diagnostic. - OptimizationRemark(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemark, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} + /// \p PassName is the name of the pass emitting this diagnostic. \p + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Fn is the function where the diagnostic is being emitted. + /// \p Loc is the location information to use in the diagnostic. If line table + /// information is available, the diagnostic will include the source code + /// location. \p CodeRegion is IR value (currently basic block) that the + /// optimization operates on. This is currently used to provide run-time + /// hotness information with PGO. + DiagnosticInfoIROptimization(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const char *PassName, StringRef RemarkName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Value *CodeRegion = nullptr) + : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, RemarkName, Fn, + Loc), + CodeRegion(CodeRegion) {} + /// \brief This is ctor variant allows a pass to build an optimization remark + /// from an existing remark. + /// + /// This is useful when a transformation pass (e.g LV) wants to emit a remark + /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis + /// remark. The string \p Prepend will be emitted before the original + /// message. + DiagnosticInfoIROptimization(const char *PassName, StringRef Prepend, + const DiagnosticInfoIROptimization &Orig) + : DiagnosticInfoOptimizationBase( + (DiagnosticKind)Orig.getKind(), Orig.getSeverity(), PassName, + Orig.RemarkName, Orig.getFunction(), Orig.getLocation()), + CodeRegion(Orig.getCodeRegion()) { + *this << Prepend; + std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); + } + + /// Legacy interface. + /// \p PassName is the name of the pass emitting this diagnostic. + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is + /// the location information to use in the diagnostic. If line table + /// information is available, the diagnostic will include the source code + /// location. \p Msg is the message to show. Note that this class does not + /// copy this message, so this reference must be valid for the whole life time + /// of the diagnostic. + DiagnosticInfoIROptimization(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, "", Fn, Loc) { + *this << Msg.str(); + } + + const Value *getCodeRegion() const { return CodeRegion; } + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark; + } + +private: + /// The IR value (currently basic block) that the optimization operates on. + /// This is currently used to provide run-time hotness information with PGO. + const Value *CodeRegion; +}; + +/// Diagnostic information for applied optimization remarks. +class OptimizationRemark : public DiagnosticInfoIROptimization { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass=, then the diagnostic will - /// be emitted. \p RemarkName is a textual identifier for the remark. \p - /// DLoc is the debug location and \p CodeRegion is the region that the - /// optimization operates on (currently on block is supported). + /// be emitted. \p RemarkName is a textual identifier for the remark (single- + /// word, camel-case). \p Loc is the debug location and \p CodeRegion is the + /// region that the optimization operates on (currently only block is + /// supported). OptimizationRemark(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, const Value *CodeRegion); - /// Same as above but the debug location and code region is derived from \p + /// Same as above, but the debug location and code region are derived from \p /// Instr. OptimizationRemark(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); + + /// Same as above, but the debug location and code region are derived from \p + /// Func. + OptimizationRemark(const char *PassName, StringRef RemarkName, + const Function *Func); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemark; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; -}; + bool isEnabled() const override { return isEnabled(getPassName()); } -/// Diagnostic information for missed-optimization remarks. -class OptimizationRemarkMissed : public DiagnosticInfoOptimizationBase { -public: +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass-missed=, then the + /// this name matches the regular expression given in -Rpass=, then the /// diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic /// will include the source code location. \p Msg is the message to show. /// Note that this class does not copy this message, so this reference /// must be valid for the whole life time of the diagnostic. - OptimizationRemarkMissed(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} + OptimizationRemark(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, + Fn, Loc, Msg) {} + + friend void emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); +}; +/// Diagnostic information for missed-optimization remarks. +class OptimizationRemarkMissed : public DiagnosticInfoIROptimization { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-missed=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, + const Value *CodeRegion); /// \brief Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkMissed; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; + bool isEnabled() const override { return isEnabled(getPassName()); } + +private: + /// This is deprecated now and only used by the function API below. + /// \p PassName is the name of the pass emitting this diagnostic. If + /// this name matches the regular expression given in -Rpass-missed=, then the + /// diagnostic will be emitted. \p Fn is the function where the diagnostic + /// is being emitted. \p Loc is the location information to use in the + /// diagnostic. If line table information is available, the diagnostic + /// will include the source code location. \p Msg is the message to show. + /// Note that this class does not copy this message, so this reference + /// must be valid for the whole life time of the diagnostic. + OptimizationRemarkMissed(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark, + PassName, Fn, Loc, Msg) {} + + friend void emitOptimizationRemarkMissed(LLVMContext &Ctx, + const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); }; /// Diagnostic information for optimization analysis remarks. -class OptimizationRemarkAnalysis : public DiagnosticInfoOptimizationBase { +class OptimizationRemarkAnalysis : public DiagnosticInfoIROptimization { public: - /// \p PassName is the name of the pass emitting this diagnostic. If - /// this name matches the regular expression given in -Rpass-analysis=, then - /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the - /// diagnostic. If line table information is available, the diagnostic will - /// include the source code location. \p Msg is the message to show. Note that - /// this class does not copy this message, so this reference must be valid for - /// the whole life time of the diagnostic. - OptimizationRemarkAnalysis(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkAnalysis, DS_Remark, - PassName, Fn, DLoc, Msg, Hotness) {} - /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion); + const DiagnosticLocation &Loc, + const Value *CodeRegion); /// \brief This is ctor variant allows a pass to build an optimization remark /// from an existing remark. @@ -626,19 +702,23 @@ public: /// message. OptimizationRemarkAnalysis(const char *PassName, StringRef Prepend, const OptimizationRemarkAnalysis &Orig) - : DiagnosticInfoOptimizationBase(PassName, Prepend, Orig) {} + : DiagnosticInfoIROptimization(PassName, Prepend, Orig) {} /// \brief Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, - Instruction *Inst); + const Instruction *Inst); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysis; } + static bool isEnabled(StringRef PassName); + /// \see DiagnosticInfoOptimizationBase::isEnabled. - bool isEnabled() const override; + bool isEnabled() const override { + return shouldAlwaysPrint() || isEnabled(getPassName()); + } static const char *AlwaysPrint; @@ -646,24 +726,65 @@ public: protected: OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, - const Twine &Msg, Optional<uint64_t> Hotness) - : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, Fn, DLoc, Msg, - Hotness) {} + const Function &Fn, const DiagnosticLocation &Loc, + const Twine &Msg) + : DiagnosticInfoIROptimization(Kind, DS_Remark, PassName, Fn, Loc, Msg) {} OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, - StringRef RemarkName, const DebugLoc &DLoc, - Value *CodeRegion); + StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion); + +private: + /// This is deprecated now and only used by the function API below. + /// \p PassName is the name of the pass emitting this diagnostic. If + /// this name matches the regular expression given in -Rpass-analysis=, then + /// the diagnostic will be emitted. \p Fn is the function where the diagnostic + /// is being emitted. \p Loc is the location information to use in the + /// diagnostic. If line table information is available, the diagnostic will + /// include the source code location. \p Msg is the message to show. Note that + /// this class does not copy this message, so this reference must be valid for + /// the whole life time of the diagnostic. + OptimizationRemarkAnalysis(const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) + : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark, + PassName, Fn, Loc, Msg) {} + + friend void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, + const char *PassName, + const Function &Fn, + const DiagnosticLocation &Loc, + const Twine &Msg); }; /// Diagnostic information for optimization analysis remarks related to /// floating-point non-commutativity. class OptimizationRemarkAnalysisFPCommute : public OptimizationRemarkAnalysis { public: + /// \p PassName is the name of the pass emitting this diagnostic. If this name + /// matches the regular expression given in -Rpass-analysis=, then the + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). The front-end will append its own message related to + /// options that address floating-point non-commutativity. + OptimizationRemarkAnalysisFPCommute(const char *PassName, + StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion) + : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, + PassName, RemarkName, Loc, CodeRegion) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_OptimizationRemarkAnalysisFPCommute; + } + +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass-analysis=, then /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address @@ -671,37 +792,42 @@ public: /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisFPCommute(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) + const DiagnosticLocation &Loc, + const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, - PassName, Fn, DLoc, Msg, Hotness) {} + PassName, Fn, Loc, Msg) {} + friend void emitOptimizationRemarkAnalysisFPCommute( + LLVMContext &Ctx, const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); +}; +/// Diagnostic information for optimization analysis remarks related to +/// pointer aliasing. +class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis { +public: /// \p PassName is the name of the pass emitting this diagnostic. If this name /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). The - /// front-end will append its own message related to options that address - /// floating-point non-commutativity. - OptimizationRemarkAnalysisFPCommute(const char *PassName, - StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion) - : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, - PassName, RemarkName, DLoc, CodeRegion) {} + /// diagnostic will be emitted. \p RemarkName is a textual identifier for the + /// remark (single-word, camel-case). \p Loc is the debug location and \p + /// CodeRegion is the region that the optimization operates on (currently only + /// block is supported). The front-end will append its own message related to + /// options that address pointer aliasing legality. + OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion) + : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, + PassName, RemarkName, Loc, CodeRegion) {} static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() == DK_OptimizationRemarkAnalysisFPCommute; + return DI->getKind() == DK_OptimizationRemarkAnalysisAliasing; } -}; -/// Diagnostic information for optimization analysis remarks related to -/// pointer aliasing. -class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis { -public: +private: + /// This is deprecated now and only used by the function API below. /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass-analysis=, then /// the diagnostic will be emitted. \p Fn is the function where the diagnostic - /// is being emitted. \p DLoc is the location information to use in the + /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address @@ -709,26 +835,14 @@ public: /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisAliasing(const char *PassName, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg, - Optional<uint64_t> Hotness = None) - : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, - PassName, Fn, DLoc, Msg, Hotness) {} - - /// \p PassName is the name of the pass emitting this diagnostic. If this name - /// matches the regular expression given in -Rpass-analysis=, then the - /// diagnostic will be emitted. \p RemarkName is a textual identifier for the - /// remark. \p DLoc is the debug location and \p CodeRegion is the region - /// that the optimization operates on (currently on block is supported). The - /// front-end will append its own message related to options that address - /// pointer aliasing legality. - OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName, - const DebugLoc &DLoc, Value *CodeRegion) + const DiagnosticLocation &Loc, + const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, - PassName, RemarkName, DLoc, CodeRegion) {} + PassName, Fn, Loc, Msg) {} - static bool classof(const DiagnosticInfo *DI) { - return DI->getKind() == DK_OptimizationRemarkAnalysisAliasing; - } + friend void emitOptimizationRemarkAnalysisAliasing( + LLVMContext &Ctx, const char *PassName, const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); }; /// Diagnostic information for machine IR parser. @@ -771,73 +885,97 @@ public: // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef) -/// Emit an optimization-applied message. \p PassName is the name of the pass -/// emitting the message. If -Rpass= is given and \p PassName matches the -/// regular expression in -Rpass, then the remark will be emitted. \p Fn is -/// the function triggering the remark, \p DLoc is the debug location where -/// the diagnostic is generated. \p Msg is the message string to use. +/// \brief Legacy interface to emit an optimization-applied message. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If -Rpass= is +/// given and \p PassName matches the regular expression in -Rpass, then the +/// remark will be emitted. \p Fn is the function triggering the remark, \p Loc +/// is the debug location where the diagnostic is generated. \p Msg is the +/// message string to use. void emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization-missed message. \p PassName is the name of the -/// pass emitting the message. If -Rpass-missed= is given and \p PassName -/// matches the regular expression in -Rpass, then the remark will be -/// emitted. \p Fn is the function triggering the remark, \p DLoc is the -/// debug location where the diagnostic is generated. \p Msg is the +/// \brief Legacy interface to emit an optimization-missed message. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If -Rpass-missed= +/// is given and \p PassName matches the regular expression in -Rpass, then the +/// remark will be emitted. \p Fn is the function triggering the remark, \p Loc +/// is the debug location where the diagnostic is generated. \p Msg is the /// message string to use. void emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark message. \p PassName is the name of -/// the pass emitting the message. If -Rpass-analysis= is given and \p -/// PassName matches the regular expression in -Rpass, then the remark will be -/// emitted. \p Fn is the function triggering the remark, \p DLoc is the debug -/// location where the diagnostic is generated. \p Msg is the message string -/// to use. +/// \brief Legacy interface to emit an optimization analysis remark message. +/// Use (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If +/// -Rpass-analysis= is given and \p PassName matches the regular expression in +/// -Rpass, then the remark will be emitted. \p Fn is the function triggering +/// the remark, \p Loc is the debug location where the diagnostic is +/// generated. \p Msg is the message string to use. void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, const char *PassName, - const Function &Fn, const DebugLoc &DLoc, + const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark related to messages about -/// floating-point non-commutativity. \p PassName is the name of the pass -/// emitting the message. If -Rpass-analysis= is given and \p PassName matches -/// the regular expression in -Rpass, then the remark will be emitted. \p Fn is -/// the function triggering the remark, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. +/// \brief Legacy interface to emit an optimization analysis remark related to +/// messages about floating-point non-commutativity. Use +/// (Machine)OptimizationRemarkEmitter instead. +/// +/// \p PassName is the name of the pass emitting the message. If +/// -Rpass-analysis= is given and \p PassName matches the regular expression in +/// -Rpass, then the remark will be emitted. \p Fn is the function triggering +/// the remark, \p Loc is the debug location where the diagnostic is +/// generated. \p Msg is the message string to use. void emitOptimizationRemarkAnalysisFPCommute(LLVMContext &Ctx, const char *PassName, const Function &Fn, - const DebugLoc &DLoc, + const DiagnosticLocation &Loc, const Twine &Msg); -/// Emit an optimization analysis remark related to messages about -/// pointer aliasing. \p PassName is the name of the pass emitting the message. +/// \brief Legacy interface to emit an optimization analysis remark related to +/// messages about pointer aliasing. Use (Machine)OptimizationRemarkEmitter +/// instead. +/// +/// \p PassName is the name of the pass emitting the message. /// If -Rpass-analysis= is given and \p PassName matches the regular expression /// in -Rpass, then the remark will be emitted. \p Fn is the function triggering -/// the remark, \p DLoc is the debug location where the diagnostic is generated. +/// the remark, \p Loc is the debug location where the diagnostic is generated. /// \p Msg is the message string to use. void emitOptimizationRemarkAnalysisAliasing(LLVMContext &Ctx, const char *PassName, const Function &Fn, - const DebugLoc &DLoc, + const DiagnosticLocation &Loc, const Twine &Msg); /// Diagnostic information for optimization failures. -class DiagnosticInfoOptimizationFailure - : public DiagnosticInfoOptimizationBase { +class DiagnosticInfoOptimizationFailure : public DiagnosticInfoIROptimization { public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. - DiagnosticInfoOptimizationFailure(const Function &Fn, const DebugLoc &DLoc, + DiagnosticInfoOptimizationFailure(const Function &Fn, + const DiagnosticLocation &Loc, const Twine &Msg) - : DiagnosticInfoOptimizationBase(DK_OptimizationFailure, DS_Warning, - nullptr, Fn, DLoc, Msg) {} + : DiagnosticInfoIROptimization(DK_OptimizationFailure, DS_Warning, + nullptr, Fn, Loc, Msg) {} + + /// \p PassName is the name of the pass emitting this diagnostic. \p + /// RemarkName is a textual identifier for the remark (single-word, + /// camel-case). \p Loc is the debug location and \p CodeRegion is the + /// region that the optimization operates on (currently basic block is + /// supported). + DiagnosticInfoOptimizationFailure(const char *PassName, StringRef RemarkName, + const DiagnosticLocation &Loc, + const Value *CodeRegion); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationFailure; @@ -848,22 +986,22 @@ public: }; /// Diagnostic information for unsupported feature in backend. -class DiagnosticInfoUnsupported - : public DiagnosticInfoWithDebugLocBase { +class DiagnosticInfoUnsupported : public DiagnosticInfoWithLocationBase { private: Twine Msg; public: - /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is + /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. - DiagnosticInfoUnsupported(const Function &Fn, const Twine &Msg, - DebugLoc DLoc = DebugLoc(), - DiagnosticSeverity Severity = DS_Error) - : DiagnosticInfoWithDebugLocBase(DK_Unsupported, Severity, Fn, DLoc), + DiagnosticInfoUnsupported( + const Function &Fn, const Twine &Msg, + const DiagnosticLocation &Loc = DiagnosticLocation(), + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfoWithLocationBase(DK_Unsupported, Severity, Fn, Loc), Msg(Msg) {} static bool classof(const DiagnosticInfo *DI) { @@ -874,19 +1012,6 @@ public: void print(DiagnosticPrinter &DP) const override; }; - -/// Emit a warning when loop vectorization is specified but fails. \p Fn is the -/// function triggering the warning, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. -void emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg); - -/// Emit a warning when loop interleaving is specified but fails. \p Fn is the -/// function triggering the warning, \p DLoc is the debug location where the -/// diagnostic is generated. \p Msg is the message string to use. -void emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, - const DebugLoc &DLoc, const Twine &Msg); - } // end namespace llvm #endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/include/llvm/IR/Dominators.h b/include/llvm/IR/Dominators.h index 7c733bac8da0..cae03d33a7ee 100644 --- a/include/llvm/IR/Dominators.h +++ b/include/llvm/IR/Dominators.h @@ -16,17 +16,21 @@ #define LLVM_IR_DOMINATORS_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/GenericDomTree.h" +#include <utility> namespace llvm { class Function; -class BasicBlock; +class Instruction; +class Module; class raw_ostream; extern template class DomTreeNodeBase<BasicBlock>; @@ -43,24 +47,37 @@ typedef DomTreeNodeBase<BasicBlock> DomTreeNode; class BasicBlockEdge { const BasicBlock *Start; const BasicBlock *End; + public: BasicBlockEdge(const BasicBlock *Start_, const BasicBlock *End_) : - Start(Start_), End(End_) { } + Start(Start_), End(End_) {} + + BasicBlockEdge(const std::pair<BasicBlock *, BasicBlock *> &Pair) + : Start(Pair.first), End(Pair.second) {} + + BasicBlockEdge(const std::pair<const BasicBlock *, const BasicBlock *> &Pair) + : Start(Pair.first), End(Pair.second) {} + const BasicBlock *getStart() const { return Start; } + const BasicBlock *getEnd() const { return End; } + bool isSingleEdge() const; }; template <> struct DenseMapInfo<BasicBlockEdge> { - static unsigned getHashValue(const BasicBlockEdge *V); typedef DenseMapInfo<const BasicBlock *> BBInfo; + + static unsigned getHashValue(const BasicBlockEdge *V); + static inline BasicBlockEdge getEmptyKey() { return BasicBlockEdge(BBInfo::getEmptyKey(), BBInfo::getEmptyKey()); } + static inline BasicBlockEdge getTombstoneKey() { return BasicBlockEdge(BBInfo::getTombstoneKey(), BBInfo::getTombstoneKey()); } @@ -69,6 +86,7 @@ template <> struct DenseMapInfo<BasicBlockEdge> { return hash_combine(BBInfo::getHashValue(Edge.getStart()), BBInfo::getHashValue(Edge.getEnd())); } + static bool isEqual(const BasicBlockEdge &LHS, const BasicBlockEdge &RHS) { return BBInfo::isEqual(LHS.getStart(), RHS.getStart()) && BBInfo::isEqual(LHS.getEnd(), RHS.getEnd()); @@ -102,19 +120,17 @@ public: recalculate(F); } + /// Handle invalidation explicitly. + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &); + /// \brief Returns *false* if the other dominator tree matches this dominator /// tree. inline bool compare(const DominatorTree &Other) const { const DomTreeNode *R = getRootNode(); const DomTreeNode *OtherR = Other.getRootNode(); - - if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) - return true; - - if (Base::compare(Other)) - return true; - - return false; + return !R || !OtherR || R->getBlock() != OtherR->getBlock() || + Base::compare(Other); } // Ensure base-class overloads are visible. @@ -205,6 +221,7 @@ class DominatorTreePrinterPass public: explicit DominatorTreePrinterPass(raw_ostream &OS); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; @@ -240,6 +257,6 @@ public: void print(raw_ostream &OS, const Module *M = nullptr) const override; }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_DOMINATORS_H diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 1854d413c627..a3762a44ccb6 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -18,6 +18,7 @@ #ifndef LLVM_IR_FUNCTION_H #define LLVM_IR_FUNCTION_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringRef.h" @@ -47,23 +48,23 @@ class DISubprogram; class Function : public GlobalObject, public ilist_node<Function> { public: - typedef SymbolTableList<Argument> ArgumentListType; typedef SymbolTableList<BasicBlock> BasicBlockListType; // BasicBlock iterators... typedef BasicBlockListType::iterator iterator; typedef BasicBlockListType::const_iterator const_iterator; - typedef ArgumentListType::iterator arg_iterator; - typedef ArgumentListType::const_iterator const_arg_iterator; + typedef Argument *arg_iterator; + typedef const Argument *const_arg_iterator; private: // Important things that make up a function! BasicBlockListType BasicBlocks; ///< The basic blocks - mutable ArgumentListType ArgumentList; ///< The formal arguments + mutable Argument *Arguments; ///< The formal arguments + size_t NumArgs; std::unique_ptr<ValueSymbolTable> SymTab; ///< Symbol table of args/instructions - AttributeSet AttributeSets; ///< Parameter attributes + AttributeList AttributeSets; ///< Parameter attributes /* * Value::SubclassData @@ -102,6 +103,8 @@ private: void BuildLazyArguments() const; + void clearArguments(); + /// Function ctor - If the (optional) Module argument is specified, the /// function is automatically inserted into the end of the function list for /// the module. @@ -121,10 +124,12 @@ public: // Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// Returns the type of the ret val. - Type *getReturnType() const; /// Returns the FunctionType for me. - FunctionType *getFunctionType() const; + FunctionType *getFunctionType() const { + return cast<FunctionType>(getValueType()); + } + /// Returns the type of the ret val. + Type *getReturnType() const { return getFunctionType()->getReturnType(); } /// getContext - Return a reference to the LLVMContext associated with this /// function. @@ -132,10 +137,16 @@ public: /// isVarArg - Return true if this function takes a variable number of /// arguments. - bool isVarArg() const; + bool isVarArg() const { return getFunctionType()->isVarArg(); } - bool isMaterializable() const; - void setIsMaterializable(bool V); + bool isMaterializable() const { + return getGlobalObjectSubClassData() & (1 << IsMaterializableBit); + } + void setIsMaterializable(bool V) { + unsigned Mask = 1 << IsMaterializableBit; + setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | + (V ? Mask : 0u)); + } /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an @@ -173,42 +184,45 @@ public: } /// @brief Return the attribute list for this Function. - AttributeSet getAttributes() const { return AttributeSets; } + AttributeList getAttributes() const { return AttributeSets; } /// @brief Set the attribute list for this Function. - void setAttributes(AttributeSet Attrs) { AttributeSets = Attrs; } + void setAttributes(AttributeList Attrs) { AttributeSets = Attrs; } /// @brief Add function attributes to this function. void addFnAttr(Attribute::AttrKind Kind) { - addAttribute(AttributeSet::FunctionIndex, Kind); + addAttribute(AttributeList::FunctionIndex, Kind); } /// @brief Add function attributes to this function. void addFnAttr(StringRef Kind, StringRef Val = StringRef()) { - addAttribute(AttributeSet::FunctionIndex, + addAttribute(AttributeList::FunctionIndex, Attribute::get(getContext(), Kind, Val)); } void addFnAttr(Attribute Attr) { - addAttribute(AttributeSet::FunctionIndex, Attr); + addAttribute(AttributeList::FunctionIndex, Attr); } /// @brief Remove function attributes from this function. void removeFnAttr(Attribute::AttrKind Kind) { - removeAttribute(AttributeSet::FunctionIndex, Kind); + removeAttribute(AttributeList::FunctionIndex, Kind); } /// @brief Remove function attribute from this function. void removeFnAttr(StringRef Kind) { setAttributes(AttributeSets.removeAttribute( - getContext(), AttributeSet::FunctionIndex, Kind)); + getContext(), AttributeList::FunctionIndex, Kind)); } /// \brief Set the entry count for this function. /// /// Entry count is the number of times this function was executed based on - /// pgo data. - void setEntryCount(uint64_t Count); + /// pgo data. \p Imports points to a set of GUIDs that needs to be imported + /// by the function for sample PGO, to enable the same inlines as the + /// profiled optimized binary. + void setEntryCount(uint64_t Count, + const DenseSet<GlobalValue::GUID> *Imports = nullptr); /// \brief Get the entry count for this function. /// @@ -216,6 +230,10 @@ public: /// pgo data. Optional<uint64_t> getEntryCount() const; + /// Returns the set of GUIDs that needs to be imported to the function for + /// sample PGO, to enable the same inlines as the profiled optimized binary. + DenseSet<GlobalValue::GUID> getImportGUIDs() const; + /// Set the section prefix for this function. void setSectionPrefix(StringRef Prefix); @@ -232,17 +250,17 @@ public: /// @brief Return the attribute for the given attribute kind. Attribute getFnAttribute(Attribute::AttrKind Kind) const { - return getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeList::FunctionIndex, Kind); } Attribute getFnAttribute(StringRef Kind) const { - return getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeList::FunctionIndex, Kind); } /// \brief Return the stack alignment for the function. unsigned getFnStackAlignment() const { if (!hasFnAttribute(Attribute::StackAlignment)) return 0; - return AttributeSets.getStackAlignment(AttributeSet::FunctionIndex); + return AttributeSets.getStackAlignment(AttributeList::FunctionIndex); } /// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm @@ -261,7 +279,7 @@ public: void addAttribute(unsigned i, Attribute Attr); /// @brief adds the attributes to the list of attributes. - void addAttributes(unsigned i, AttributeSet Attrs); + void addAttributes(unsigned i, AttributeList Attrs); /// @brief removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute::AttrKind Kind); @@ -270,13 +288,18 @@ public: void removeAttribute(unsigned i, StringRef Kind); /// @brief removes the attributes from the list of attributes. - void removeAttributes(unsigned i, AttributeSet Attrs); + void removeAttributes(unsigned i, AttributeList Attrs); /// @brief check if an attributes is in the list of attributes. bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const { return getAttributes().hasAttribute(i, Kind); } + /// @brief check if an attributes is in the list of attributes. + bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const { + return getAttributes().hasParamAttribute(ArgNo, Kind); + } + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { return AttributeSets.getAttribute(i, Kind); } @@ -496,19 +519,6 @@ public: /// Get the underlying elements of the Function... the basic block list is /// empty for external functions. /// - const ArgumentListType &getArgumentList() const { - CheckLazyArguments(); - return ArgumentList; - } - ArgumentListType &getArgumentList() { - CheckLazyArguments(); - return ArgumentList; - } - - static ArgumentListType Function::*getSublistAccess(Argument*) { - return &Function::ArgumentList; - } - const BasicBlockListType &getBasicBlockList() const { return BasicBlocks; } BasicBlockListType &getBasicBlockList() { return BasicBlocks; } @@ -549,20 +559,20 @@ public: arg_iterator arg_begin() { CheckLazyArguments(); - return ArgumentList.begin(); + return Arguments; } const_arg_iterator arg_begin() const { CheckLazyArguments(); - return ArgumentList.begin(); + return Arguments; } arg_iterator arg_end() { CheckLazyArguments(); - return ArgumentList.end(); + return Arguments + NumArgs; } const_arg_iterator arg_end() const { CheckLazyArguments(); - return ArgumentList.end(); + return Arguments + NumArgs; } iterator_range<arg_iterator> args() { @@ -574,8 +584,8 @@ public: /// @} - size_t arg_size() const; - bool arg_empty() const; + size_t arg_size() const { return NumArgs; } + bool arg_empty() const { return arg_size() == 0; } /// \brief Check whether this function has a personality function. bool hasPersonalityFn() const { @@ -671,6 +681,9 @@ public: /// to \a DISubprogram. DISubprogram *getSubprogram() const; + /// Returns true if we should emit debug info for profiling. + bool isDebugInfoForProfiling() const; + private: void allocHungoffUselist(); template<int Idx> void setHungoffOperand(Constant *C); diff --git a/include/llvm/IR/GlobalIndirectSymbol.h b/include/llvm/IR/GlobalIndirectSymbol.h index 671309e85d19..212703af7101 100644 --- a/include/llvm/IR/GlobalIndirectSymbol.h +++ b/include/llvm/IR/GlobalIndirectSymbol.h @@ -48,27 +48,31 @@ public: setOperand(0, Symbol); } const Constant *getIndirectSymbol() const { - return const_cast<GlobalIndirectSymbol *>(this)->getIndirectSymbol(); + return getOperand(0); } Constant *getIndirectSymbol() { - return getOperand(0); + return const_cast<Constant *>( + static_cast<const GlobalIndirectSymbol *>(this)->getIndirectSymbol()); } const GlobalObject *getBaseObject() const { - return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(); + return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets()); } GlobalObject *getBaseObject() { - return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets()); + return const_cast<GlobalObject *>( + static_cast<const GlobalIndirectSymbol *>(this)->getBaseObject()); } const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const { - return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(DL, Offset); - } - GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { return dyn_cast<GlobalObject>( getIndirectSymbol()->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); } + GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { + return const_cast<GlobalObject *>( + static_cast<const GlobalIndirectSymbol *>(this) + ->getBaseObject(DL, Offset)); + } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { diff --git a/include/llvm/IR/GlobalObject.h b/include/llvm/IR/GlobalObject.h index 1057f564aab3..f3789bafefe3 100644 --- a/include/llvm/IR/GlobalObject.h +++ b/include/llvm/IR/GlobalObject.h @@ -63,8 +63,17 @@ public: } void setAlignment(unsigned Align); - unsigned getGlobalObjectSubClassData() const; - void setGlobalObjectSubClassData(unsigned Val); + unsigned getGlobalObjectSubClassData() const { + unsigned ValueData = getGlobalValueSubClassData(); + return ValueData >> GlobalObjectBits; + } + + void setGlobalObjectSubClassData(unsigned Val) { + unsigned OldData = getGlobalValueSubClassData(); + setGlobalValueSubClassData((OldData & GlobalObjectMask) | + (Val << GlobalObjectBits)); + assert(getGlobalObjectSubClassData() == Val && "representation error"); + } /// Check if this global has a custom object file section. /// diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index c6398aaa4847..bb30fa8be867 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -211,9 +211,10 @@ public: } bool hasComdat() const { return getComdat() != nullptr; } - Comdat *getComdat(); - const Comdat *getComdat() const { - return const_cast<GlobalValue *>(this)->getComdat(); + const Comdat *getComdat() const; + Comdat *getComdat() { + return const_cast<Comdat *>( + static_cast<const GlobalValue *>(this)->getComdat()); } VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } @@ -514,10 +515,11 @@ public: // increased. bool canIncreaseAlignment() const; - const GlobalObject *getBaseObject() const { - return const_cast<GlobalValue *>(this)->getBaseObject(); + const GlobalObject *getBaseObject() const; + GlobalObject *getBaseObject() { + return const_cast<GlobalObject *>( + static_cast<const GlobalValue *>(this)->getBaseObject()); } - GlobalObject *getBaseObject(); /// Returns whether this is a reference to an absolute symbol. bool isAbsoluteSymbolRef() const; diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 1d9c16989de9..bc689f3b01d7 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -33,6 +33,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -75,7 +76,7 @@ class IRBuilderCallbackInserter : IRBuilderDefaultInserter { public: IRBuilderCallbackInserter(std::function<void(Instruction *)> Callback) - : Callback(Callback) {} + : Callback(std::move(Callback)) {} protected: void InsertHelper(Instruction *I, const Twine &Name, @@ -560,6 +561,22 @@ public: Type *ResultType, const Twine &Name = ""); + /// Create a call to intrinsic \p ID with 2 operands which is mangled on the + /// first type. + CallInst *CreateBinaryIntrinsic(Intrinsic::ID ID, + Value *LHS, Value *RHS, + const Twine &Name = ""); + + /// Create call to the minnum intrinsic. + CallInst *CreateMinNum(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, Name); + } + + /// Create call to the maxnum intrinsic. + CallInst *CreateMaxNum(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, Name); + } + private: /// \brief Create a call to a masked intrinsic with given Id. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef<Value *> Ops, @@ -1073,9 +1090,15 @@ public: // Instruction creation methods: Memory Instructions //===--------------------------------------------------------------------===// + AllocaInst *CreateAlloca(Type *Ty, unsigned AddrSpace, + Value *ArraySize = nullptr, const Twine &Name = "") { + return Insert(new AllocaInst(Ty, AddrSpace, ArraySize), Name); + } + AllocaInst *CreateAlloca(Type *Ty, Value *ArraySize = nullptr, const Twine &Name = "") { - return Insert(new AllocaInst(Ty, ArraySize), Name); + const DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + return Insert(new AllocaInst(Ty, DL.getAllocaAddrSpace(), ArraySize), Name); } // \brief Provided to resolve 'CreateLoad(Ptr, "...")' correctly, instead of // converting the string to 'bool' for the isVolatile parameter. @@ -1790,24 +1813,16 @@ public: return V; } - /// \brief Create an assume intrinsic call that represents an alignment - /// assumption on the provided pointer. - /// - /// An optional offset can be provided, and if it is provided, the offset - /// must be subtracted from the provided pointer to get the pointer with the - /// specified alignment. - CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, - unsigned Alignment, - Value *OffsetValue = nullptr) { - assert(isa<PointerType>(PtrValue->getType()) && - "trying to create an alignment assumption on a non-pointer?"); - - PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); - Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); +private: + /// \brief Helper function that creates an assume intrinsic call that + /// represents an alignment assumption on the provided Ptr, Mask, Type + /// and Offset. + CallInst *CreateAlignmentAssumptionHelper(const DataLayout &DL, + Value *PtrValue, Value *Mask, + Type *IntPtrTy, + Value *OffsetValue) { Value *PtrIntValue = CreatePtrToInt(PtrValue, IntPtrTy, "ptrint"); - Value *Mask = ConstantInt::get(IntPtrTy, - Alignment > 0 ? Alignment - 1 : 0); if (OffsetValue) { bool IsOffsetZero = false; if (ConstantInt *CI = dyn_cast<ConstantInt>(OffsetValue)) @@ -1824,9 +1839,60 @@ public: Value *Zero = ConstantInt::get(IntPtrTy, 0); Value *MaskedPtr = CreateAnd(PtrIntValue, Mask, "maskedptr"); Value *InvCond = CreateICmpEQ(MaskedPtr, Zero, "maskcond"); - return CreateAssumption(InvCond); } + +public: + /// \brief Create an assume intrinsic call that represents an alignment + /// assumption on the provided pointer. + /// + /// An optional offset can be provided, and if it is provided, the offset + /// must be subtracted from the provided pointer to get the pointer with the + /// specified alignment. + CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, + unsigned Alignment, + Value *OffsetValue = nullptr) { + assert(isa<PointerType>(PtrValue->getType()) && + "trying to create an alignment assumption on a non-pointer?"); + PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); + Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); + + Value *Mask = ConstantInt::get(IntPtrTy, Alignment > 0 ? Alignment - 1 : 0); + return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy, + OffsetValue); + } + // + /// \brief Create an assume intrinsic call that represents an alignment + /// assumption on the provided pointer. + /// + /// An optional offset can be provided, and if it is provided, the offset + /// must be subtracted from the provided pointer to get the pointer with the + /// specified alignment. + /// + /// This overload handles the condition where the Alignment is dependent + /// on an existing value rather than a static value. + CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, + Value *Alignment, + Value *OffsetValue = nullptr) { + assert(isa<PointerType>(PtrValue->getType()) && + "trying to create an alignment assumption on a non-pointer?"); + PointerType *PtrTy = cast<PointerType>(PtrValue->getType()); + Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); + + if (Alignment->getType() != IntPtrTy) + Alignment = CreateIntCast(Alignment, IntPtrTy, /*isSigned*/ true, + "alignmentcast"); + Value *IsPositive = + CreateICmp(CmpInst::ICMP_SGT, Alignment, + ConstantInt::get(Alignment->getType(), 0), "ispositive"); + Value *PositiveMask = + CreateSub(Alignment, ConstantInt::get(IntPtrTy, 1), "positivemask"); + Value *Mask = CreateSelect(IsPositive, PositiveMask, + ConstantInt::get(IntPtrTy, 0), "mask"); + + return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy, + OffsetValue); + } }; // Create wrappers for C Binding types (see CBindingWrapping.h). diff --git a/include/llvm/IR/InlineAsm.h b/include/llvm/IR/InlineAsm.h index f95509b9b09a..5d2f72d211ff 100644 --- a/include/llvm/IR/InlineAsm.h +++ b/include/llvm/IR/InlineAsm.h @@ -1,4 +1,4 @@ -//===-- llvm/InlineAsm.h - Class to represent inline asm strings-*- C++ -*-===// +//===- llvm/InlineAsm.h - Class to represent inline asm strings -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -102,12 +102,14 @@ public: /// input constraint is required to match it (e.g. "0"). The value is the /// constraint number that matches this one (for example, if this is /// constraint #0 and constraint #4 has the value "0", this will be 4). - signed char MatchingInput; + signed char MatchingInput = -1; + /// Code - The constraint code, either the register name (in braces) or the /// constraint letter/number. ConstraintCodeVector Codes; + /// Default constructor. - SubConstraintInfo() : MatchingInput(-1) {} + SubConstraintInfo() = default; }; typedef std::vector<SubConstraintInfo> SubConstraintInfoVector; @@ -117,17 +119,17 @@ public: struct ConstraintInfo { /// Type - The basic type of the constraint: input/output/clobber /// - ConstraintPrefix Type; + ConstraintPrefix Type = isInput; /// isEarlyClobber - "&": output operand writes result before inputs are all /// read. This is only ever set for an output operand. - bool isEarlyClobber; + bool isEarlyClobber = false; /// MatchingInput - If this is not -1, this is an output constraint where an /// input constraint is required to match it (e.g. "0"). The value is the /// constraint number that matches this one (for example, if this is /// constraint #0 and constraint #4 has the value "0", this will be 4). - signed char MatchingInput; + signed char MatchingInput = -1; /// hasMatchingInput - Return true if this is an output constraint that has /// a matching input constraint. @@ -135,30 +137,30 @@ public: /// isCommutative - This is set to true for a constraint that is commutative /// with the next operand. - bool isCommutative; + bool isCommutative = false; /// isIndirect - True if this operand is an indirect operand. This means /// that the address of the source or destination is present in the call /// instruction, instead of it being returned or passed in explicitly. This /// is represented with a '*' in the asm string. - bool isIndirect; + bool isIndirect = false; /// Code - The constraint code, either the register name (in braces) or the /// constraint letter/number. ConstraintCodeVector Codes; /// isMultipleAlternative - '|': has multiple-alternative constraints. - bool isMultipleAlternative; + bool isMultipleAlternative = false; /// multipleAlternatives - If there are multiple alternative constraints, /// this array will contain them. Otherwise it will be empty. SubConstraintInfoVector multipleAlternatives; /// The currently selected alternative constraint index. - unsigned currentAlternativeIndex; + unsigned currentAlternativeIndex = 0; /// Default constructor. - ConstraintInfo(); + ConstraintInfo() = default; /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, diff --git a/include/llvm/IR/InstVisitor.h b/include/llvm/IR/InstVisitor.h index 088d3e0fbfa5..55579819fd34 100644 --- a/include/llvm/IR/InstVisitor.h +++ b/include/llvm/IR/InstVisitor.h @@ -116,6 +116,9 @@ public: // visit - Finally, code to visit an instruction... // RetTy visit(Instruction &I) { + static_assert(std::is_base_of<InstVisitor, SubClass>::value, + "Must pass the derived type to this template!"); + switch (I.getOpcode()) { default: llvm_unreachable("Unknown instruction type encountered!"); // Build the switch statement using the Instruction.def file... diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index f2abbec64fe6..518094735d72 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -1061,13 +1061,13 @@ public: /// @brief Determine if Pred1 implies Pred2 is true when two compares have /// matching operands. - bool isImpliedTrueByMatchingCmp(Predicate Pred2) { + bool isImpliedTrueByMatchingCmp(Predicate Pred2) const { return isImpliedTrueByMatchingCmp(getPredicate(), Pred2); } /// @brief Determine if Pred1 implies Pred2 is false when two compares have /// matching operands. - bool isImpliedFalseByMatchingCmp(Predicate Pred2) { + bool isImpliedFalseByMatchingCmp(Predicate Pred2) const { return isImpliedFalseByMatchingCmp(getPredicate(), Pred2); } diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index fd7c54d69b63..90c3175122fd 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -68,14 +68,20 @@ public: /// Note: this is undefined behavior if the instruction does not have a /// parent, or the parent basic block does not have a parent function. const Module *getModule() const; - Module *getModule(); + Module *getModule() { + return const_cast<Module *>( + static_cast<const Instruction *>(this)->getModule()); + } /// Return the function this instruction belongs to. /// /// Note: it is undefined behavior to call this on an instruction not /// currently inserted into a function. const Function *getFunction() const; - Function *getFunction(); + Function *getFunction() { + return const_cast<Function *>( + static_cast<const Instruction *>(this)->getFunction()); + } /// This method unlinks 'this' from the containing basic block, but does not /// delete it. @@ -252,6 +258,12 @@ public: /// Returns false if no metadata was found. bool extractProfTotalWeight(uint64_t &TotalVal) const; + /// Updates branch_weights metadata by scaling it by \p S / \p T. + void updateProfWeight(uint64_t S, uint64_t T); + + /// Sets the branch_weights metadata to \p W for CallInst. + void setProfWeight(uint64_t W); + /// Set the debug location information for this instruction. void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); } @@ -276,6 +288,10 @@ public: /// Determine whether the no signed wrap flag is set. bool hasNoSignedWrap() const; + /// Drops flags that may cause this instruction to evaluate to poison despite + /// having non-poison inputs. + void dropPoisonGeneratingFlags(); + /// Determine whether the exact flag is set. bool isExact() const; @@ -329,6 +345,9 @@ public: /// Determine whether the allow-reciprocal flag is set. bool hasAllowReciprocal() const; + /// Determine whether the allow-contract flag is set. + bool hasAllowContract() const; + /// Convenience function for getting all the fast-math flags, which must be an /// operator which supports these flags. See LangRef.html for the meaning of /// these flags. @@ -372,18 +391,30 @@ public: /// /// In LLVM, the Add, Mul, And, Or, and Xor operators are associative. /// - bool isAssociative() const; - static bool isAssociative(unsigned op); + bool isAssociative() const LLVM_READONLY; + static bool isAssociative(unsigned Opcode) { + return Opcode == And || Opcode == Or || Opcode == Xor || + Opcode == Add || Opcode == Mul; + } /// Return true if the instruction is commutative: /// /// Commutative operators satisfy: (x op y) === (y op x) /// - /// In LLVM, these are the associative operators, plus SetEQ and SetNE, when + /// In LLVM, these are the commutative operators, plus SetEQ and SetNE, when /// applied to any type. /// bool isCommutative() const { return isCommutative(getOpcode()); } - static bool isCommutative(unsigned op); + static bool isCommutative(unsigned Opcode) { + switch (Opcode) { + case Add: case FAdd: + case Mul: case FMul: + case And: case Or: case Xor: + return true; + default: + return false; + } + } /// Return true if the instruction is idempotent: /// @@ -392,7 +423,9 @@ public: /// In LLVM, the And and Or operators are idempotent. /// bool isIdempotent() const { return isIdempotent(getOpcode()); } - static bool isIdempotent(unsigned op); + static bool isIdempotent(unsigned Opcode) { + return Opcode == And || Opcode == Or; + } /// Return true if the instruction is nilpotent: /// @@ -404,7 +437,9 @@ public: /// In LLVM, the Xor operator is nilpotent. /// bool isNilpotent() const { return isNilpotent(getOpcode()); } - static bool isNilpotent(unsigned op); + static bool isNilpotent(unsigned Opcode) { + return Opcode == Xor; + } /// Return true if this instruction may modify memory. bool mayWriteToMemory() const; diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index a5d78a08171a..34dafebe0fc5 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -67,18 +67,21 @@ protected: AllocaInst *cloneImpl() const; public: - explicit AllocaInst(Type *Ty, Value *ArraySize = nullptr, + explicit AllocaInst(Type *Ty, unsigned AddrSpace, + Value *ArraySize = nullptr, const Twine &Name = "", Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, Value *ArraySize, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, const Twine &Name, BasicBlock *InsertAtEnd); - AllocaInst(Type *Ty, const Twine &Name, Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd); + AllocaInst(Type *Ty, unsigned AddrSpace, + const Twine &Name, Instruction *InsertBefore = nullptr); + AllocaInst(Type *Ty, unsigned AddrSpace, + const Twine &Name, BasicBlock *InsertAtEnd); - AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align, const Twine &Name = "", Instruction *InsertBefore = nullptr); - AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, + AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align, const Twine &Name, BasicBlock *InsertAtEnd); // Out of line virtual method, so the vtable, etc. has a home. @@ -958,6 +961,14 @@ public: inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return op_end(); } + inline iterator_range<op_iterator> indices() { + return make_range(idx_begin(), idx_end()); + } + + inline iterator_range<const_op_iterator> indices() const { + return make_range(idx_begin(), idx_end()); + } + Value *getPointerOperand() { return getOperand(0); } @@ -1354,7 +1365,7 @@ class CallInst : public Instruction, public OperandBundleUser<CallInst, User::op_iterator> { friend class OperandBundleUser<CallInst, User::op_iterator>; - AttributeSet AttributeList; ///< parameter attributes for call + AttributeList Attrs; ///< parameter attributes for call FunctionType *FTy; CallInst(const CallInst &CI); @@ -1633,11 +1644,11 @@ public: /// Return the parameter attributes for this call. /// - AttributeSet getAttributes() const { return AttributeList; } + AttributeList getAttributes() const { return Attrs; } /// Set the parameter attributes for this call. /// - void setAttributes(AttributeSet Attrs) { AttributeList = Attrs; } + void setAttributes(AttributeList A) { Attrs = A; } /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind Kind); @@ -1670,8 +1681,11 @@ public: return hasFnAttrImpl(Kind); } - /// Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + /// Determine whether the return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const; + + /// Determine whether the argument or parameter has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const; /// Get the attribute of a given kind at a position. Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -1700,26 +1714,26 @@ public: /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { - return AttributeList.getParamAlignment(i); + return Attrs.getParamAlignment(i); } /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { - return AttributeList.getDereferenceableBytes(i); + return Attrs.getDereferenceableBytes(i); } /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { - return AttributeList.getDereferenceableOrNullBytes(i); + return Attrs.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { - return AttributeList.hasAttribute(n, Attribute::NoAlias); + return Attrs.hasAttribute(n, Attribute::NoAlias); } /// Return true if the call should not be treated as a call to a @@ -1732,7 +1746,7 @@ public: /// Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); + addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); } /// Return true if the call can return twice @@ -1740,7 +1754,7 @@ public: return hasFnAttr(Attribute::ReturnsTwice); } void setCanReturnTwice() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReturnsTwice); + addAttribute(AttributeList::FunctionIndex, Attribute::ReturnsTwice); } /// Determine if the call does not access memory. @@ -1748,7 +1762,7 @@ public: return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone); } /// Determine if the call does not access or only reads memory. @@ -1756,7 +1770,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly); } /// Determine if the call does not access or only writes memory. @@ -1764,7 +1778,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); } void setDoesNotReadMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::WriteOnly); } /// @brief Determine if the call can access memmory only using pointers based @@ -1773,34 +1787,34 @@ public: return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ArgMemOnly); } /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); + addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); + addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind); } /// Determine if the call cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); + addAttribute(AttributeList::FunctionIndex, Attribute::NoDuplicate); } /// Determine if the call is convergent bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } void setConvergent() { - addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + addAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } void setNotConvergent() { - removeAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + removeAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } /// Determine if the call returns a structure through first @@ -1810,12 +1824,12 @@ public: return false; // Be friendly and also check the callee. - return paramHasAttr(1, Attribute::StructRet); + return paramHasAttr(0, Attribute::StructRet); } /// Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { - return AttributeList.hasAttrSomewhere(Attribute::ByVal); + return Attrs.hasAttrSomewhere(Attribute::ByVal); } /// Return the function called, or null if this is an @@ -1858,7 +1872,7 @@ public: private: template <typename AttrKind> bool hasFnAttrImpl(AttrKind Kind) const { - if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, Kind)) + if (Attrs.hasAttribute(AttributeList::FunctionIndex, Kind)) return true; // Operand bundles override attributes on the called function, but don't @@ -1867,7 +1881,8 @@ private: return false; if (const Function *F = getCalledFunction()) - return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Kind); + return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, + Kind); return false; } @@ -3084,42 +3099,41 @@ public: // -2 static const unsigned DefaultPseudoIndex = static_cast<unsigned>(~0L-1); - template <class SwitchInstTy, class ConstantIntTy, class BasicBlockTy> - class CaseIteratorT { - protected: - SwitchInstTy *SI; - unsigned Index; + template <typename CaseHandleT> class CaseIteratorImpl; - public: - typedef CaseIteratorT<SwitchInstTy, ConstantIntTy, BasicBlockTy> Self; + /// A handle to a particular switch case. It exposes a convenient interface + /// to both the case value and the successor block. + /// + /// We define this as a template and instantiate it to form both a const and + /// non-const handle. + template <typename SwitchInstT, typename ConstantIntT, typename BasicBlockT> + class CaseHandleImpl { + // Directly befriend both const and non-const iterators. + friend class SwitchInst::CaseIteratorImpl< + CaseHandleImpl<SwitchInstT, ConstantIntT, BasicBlockT>>; - /// Initializes case iterator for given SwitchInst and for given - /// case number. - CaseIteratorT(SwitchInstTy *SI, unsigned CaseNum) { - this->SI = SI; - Index = CaseNum; - } + protected: + // Expose the switch type we're parameterized with to the iterator. + typedef SwitchInstT SwitchInstType; - /// Initializes case iterator for given SwitchInst and for given - /// TerminatorInst's successor index. - static Self fromSuccessorIndex(SwitchInstTy *SI, unsigned SuccessorIndex) { - assert(SuccessorIndex < SI->getNumSuccessors() && - "Successor index # out of range!"); - return SuccessorIndex != 0 ? - Self(SI, SuccessorIndex - 1) : - Self(SI, DefaultPseudoIndex); - } + SwitchInstT *SI; + ptrdiff_t Index; + + CaseHandleImpl() = default; + CaseHandleImpl(SwitchInstT *SI, ptrdiff_t Index) : SI(SI), Index(Index) {} + public: /// Resolves case value for current case. - ConstantIntTy *getCaseValue() { - assert(Index < SI->getNumCases() && "Index out the number of cases."); - return reinterpret_cast<ConstantIntTy*>(SI->getOperand(2 + Index*2)); + ConstantIntT *getCaseValue() const { + assert((unsigned)Index < SI->getNumCases() && + "Index out the number of cases."); + return reinterpret_cast<ConstantIntT *>(SI->getOperand(2 + Index * 2)); } /// Resolves successor for current case. - BasicBlockTy *getCaseSuccessor() { - assert((Index < SI->getNumCases() || - Index == DefaultPseudoIndex) && + BasicBlockT *getCaseSuccessor() const { + assert(((unsigned)Index < SI->getNumCases() || + (unsigned)Index == DefaultPseudoIndex) && "Index out the number of cases."); return SI->getSuccessor(getSuccessorIndex()); } @@ -3129,63 +3143,32 @@ public: /// Returns TerminatorInst's successor index for current case successor. unsigned getSuccessorIndex() const { - assert((Index == DefaultPseudoIndex || Index < SI->getNumCases()) && + assert(((unsigned)Index == DefaultPseudoIndex || + (unsigned)Index < SI->getNumCases()) && "Index out the number of cases."); - return Index != DefaultPseudoIndex ? Index + 1 : 0; + return (unsigned)Index != DefaultPseudoIndex ? Index + 1 : 0; } - Self operator++() { - // Check index correctness after increment. - // Note: Index == getNumCases() means end(). - assert(Index+1 <= SI->getNumCases() && "Index out the number of cases."); - ++Index; - return *this; - } - Self operator++(int) { - Self tmp = *this; - ++(*this); - return tmp; - } - Self operator--() { - // Check index correctness after decrement. - // Note: Index == getNumCases() means end(). - // Also allow "-1" iterator here. That will became valid after ++. - assert((Index == 0 || Index-1 <= SI->getNumCases()) && - "Index out the number of cases."); - --Index; - return *this; - } - Self operator--(int) { - Self tmp = *this; - --(*this); - return tmp; - } - bool operator==(const Self& RHS) const { - assert(RHS.SI == SI && "Incompatible operators."); - return RHS.Index == Index; - } - bool operator!=(const Self& RHS) const { - assert(RHS.SI == SI && "Incompatible operators."); - return RHS.Index != Index; - } - Self &operator*() { - return *this; + bool operator==(const CaseHandleImpl &RHS) const { + assert(SI == RHS.SI && "Incompatible operators."); + return Index == RHS.Index; } }; - typedef CaseIteratorT<const SwitchInst, const ConstantInt, const BasicBlock> - ConstCaseIt; + typedef CaseHandleImpl<const SwitchInst, const ConstantInt, const BasicBlock> + ConstCaseHandle; - class CaseIt : public CaseIteratorT<SwitchInst, ConstantInt, BasicBlock> { - typedef CaseIteratorT<SwitchInst, ConstantInt, BasicBlock> ParentTy; + class CaseHandle + : public CaseHandleImpl<SwitchInst, ConstantInt, BasicBlock> { + friend class SwitchInst::CaseIteratorImpl<CaseHandle>; public: - CaseIt(const ParentTy &Src) : ParentTy(Src) {} - CaseIt(SwitchInst *SI, unsigned CaseNum) : ParentTy(SI, CaseNum) {} + CaseHandle(SwitchInst *SI, ptrdiff_t Index) : CaseHandleImpl(SI, Index) {} /// Sets the new value for current case. void setValue(ConstantInt *V) { - assert(Index < SI->getNumCases() && "Index out the number of cases."); + assert((unsigned)Index < SI->getNumCases() && + "Index out the number of cases."); SI->setOperand(2 + Index*2, reinterpret_cast<Value*>(V)); } @@ -3195,6 +3178,76 @@ public: } }; + template <typename CaseHandleT> + class CaseIteratorImpl + : public iterator_facade_base<CaseIteratorImpl<CaseHandleT>, + std::random_access_iterator_tag, + CaseHandleT> { + typedef typename CaseHandleT::SwitchInstType SwitchInstT; + + CaseHandleT Case; + + public: + /// Default constructed iterator is in an invalid state until assigned to + /// a case for a particular switch. + CaseIteratorImpl() = default; + + /// Initializes case iterator for given SwitchInst and for given + /// case number. + CaseIteratorImpl(SwitchInstT *SI, unsigned CaseNum) : Case(SI, CaseNum) {} + + /// Initializes case iterator for given SwitchInst and for given + /// TerminatorInst's successor index. + static CaseIteratorImpl fromSuccessorIndex(SwitchInstT *SI, + unsigned SuccessorIndex) { + assert(SuccessorIndex < SI->getNumSuccessors() && + "Successor index # out of range!"); + return SuccessorIndex != 0 ? CaseIteratorImpl(SI, SuccessorIndex - 1) + : CaseIteratorImpl(SI, DefaultPseudoIndex); + } + + /// Support converting to the const variant. This will be a no-op for const + /// variant. + operator CaseIteratorImpl<ConstCaseHandle>() const { + return CaseIteratorImpl<ConstCaseHandle>(Case.SI, Case.Index); + } + + CaseIteratorImpl &operator+=(ptrdiff_t N) { + // Check index correctness after addition. + // Note: Index == getNumCases() means end(). + assert(Case.Index + N >= 0 && + (unsigned)(Case.Index + N) <= Case.SI->getNumCases() && + "Case.Index out the number of cases."); + Case.Index += N; + return *this; + } + CaseIteratorImpl &operator-=(ptrdiff_t N) { + // Check index correctness after subtraction. + // Note: Case.Index == getNumCases() means end(). + assert(Case.Index - N >= 0 && + (unsigned)(Case.Index - N) <= Case.SI->getNumCases() && + "Case.Index out the number of cases."); + Case.Index -= N; + return *this; + } + ptrdiff_t operator-(const CaseIteratorImpl &RHS) const { + assert(Case.SI == RHS.Case.SI && "Incompatible operators."); + return Case.Index - RHS.Case.Index; + } + bool operator==(const CaseIteratorImpl &RHS) const { + return Case == RHS.Case; + } + bool operator<(const CaseIteratorImpl &RHS) const { + assert(Case.SI == RHS.Case.SI && "Incompatible operators."); + return Case.Index < RHS.Case.Index; + } + CaseHandleT &operator*() { return Case; } + const CaseHandleT &operator*() const { return Case; } + }; + + typedef CaseIteratorImpl<CaseHandle> CaseIt; + typedef CaseIteratorImpl<ConstCaseHandle> ConstCaseIt; + static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore = nullptr) { @@ -3278,30 +3331,40 @@ public: /// default case iterator to indicate that it is handled by the default /// handler. CaseIt findCaseValue(const ConstantInt *C) { - for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValue() == C) - return i; + CaseIt I = llvm::find_if( + cases(), [C](CaseHandle &Case) { return Case.getCaseValue() == C; }); + if (I != case_end()) + return I; + return case_default(); } ConstCaseIt findCaseValue(const ConstantInt *C) const { - for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValue() == C) - return i; + ConstCaseIt I = llvm::find_if(cases(), [C](ConstCaseHandle &Case) { + return Case.getCaseValue() == C; + }); + if (I != case_end()) + return I; + return case_default(); } /// Finds the unique case value for a given successor. Returns null if the /// successor is not found, not unique, or is the default case. ConstantInt *findCaseDest(BasicBlock *BB) { - if (BB == getDefaultDest()) return nullptr; + if (BB == getDefaultDest()) + return nullptr; ConstantInt *CI = nullptr; - for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) { - if (i.getCaseSuccessor() == BB) { - if (CI) return nullptr; // Multiple cases lead to BB. - else CI = i.getCaseValue(); - } + for (auto Case : cases()) { + if (Case.getCaseSuccessor() != BB) + continue; + + if (CI) + return nullptr; // Multiple cases lead to BB. + + CI = Case.getCaseValue(); } + return CI; } @@ -3316,8 +3379,9 @@ public: /// index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, - /// including the case_end() iterator. - void removeCase(CaseIt i); + /// including the case_end() iterator. It returns an iterator for the next + /// case. + CaseIt removeCase(CaseIt I); unsigned getNumSuccessors() const { return getNumOperands()/2; } BasicBlock *getSuccessor(unsigned idx) const { @@ -3465,7 +3529,7 @@ class InvokeInst : public TerminatorInst, public OperandBundleUser<InvokeInst, User::op_iterator> { friend class OperandBundleUser<InvokeInst, User::op_iterator>; - AttributeSet AttributeList; + AttributeList Attrs; FunctionType *FTy; InvokeInst(const InvokeInst &BI); @@ -3669,11 +3733,11 @@ public: /// Return the parameter attributes for this invoke. /// - AttributeSet getAttributes() const { return AttributeList; } + AttributeList getAttributes() const { return Attrs; } /// Set the parameter attributes for this invoke. /// - void setAttributes(AttributeSet Attrs) { AttributeList = Attrs; } + void setAttributes(AttributeList A) { Attrs = A; } /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind Kind); @@ -3706,8 +3770,11 @@ public: return hasFnAttrImpl(Kind); } - /// Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + /// Determine whether the return value has the given attribute. + bool hasRetAttr(Attribute::AttrKind Kind) const; + + /// Determine whether the argument or parameter has the given attribute. + bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const; /// Get the attribute of a given kind at a position. Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { @@ -3737,26 +3804,26 @@ public: /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { - return AttributeList.getParamAlignment(i); + return Attrs.getParamAlignment(i); } /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { - return AttributeList.getDereferenceableBytes(i); + return Attrs.getDereferenceableBytes(i); } /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { - return AttributeList.getDereferenceableOrNullBytes(i); + return Attrs.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { - return AttributeList.hasAttribute(n, Attribute::NoAlias); + return Attrs.hasAttribute(n, Attribute::NoAlias); } /// Return true if the call should not be treated as a call to a @@ -3771,7 +3838,7 @@ public: /// Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); + addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); } /// Determine if the call does not access memory. @@ -3779,7 +3846,7 @@ public: return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone); } /// Determine if the call does not access or only reads memory. @@ -3787,7 +3854,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ReadOnly); } /// Determine if the call does not access or only writes memory. @@ -3795,7 +3862,7 @@ public: return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); } void setDoesNotReadMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::WriteOnly); } /// @brief Determine if the call access memmory only using it's pointer @@ -3804,34 +3871,34 @@ public: return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { - addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); + addAttribute(AttributeList::FunctionIndex, Attribute::ArgMemOnly); } /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); + addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); + addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind); } /// Determine if the invoke cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { - addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); + addAttribute(AttributeList::FunctionIndex, Attribute::NoDuplicate); } /// Determine if the invoke is convergent bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } void setConvergent() { - addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + addAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } void setNotConvergent() { - removeAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + removeAttribute(AttributeList::FunctionIndex, Attribute::Convergent); } /// Determine if the call returns a structure through first @@ -3841,12 +3908,12 @@ public: return false; // Be friendly and also check the callee. - return paramHasAttr(1, Attribute::StructRet); + return paramHasAttr(0, Attribute::StructRet); } /// Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { - return AttributeList.hasAttrSomewhere(Attribute::ByVal); + return Attrs.hasAttrSomewhere(Attribute::ByVal); } /// Return the function called, or null if this is an @@ -3918,7 +3985,7 @@ private: void setSuccessorV(unsigned idx, BasicBlock *B) override; template <typename AttrKind> bool hasFnAttrImpl(AttrKind Kind) const { - if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, Kind)) + if (Attrs.hasAttribute(AttributeList::FunctionIndex, Kind)) return true; // Operand bundles override attributes on the called function, but don't @@ -3927,7 +3994,8 @@ private: return false; if (const Function *F = getCalledFunction()) - return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Kind); + return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, + Kind); return false; } diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index b14a54503e52..f69b5bfc0be2 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -152,6 +152,71 @@ namespace llvm { } }; + /// This is the common base class for constrained floating point intrinsics. + class ConstrainedFPIntrinsic : public IntrinsicInst { + public: + enum RoundingMode { + rmInvalid, + rmDynamic, + rmToNearest, + rmDownward, + rmUpward, + rmTowardZero + }; + + enum ExceptionBehavior { + ebInvalid, + ebIgnore, + ebMayTrap, + ebStrict + }; + + RoundingMode getRoundingMode() const; + ExceptionBehavior getExceptionBehavior() const; + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const IntrinsicInst *I) { + switch (I->getIntrinsicID()) { + case Intrinsic::experimental_constrained_fadd: + case Intrinsic::experimental_constrained_fsub: + case Intrinsic::experimental_constrained_fmul: + case Intrinsic::experimental_constrained_fdiv: + case Intrinsic::experimental_constrained_frem: + return true; + default: return false; + } + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } + }; + + /// This class represents atomic memcpy intrinsic + /// TODO: Integrate this class into MemIntrinsic hierarchy. + class ElementAtomicMemCpyInst : public IntrinsicInst { + public: + Value *getRawDest() const { return getArgOperand(0); } + Value *getRawSource() const { return getArgOperand(1); } + + Value *getNumElements() const { return getArgOperand(2); } + void setNumElements(Value *V) { setArgOperand(2, V); } + + uint64_t getSrcAlignment() const { return getParamAlignment(1); } + uint64_t getDstAlignment() const { return getParamAlignment(2); } + + uint64_t getElementSizeInBytes() const { + Value *Arg = getArgOperand(3); + return cast<ConstantInt>(Arg)->getZExtValue(); + } + + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::memcpy_element_atomic; + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } + }; + /// This is the common base class for memset/memcpy/memmove. class MemIntrinsic : public IntrinsicInst { public: diff --git a/include/llvm/IR/Intrinsics.h b/include/llvm/IR/Intrinsics.h index d07358445dab..2f6bdf8ecf19 100644 --- a/include/llvm/IR/Intrinsics.h +++ b/include/llvm/IR/Intrinsics.h @@ -28,7 +28,7 @@ class FunctionType; class Function; class LLVMContext; class Module; -class AttributeSet; +class AttributeList; /// This namespace contains an enum with a value for every intrinsic/builtin /// function known by LLVM. The enum values are returned by @@ -69,7 +69,7 @@ namespace Intrinsic { bool isLeaf(ID id); /// Return the attributes for an intrinsic. - AttributeSet getAttributes(LLVMContext &C, ID id); + AttributeList getAttributes(LLVMContext &C, ID id); /// Create or insert an LLVM Function declaration for an intrinsic, and return /// it. diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 89ae94270888..309b21489224 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -331,13 +331,13 @@ def int_get_dynamic_area_offset : Intrinsic<[llvm_anyint_ty]>; def int_thread_pointer : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>, GCCBuiltin<"__builtin_thread_pointer">; -// IntrArgMemOnly is more pessimistic than strictly necessary for prefetch, -// however it does conveniently prevent the prefetch from being reordered -// with respect to nearby accesses to the same memory. -def int_prefetch : Intrinsic<[], - [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty], - [IntrArgMemOnly, NoCapture<0>]>; +// IntrInaccessibleMemOrArgMemOnly is a little more pessimistic than strictly +// necessary for prefetch, however it does conveniently prevent the prefetch +// from being reordered overly much with respect to nearby access to the same +// memory while not impeding optimization. +def int_prefetch + : Intrinsic<[], [ llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], + [ IntrInaccessibleMemOrArgMemOnly, ReadOnly<0>, NoCapture<0> ]>; def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; @@ -389,6 +389,9 @@ def int_memset : Intrinsic<[], llvm_i32_ty, llvm_i1_ty], [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>; +// FIXME: Add version of these floating point intrinsics which allow non-default +// rounding modes and FP exception handling. + let IntrProperties = [IntrNoMem] in { def int_fma : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, @@ -438,10 +441,44 @@ def int_sigsetjmp : Intrinsic<[llvm_i32_ty] , [llvm_ptr_ty, llvm_i32_ty]>; def int_siglongjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>; // Internal interface for object size checking -def int_objectsize : Intrinsic<[llvm_anyint_ty], [llvm_anyptr_ty, llvm_i1_ty], +def int_objectsize : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, llvm_i1_ty, llvm_i1_ty], [IntrNoMem]>, GCCBuiltin<"__builtin_object_size">; +//===--------------- Constrained Floating Point Intrinsics ----------------===// +// + +let IntrProperties = [IntrInaccessibleMemOnly] in { + def int_experimental_constrained_fadd : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fsub : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fmul : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_fdiv : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; + def int_experimental_constrained_frem : Intrinsic<[ llvm_anyfloat_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_metadata_ty, + llvm_metadata_ty ]>; +} +// FIXME: Add intrinsic for fcmp, fptrunc, fpext, fptoui and fptosi. + + //===------------------------- Expect Intrinsics --------------------------===// // def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, @@ -565,10 +602,10 @@ def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], //===------------------------- Memory Use Markers -------------------------===// // def int_lifetime_start : Intrinsic<[], - [llvm_i64_ty, llvm_ptr_ty], + [llvm_i64_ty, llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_lifetime_end : Intrinsic<[], - [llvm_i64_ty, llvm_ptr_ty], + [llvm_i64_ty, llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_anyptr_ty], @@ -578,9 +615,16 @@ def int_invariant_end : Intrinsic<[], llvm_anyptr_ty], [IntrArgMemOnly, NoCapture<2>]>; +// invariant.group.barrier can't be marked with 'readnone' (IntrNoMem), +// because it would cause CSE of two barriers with the same argument. +// Readonly and argmemonly says that barrier only reads its argument and +// it can be CSE only if memory didn't change between 2 barriers call, +// which is valid. +// The argument also can't be marked with 'returned' attribute, because +// it would remove barrier. def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], - [IntrNoMem]>; + [IntrReadMem, IntrArgMemOnly]>; //===------------------------ Stackmap Intrinsics -------------------------===// // @@ -619,18 +663,18 @@ def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty], // Coroutine Structure Intrinsics. -def int_coro_id : Intrinsic<[llvm_token_ty], [llvm_i32_ty, llvm_ptr_ty, - llvm_ptr_ty, llvm_ptr_ty], - [IntrArgMemOnly, IntrReadMem, +def int_coro_id : Intrinsic<[llvm_token_ty], [llvm_i32_ty, llvm_ptr_ty, + llvm_ptr_ty, llvm_ptr_ty], + [IntrArgMemOnly, IntrReadMem, ReadNone<1>, ReadOnly<2>, NoCapture<2>]>; def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], []>; def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], [WriteOnly<1>]>; -def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], - [IntrReadMem, IntrArgMemOnly, ReadOnly<1>, +def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], + [IntrReadMem, IntrArgMemOnly, ReadOnly<1>, NoCapture<1>]>; -def int_coro_end : Intrinsic<[], [llvm_ptr_ty, llvm_i1_ty], []>; +def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []>; def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>; @@ -745,6 +789,10 @@ def int_memcpy_element_atomic : Intrinsic<[], [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, WriteOnly<0>, ReadOnly<1>]>; +//===----- Intrinsics that are used to provide predicate information -----===// + +def int_ssa_copy : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], + [IntrNoMem, Returned<0>]>; //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// diff --git a/include/llvm/IR/IntrinsicsAMDGPU.td b/include/llvm/IR/IntrinsicsAMDGPU.td index dcec3860f2ca..5415c6b0d151 100644 --- a/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/include/llvm/IR/IntrinsicsAMDGPU.td @@ -64,6 +64,10 @@ def int_r600_recipsqrt_clamped : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_r600_cube : Intrinsic< + [llvm_v4f32_ty], [llvm_v4f32_ty], [IntrNoMem] +>; + } // End TargetPrefix = "r600" let TargetPrefix = "amdgcn" in { @@ -121,7 +125,8 @@ def int_amdgcn_s_barrier : GCCBuiltin<"__builtin_amdgcn_s_barrier">, def int_amdgcn_wave_barrier : GCCBuiltin<"__builtin_amdgcn_wave_barrier">, Intrinsic<[], [], [IntrConvergent]>; -def int_amdgcn_s_waitcnt : Intrinsic<[], [llvm_i32_ty], []>; +def int_amdgcn_s_waitcnt : GCCBuiltin<"__builtin_amdgcn_s_waitcnt">, + Intrinsic<[], [llvm_i32_ty], []>; def int_amdgcn_div_scale : Intrinsic< // 1st parameter: Numerator @@ -202,10 +207,19 @@ def int_amdgcn_fract : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_amdgcn_cvt_pkrtz : Intrinsic< + [llvm_v2f16_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; + def int_amdgcn_class : Intrinsic< [llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem] >; +def int_amdgcn_fmed3 : GCCBuiltin<"__builtin_amdgcn_fmed3">, + Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem] +>; + def int_amdgcn_cubeid : GCCBuiltin<"__builtin_amdgcn_cubeid">, Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] @@ -231,17 +245,20 @@ def int_amdgcn_cubetc : GCCBuiltin<"__builtin_amdgcn_cubetc">, def int_amdgcn_sffbh : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], [IntrNoMem]>; -// TODO: Do we want an ordering for these? -def int_amdgcn_atomic_inc : Intrinsic<[llvm_anyint_ty], - [llvm_anyptr_ty, LLVMMatchType<0>], - [IntrArgMemOnly, NoCapture<0>] ->; -def int_amdgcn_atomic_dec : Intrinsic<[llvm_anyint_ty], - [llvm_anyptr_ty, LLVMMatchType<0>], +// Fields should mirror atomicrmw +class AMDGPUAtomicIncIntrin : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, + LLVMMatchType<0>, + llvm_i32_ty, // ordering + llvm_i32_ty, // scope + llvm_i1_ty], // isVolatile [IntrArgMemOnly, NoCapture<0>] >; +def int_amdgcn_atomic_inc : AMDGPUAtomicIncIntrin; +def int_amdgcn_atomic_dec : AMDGPUAtomicIncIntrin; + class AMDGPUImageLoad : Intrinsic < [llvm_anyfloat_ty], // vdata(VGPR) [llvm_anyint_ty, // vaddr(VGPR) @@ -451,6 +468,32 @@ def int_amdgcn_buffer_atomic_cmpswap : Intrinsic< llvm_i1_ty], // slc(imm) []>; +// Uses that do not set the done bit should set IntrWriteMem on the +// call site. +def int_amdgcn_exp : Intrinsic <[], [ + llvm_i32_ty, // tgt, + llvm_i32_ty, // en + llvm_any_ty, // src0 (f32 or i32) + LLVMMatchType<0>, // src1 + LLVMMatchType<0>, // src2 + LLVMMatchType<0>, // src3 + llvm_i1_ty, // done + llvm_i1_ty // vm + ], + [] +>; + +// exp with compr bit set. +def int_amdgcn_exp_compr : Intrinsic <[], [ + llvm_i32_ty, // tgt, + llvm_i32_ty, // en + llvm_anyvector_ty, // src0 (v2f16 or v2i16) + LLVMMatchType<0>, // src1 + llvm_i1_ty, // done + llvm_i1_ty], // vm + [] +>; + def int_amdgcn_buffer_wbinvl1_sc : GCCBuiltin<"__builtin_amdgcn_buffer_wbinvl1_sc">, Intrinsic<[], [], []>; @@ -530,7 +573,14 @@ def int_amdgcn_ds_swizzle : GCCBuiltin<"__builtin_amdgcn_ds_swizzle">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; -// llvm.amdgcn.lerp +def int_amdgcn_ubfe : Intrinsic<[llvm_anyint_ty], + [LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], [IntrNoMem] +>; + +def int_amdgcn_sbfe : Intrinsic<[llvm_anyint_ty], + [LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], [IntrNoMem] +>; + def int_amdgcn_lerp : GCCBuiltin<"__builtin_amdgcn_lerp">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; @@ -619,10 +669,51 @@ def int_amdgcn_s_memrealtime : // llvm.amdgcn.ds.permute <index> <src> def int_amdgcn_ds_permute : + GCCBuiltin<"__builtin_amdgcn_ds_permute">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; // llvm.amdgcn.ds.bpermute <index> <src> def int_amdgcn_ds_bpermute : + GCCBuiltin<"__builtin_amdgcn_ds_bpermute">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; + +//===----------------------------------------------------------------------===// +// Special Intrinsics for backend internal use only. No frontend +// should emit calls to these. +// ===----------------------------------------------------------------------===// +def int_amdgcn_if : Intrinsic<[llvm_i1_ty, llvm_i64_ty], + [llvm_i1_ty], [IntrConvergent] +>; + +def int_amdgcn_else : Intrinsic<[llvm_i1_ty, llvm_i64_ty], + [llvm_i64_ty], [IntrConvergent] +>; + +def int_amdgcn_break : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_if_break : Intrinsic<[llvm_i64_ty], + [llvm_i1_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_else_break : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent] +>; + +def int_amdgcn_loop : Intrinsic<[llvm_i1_ty], + [llvm_i64_ty], [IntrConvergent] +>; + +def int_amdgcn_end_cf : Intrinsic<[], [llvm_i64_ty], [IntrConvergent]>; + +// Represent unreachable in a divergent region. +def int_amdgcn_unreachable : Intrinsic<[], [], [IntrConvergent]>; + +// Emit 2.5 ulp, no denormal division. Should only be inserted by +// pass based on !fpmath metadata. +def int_amdgcn_fdiv_fast : Intrinsic< + [llvm_float_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem] +>; } diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index 24239689a62e..18ed24be56d4 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -67,7 +67,7 @@ def int_arm_isb : GCCBuiltin<"__builtin_arm_isb">, MSBuiltin<"__isb">, // VFP def int_arm_get_fpscr : GCCBuiltin<"__builtin_arm_get_fpscr">, - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; + Intrinsic<[llvm_i32_ty], [], []>; def int_arm_set_fpscr : GCCBuiltin<"__builtin_arm_set_fpscr">, Intrinsic<[], [llvm_i32_ty], []>; def int_arm_vcvtr : Intrinsic<[llvm_float_ty], [llvm_anyfloat_ty], diff --git a/include/llvm/IR/IntrinsicsHexagon.td b/include/llvm/IR/IntrinsicsHexagon.td index 6519f051deeb..8ac56e03be6a 100644 --- a/include/llvm/IR/IntrinsicsHexagon.td +++ b/include/llvm/IR/IntrinsicsHexagon.td @@ -5659,20 +5659,20 @@ class Hexagon_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> [IntrNoMem]>; // -// Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> -// tag : M6_vabsdiffb -class Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> +// Hexagon_vv64ivmemv512_Intrinsic<string GCCIntSuffix> +// tag: V6_vS32b_qpred_ai +class Hexagon_vv64ivmemv512_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, - [llvm_i64_ty], [llvm_i64_ty,llvm_i64_ty], - [IntrNoMem]>; + [], [llvm_v512i1_ty,llvm_ptr_ty,llvm_v16i32_ty], + [IntrArgMemOnly]>; // -// Hexagon_LLii_Intrinsic<string GCCIntSuffix> -// tag : S6_vsplatrbp -class Hexagon_LLii_Intrinsic<string GCCIntSuffix> +// Hexagon_vv128ivmemv1024_Intrinsic<string GCCIntSuffix> +// tag: V6_vS32b_qpred_ai_128B +class Hexagon_vv128ivmemv1024_Intrinsic<string GCCIntSuffix> : Hexagon_Intrinsic<GCCIntSuffix, - [llvm_i64_ty], [llvm_i32_ty], - [IntrNoMem]>; + [], [llvm_v1024i1_ty,llvm_ptr_ty,llvm_v32i32_ty], + [IntrArgMemOnly]>; // // BUILTIN_INFO(HEXAGON.S6_rol_i_r,SI_ftype_SISI,2) @@ -9343,6 +9343,303 @@ def int_hexagon_V6_vlutvwh_oracc_128B : Hexagon_v2048v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_oracc_128B">; // +// Masked vector stores +// +def int_hexagon_V6_vmaskedstoreq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstoreq">; + +def int_hexagon_V6_vmaskedstorenq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorenq">; + +def int_hexagon_V6_vmaskedstorentq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorentq">; + +def int_hexagon_V6_vmaskedstorentnq : +Hexagon_vv64ivmemv512_Intrinsic<"HEXAGON_V6_vmaskedstorentnq">; + +def int_hexagon_V6_vmaskedstoreq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstoreq_128B">; + +def int_hexagon_V6_vmaskedstorenq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorenq_128B">; + +def int_hexagon_V6_vmaskedstorentq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorentq_128B">; + +def int_hexagon_V6_vmaskedstorentnq_128B : +Hexagon_vv128ivmemv1024_Intrinsic<"HEXAGON_V6_vmaskedstorentnq_128B">; + + +/// +/// HexagonV62 intrinsics +/// + +// +// Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> +// tag : M6_vabsdiffb +class Hexagon_LLiLLiLLi_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_i64_ty], [llvm_i64_ty,llvm_i64_ty], + [IntrNoMem]>; + +// +// Hexagon_LLii_Intrinsic<string GCCIntSuffix> +// tag : S6_vsplatrbp +class Hexagon_LLii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_i64_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlsrb +class Hexagon_V62_v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlsrb_128B +class Hexagon_V62_v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vasrwuhrndsat +class Hexagon_V62_v512v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vasrwuhrndsat_128B +class Hexagon_V62_v1024v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vrounduwuh +class Hexagon_V62_v512v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vrounduwuh_128B +class Hexagon_V62_v1024v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v2048_Intrinsic<string GCCIntSuffix> +// tag : V6_vadduwsat_dv_128B +class Hexagon_V62_v2048v2048v2048_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v64i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vaddhw_acc +class Hexagon_V62_v1024v1024v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vaddhw_acc_128B +class Hexagon_V62_v2048v2048v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v512v512_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpyewuh_64 +class Hexagon_V62_v1024v512v512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v1024v1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpyewuh_64_128B +class Hexagon_V62_v2048v1024v1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048i_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpauhb_128B +class Hexagon_V62_v2048v2048i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v2048i_Intrinsic<string GCCIntSuffix> +// tag : V6_vmpauhb_acc_128B +class Hexagon_V62_v2048v2048v2048i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v64i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt +class Hexagon_V62_v512v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v512i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_128B +class Hexagon_V62_v1024v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v1024i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_acc +class Hexagon_V62_v512v512v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v512i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_vandnqrt_acc_128B +class Hexagon_V62_v1024v1024v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v1024i1_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v64iv512_Intrinsic<string GCCIntSuffix> +// tag : V6_vandvqv +class Hexagon_V62_v512v64iv512_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v512i1_ty,llvm_v16i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v128iv1024_Intrinsic<string GCCIntSuffix> +// tag : V6_vandvqv_128B +class Hexagon_V62_v1024v128iv1024_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v1024i1_ty,llvm_v32i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v64ii_Intrinsic<string GCCIntSuffix> +// tag : V6_pred_scalar2v2 +class Hexagon_V62_v64ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v512i1_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v128ii_Intrinsic<string GCCIntSuffix> +// tag : V6_pred_scalar2v2_128B +class Hexagon_V62_v128ii_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v1024i1_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v64iv64iv64i_Intrinsic<string GCCIntSuffix> +// tag : V6_shuffeqw +class Hexagon_V62_v64iv64iv64i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v512i1_ty], [llvm_v512i1_ty,llvm_v512i1_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v128iv128iv128i_Intrinsic<string GCCIntSuffix> +// tag : V6_shuffeqw_128B +class Hexagon_V62_v128iv128iv128i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v1024i1_ty], [llvm_v1024i1_ty,llvm_v1024i1_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_lvsplath +class Hexagon_V62_v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_lvsplath_128B +class Hexagon_V62_v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v512v512v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvvb_oracci +class Hexagon_V62_v512v512v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v16i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvvb_oracci_128B +class Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwhi +class Hexagon_V62_v1024v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwhi_128B +class Hexagon_V62_v2048v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v1024v1024v512v512i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwh_oracci +class Hexagon_V62_v1024v1024v512v512i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v32i32_ty], [llvm_v32i32_ty,llvm_v16i32_ty,llvm_v16i32_ty,llvm_i32_ty], + [IntrNoMem]>; + +// +// Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> +// tag : V6_vlutvwh_oracci_128B +class Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<string GCCIntSuffix> + : Hexagon_Intrinsic<GCCIntSuffix, + [llvm_v64i32_ty], [llvm_v64i32_ty,llvm_v32i32_ty,llvm_v32i32_ty,llvm_i32_ty], + [IntrNoMem]>; + + +// // BUILTIN_INFO(HEXAGON.M6_vabsdiffb,DI_ftype_DIDI,2) // tag : M6_vabsdiffb def int_hexagon_M6_vabsdiffb : @@ -9355,12 +9652,6 @@ def int_hexagon_M6_vabsdiffub : Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_M6_vabsdiffub">; // -// BUILTIN_INFO(HEXAGON.S6_vsplatrbp,DI_ftype_SI,1) -// tag : S6_vsplatrbp -def int_hexagon_S6_vsplatrbp : -Hexagon_LLii_Intrinsic<"HEXAGON_S6_vsplatrbp">; - -// // BUILTIN_INFO(HEXAGON.S6_vtrunehb_ppp,DI_ftype_DIDI,2) // tag : S6_vtrunehb_ppp def int_hexagon_S6_vtrunehb_ppp : @@ -9371,3 +9662,550 @@ Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_S6_vtrunehb_ppp">; // tag : S6_vtrunohb_ppp def int_hexagon_S6_vtrunohb_ppp : Hexagon_LLiLLiLLi_Intrinsic<"HEXAGON_S6_vtrunohb_ppp">; + +// +// BUILTIN_INFO(HEXAGON.S6_vsplatrbp,DI_ftype_SI,1) +// tag : S6_vsplatrbp +def int_hexagon_S6_vsplatrbp : +Hexagon_LLii_Intrinsic<"HEXAGON_S6_vsplatrbp">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlsrb,VI_ftype_VISI,2) +// tag : V6_vlsrb +def int_hexagon_V6_vlsrb : +Hexagon_V62_v512v512i_Intrinsic<"HEXAGON_V6_vlsrb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlsrb_128B,VI_ftype_VISI,2) +// tag : V6_vlsrb_128B +def int_hexagon_V6_vlsrb_128B : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vlsrb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrwuhrndsat,VI_ftype_VIVISI,3) +// tag : V6_vasrwuhrndsat +def int_hexagon_V6_vasrwuhrndsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasrwuhrndsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrwuhrndsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasrwuhrndsat_128B +def int_hexagon_V6_vasrwuhrndsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasrwuhrndsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasruwuhrndsat,VI_ftype_VIVISI,3) +// tag : V6_vasruwuhrndsat +def int_hexagon_V6_vasruwuhrndsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasruwuhrndsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasruwuhrndsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasruwuhrndsat_128B +def int_hexagon_V6_vasruwuhrndsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasruwuhrndsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrhbsat,VI_ftype_VIVISI,3) +// tag : V6_vasrhbsat +def int_hexagon_V6_vasrhbsat : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vasrhbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vasrhbsat_128B,VI_ftype_VIVISI,3) +// tag : V6_vasrhbsat_128B +def int_hexagon_V6_vasrhbsat_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vasrhbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduwuh,VI_ftype_VIVI,2) +// tag : V6_vrounduwuh +def int_hexagon_V6_vrounduwuh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vrounduwuh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduwuh_128B,VI_ftype_VIVI,2) +// tag : V6_vrounduwuh_128B +def int_hexagon_V6_vrounduwuh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vrounduwuh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduhub,VI_ftype_VIVI,2) +// tag : V6_vrounduhub +def int_hexagon_V6_vrounduhub : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vrounduhub">; + +// +// BUILTIN_INFO(HEXAGON.V6_vrounduhub_128B,VI_ftype_VIVI,2) +// tag : V6_vrounduhub_128B +def int_hexagon_V6_vrounduhub_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vrounduhub_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat,VI_ftype_VIVI,2) +// tag : V6_vadduwsat +def int_hexagon_V6_vadduwsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vadduwsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_128B,VI_ftype_VIVI,2) +// tag : V6_vadduwsat_128B +def int_hexagon_V6_vadduwsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vadduwsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_dv,VD_ftype_VDVD,2) +// tag : V6_vadduwsat_dv +def int_hexagon_V6_vadduwsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vadduwsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduwsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vadduwsat_dv_128B +def int_hexagon_V6_vadduwsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vadduwsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat,VI_ftype_VIVI,2) +// tag : V6_vsubuwsat +def int_hexagon_V6_vsubuwsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubuwsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubuwsat_128B +def int_hexagon_V6_vsubuwsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubuwsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_dv,VD_ftype_VDVD,2) +// tag : V6_vsubuwsat_dv +def int_hexagon_V6_vsubuwsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubuwsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubuwsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vsubuwsat_dv_128B +def int_hexagon_V6_vsubuwsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vsubuwsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat,VI_ftype_VIVI,2) +// tag : V6_vaddbsat +def int_hexagon_V6_vaddbsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_128B,VI_ftype_VIVI,2) +// tag : V6_vaddbsat_128B +def int_hexagon_V6_vaddbsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_dv,VD_ftype_VDVD,2) +// tag : V6_vaddbsat_dv +def int_hexagon_V6_vaddbsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddbsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddbsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vaddbsat_dv_128B +def int_hexagon_V6_vaddbsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vaddbsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat,VI_ftype_VIVI,2) +// tag : V6_vsubbsat +def int_hexagon_V6_vsubbsat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubbsat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubbsat_128B +def int_hexagon_V6_vsubbsat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubbsat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_dv,VD_ftype_VDVD,2) +// tag : V6_vsubbsat_dv +def int_hexagon_V6_vsubbsat_dv : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubbsat_dv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubbsat_dv_128B,VD_ftype_VDVD,2) +// tag : V6_vsubbsat_dv_128B +def int_hexagon_V6_vsubbsat_dv_128B : +Hexagon_V62_v2048v2048v2048_Intrinsic<"HEXAGON_V6_vsubbsat_dv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddububb_sat,VI_ftype_VIVI,2) +// tag : V6_vaddububb_sat +def int_hexagon_V6_vaddububb_sat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddububb_sat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddububb_sat_128B,VI_ftype_VIVI,2) +// tag : V6_vaddububb_sat_128B +def int_hexagon_V6_vaddububb_sat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddububb_sat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubububb_sat,VI_ftype_VIVI,2) +// tag : V6_vsubububb_sat +def int_hexagon_V6_vsubububb_sat : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsubububb_sat">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsubububb_sat_128B,VI_ftype_VIVI,2) +// tag : V6_vsubububb_sat_128B +def int_hexagon_V6_vsubububb_sat_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsubububb_sat_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddhw_acc,VD_ftype_VDVIVI,3) +// tag : V6_vaddhw_acc +def int_hexagon_V6_vaddhw_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vaddhw_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddhw_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vaddhw_acc_128B +def int_hexagon_V6_vaddhw_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vaddhw_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduhw_acc,VD_ftype_VDVIVI,3) +// tag : V6_vadduhw_acc +def int_hexagon_V6_vadduhw_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vadduhw_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vadduhw_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vadduhw_acc_128B +def int_hexagon_V6_vadduhw_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vadduhw_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddubh_acc,VD_ftype_VDVIVI,3) +// tag : V6_vaddubh_acc +def int_hexagon_V6_vaddubh_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vaddubh_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddubh_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vaddubh_acc_128B +def int_hexagon_V6_vaddubh_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vaddubh_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyewuh_64,VD_ftype_VIVI,2) +// tag : V6_vmpyewuh_64 +def int_hexagon_V6_vmpyewuh_64 : +Hexagon_V62_v1024v512v512_Intrinsic<"HEXAGON_V6_vmpyewuh_64">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyewuh_64_128B,VD_ftype_VIVI,2) +// tag : V6_vmpyewuh_64_128B +def int_hexagon_V6_vmpyewuh_64_128B : +Hexagon_V62_v2048v1024v1024_Intrinsic<"HEXAGON_V6_vmpyewuh_64_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyowh_64_acc,VD_ftype_VDVIVI,3) +// tag : V6_vmpyowh_64_acc +def int_hexagon_V6_vmpyowh_64_acc : +Hexagon_V62_v1024v1024v512v512_Intrinsic<"HEXAGON_V6_vmpyowh_64_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyowh_64_acc_128B,VD_ftype_VDVIVI,3) +// tag : V6_vmpyowh_64_acc_128B +def int_hexagon_V6_vmpyowh_64_acc_128B : +Hexagon_V62_v2048v2048v1024v1024_Intrinsic<"HEXAGON_V6_vmpyowh_64_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb,VD_ftype_VDSI,2) +// tag : V6_vmpauhb +def int_hexagon_V6_vmpauhb : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vmpauhb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_128B,VD_ftype_VDSI,2) +// tag : V6_vmpauhb_128B +def int_hexagon_V6_vmpauhb_128B : +Hexagon_V62_v2048v2048i_Intrinsic<"HEXAGON_V6_vmpauhb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_acc,VD_ftype_VDVDSI,3) +// tag : V6_vmpauhb_acc +def int_hexagon_V6_vmpauhb_acc : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vmpauhb_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpauhb_acc_128B,VD_ftype_VDVDSI,3) +// tag : V6_vmpauhb_acc_128B +def int_hexagon_V6_vmpauhb_acc_128B : +Hexagon_V62_v2048v2048v2048i_Intrinsic<"HEXAGON_V6_vmpauhb_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub,VI_ftype_VISI,2) +// tag : V6_vmpyiwub +def int_hexagon_V6_vmpyiwub : +Hexagon_V62_v512v512i_Intrinsic<"HEXAGON_V6_vmpyiwub">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_128B,VI_ftype_VISI,2) +// tag : V6_vmpyiwub_128B +def int_hexagon_V6_vmpyiwub_128B : +Hexagon_V62_v1024v1024i_Intrinsic<"HEXAGON_V6_vmpyiwub_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_acc,VI_ftype_VIVISI,3) +// tag : V6_vmpyiwub_acc +def int_hexagon_V6_vmpyiwub_acc : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vmpyiwub_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmpyiwub_acc_128B,VI_ftype_VIVISI,3) +// tag : V6_vmpyiwub_acc_128B +def int_hexagon_V6_vmpyiwub_acc_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vmpyiwub_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt,VI_ftype_QVSI,2) +// tag : V6_vandnqrt +def int_hexagon_V6_vandnqrt : +Hexagon_V62_v512v64ii_Intrinsic<"HEXAGON_V6_vandnqrt">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_128B,VI_ftype_QVSI,2) +// tag : V6_vandnqrt_128B +def int_hexagon_V6_vandnqrt_128B : +Hexagon_V62_v1024v128ii_Intrinsic<"HEXAGON_V6_vandnqrt_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_acc,VI_ftype_VIQVSI,3) +// tag : V6_vandnqrt_acc +def int_hexagon_V6_vandnqrt_acc : +Hexagon_V62_v512v512v64ii_Intrinsic<"HEXAGON_V6_vandnqrt_acc">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandnqrt_acc_128B,VI_ftype_VIQVSI,3) +// tag : V6_vandnqrt_acc_128B +def int_hexagon_V6_vandnqrt_acc_128B : +Hexagon_V62_v1024v1024v128ii_Intrinsic<"HEXAGON_V6_vandnqrt_acc_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvqv,VI_ftype_QVVI,2) +// tag : V6_vandvqv +def int_hexagon_V6_vandvqv : +Hexagon_V62_v512v64iv512_Intrinsic<"HEXAGON_V6_vandvqv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvqv_128B,VI_ftype_QVVI,2) +// tag : V6_vandvqv_128B +def int_hexagon_V6_vandvqv_128B : +Hexagon_V62_v1024v128iv1024_Intrinsic<"HEXAGON_V6_vandvqv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvnqv,VI_ftype_QVVI,2) +// tag : V6_vandvnqv +def int_hexagon_V6_vandvnqv : +Hexagon_V62_v512v64iv512_Intrinsic<"HEXAGON_V6_vandvnqv">; + +// +// BUILTIN_INFO(HEXAGON.V6_vandvnqv_128B,VI_ftype_QVVI,2) +// tag : V6_vandvnqv_128B +def int_hexagon_V6_vandvnqv_128B : +Hexagon_V62_v1024v128iv1024_Intrinsic<"HEXAGON_V6_vandvnqv_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_pred_scalar2v2,QV_ftype_SI,1) +// tag : V6_pred_scalar2v2 +def int_hexagon_V6_pred_scalar2v2 : +Hexagon_V62_v64ii_Intrinsic<"HEXAGON_V6_pred_scalar2v2">; + +// +// BUILTIN_INFO(HEXAGON.V6_pred_scalar2v2_128B,QV_ftype_SI,1) +// tag : V6_pred_scalar2v2_128B +def int_hexagon_V6_pred_scalar2v2_128B : +Hexagon_V62_v128ii_Intrinsic<"HEXAGON_V6_pred_scalar2v2_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqw,QV_ftype_QVQV,2) +// tag : V6_shuffeqw +def int_hexagon_V6_shuffeqw : +Hexagon_V62_v64iv64iv64i_Intrinsic<"HEXAGON_V6_shuffeqw">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqw_128B,QV_ftype_QVQV,2) +// tag : V6_shuffeqw_128B +def int_hexagon_V6_shuffeqw_128B : +Hexagon_V62_v128iv128iv128i_Intrinsic<"HEXAGON_V6_shuffeqw_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqh,QV_ftype_QVQV,2) +// tag : V6_shuffeqh +def int_hexagon_V6_shuffeqh : +Hexagon_V62_v64iv64iv64i_Intrinsic<"HEXAGON_V6_shuffeqh">; + +// +// BUILTIN_INFO(HEXAGON.V6_shuffeqh_128B,QV_ftype_QVQV,2) +// tag : V6_shuffeqh_128B +def int_hexagon_V6_shuffeqh_128B : +Hexagon_V62_v128iv128iv128i_Intrinsic<"HEXAGON_V6_shuffeqh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmaxb,VI_ftype_VIVI,2) +// tag : V6_vmaxb +def int_hexagon_V6_vmaxb : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vmaxb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vmaxb_128B,VI_ftype_VIVI,2) +// tag : V6_vmaxb_128B +def int_hexagon_V6_vmaxb_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vmaxb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vminb,VI_ftype_VIVI,2) +// tag : V6_vminb +def int_hexagon_V6_vminb : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vminb">; + +// +// BUILTIN_INFO(HEXAGON.V6_vminb_128B,VI_ftype_VIVI,2) +// tag : V6_vminb_128B +def int_hexagon_V6_vminb_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vminb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsatuwuh,VI_ftype_VIVI,2) +// tag : V6_vsatuwuh +def int_hexagon_V6_vsatuwuh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vsatuwuh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vsatuwuh_128B,VI_ftype_VIVI,2) +// tag : V6_vsatuwuh_128B +def int_hexagon_V6_vsatuwuh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vsatuwuh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplath,VI_ftype_SI,1) +// tag : V6_lvsplath +def int_hexagon_V6_lvsplath : +Hexagon_V62_v512i_Intrinsic<"HEXAGON_V6_lvsplath">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplath_128B,VI_ftype_SI,1) +// tag : V6_lvsplath_128B +def int_hexagon_V6_lvsplath_128B : +Hexagon_V62_v1024i_Intrinsic<"HEXAGON_V6_lvsplath_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplatb,VI_ftype_SI,1) +// tag : V6_lvsplatb +def int_hexagon_V6_lvsplatb : +Hexagon_V62_v512i_Intrinsic<"HEXAGON_V6_lvsplatb">; + +// +// BUILTIN_INFO(HEXAGON.V6_lvsplatb_128B,VI_ftype_SI,1) +// tag : V6_lvsplatb_128B +def int_hexagon_V6_lvsplatb_128B : +Hexagon_V62_v1024i_Intrinsic<"HEXAGON_V6_lvsplatb_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbw,VI_ftype_VIVI,2) +// tag : V6_vaddclbw +def int_hexagon_V6_vaddclbw : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddclbw">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbw_128B,VI_ftype_VIVI,2) +// tag : V6_vaddclbw_128B +def int_hexagon_V6_vaddclbw_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddclbw_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbh,VI_ftype_VIVI,2) +// tag : V6_vaddclbh +def int_hexagon_V6_vaddclbh : +Hexagon_V62_v512v512v512_Intrinsic<"HEXAGON_V6_vaddclbh">; + +// +// BUILTIN_INFO(HEXAGON.V6_vaddclbh_128B,VI_ftype_VIVI,2) +// tag : V6_vaddclbh_128B +def int_hexagon_V6_vaddclbh_128B : +Hexagon_V62_v1024v1024v1024_Intrinsic<"HEXAGON_V6_vaddclbh_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvbi,VI_ftype_VIVISI,3) +// tag : V6_vlutvvbi +def int_hexagon_V6_vlutvvbi : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvbi">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvbi_128B,VI_ftype_VIVISI,3) +// tag : V6_vlutvvbi_128B +def int_hexagon_V6_vlutvvbi_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvbi_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_oracci,VI_ftype_VIVIVISI,4) +// tag : V6_vlutvvb_oracci +def int_hexagon_V6_vlutvvb_oracci : +Hexagon_V62_v512v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvb_oracci">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_oracci_128B,VI_ftype_VIVIVISI,4) +// tag : V6_vlutvvb_oracci_128B +def int_hexagon_V6_vlutvvb_oracci_128B : +Hexagon_V62_v1024v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvb_oracci_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwhi,VD_ftype_VIVISI,3) +// tag : V6_vlutvwhi +def int_hexagon_V6_vlutvwhi : +Hexagon_V62_v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwhi">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwhi_128B,VD_ftype_VIVISI,3) +// tag : V6_vlutvwhi_128B +def int_hexagon_V6_vlutvwhi_128B : +Hexagon_V62_v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwhi_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_oracci,VD_ftype_VDVIVISI,4) +// tag : V6_vlutvwh_oracci +def int_hexagon_V6_vlutvwh_oracci : +Hexagon_V62_v1024v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwh_oracci">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_oracci_128B,VD_ftype_VDVIVISI,4) +// tag : V6_vlutvwh_oracci_128B +def int_hexagon_V6_vlutvwh_oracci_128B : +Hexagon_V62_v2048v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_oracci_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_nm,VI_ftype_VIVISI,3) +// tag : V6_vlutvvb_nm +def int_hexagon_V6_vlutvvb_nm : +Hexagon_V62_v512v512v512i_Intrinsic<"HEXAGON_V6_vlutvvb_nm">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvvb_nm_128B,VI_ftype_VIVISI,3) +// tag : V6_vlutvvb_nm_128B +def int_hexagon_V6_vlutvvb_nm_128B : +Hexagon_V62_v1024v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvvb_nm_128B">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_nm,VD_ftype_VIVISI,3) +// tag : V6_vlutvwh_nm +def int_hexagon_V6_vlutvwh_nm : +Hexagon_V62_v1024v512v512i_Intrinsic<"HEXAGON_V6_vlutvwh_nm">; + +// +// BUILTIN_INFO(HEXAGON.V6_vlutvwh_nm_128B,VD_ftype_VIVISI,3) +// tag : V6_vlutvwh_nm_128B +def int_hexagon_V6_vlutvwh_nm_128B : +Hexagon_V62_v2048v1024v1024i_Intrinsic<"HEXAGON_V6_vlutvwh_nm_128B">; + diff --git a/include/llvm/IR/IntrinsicsNVVM.td b/include/llvm/IR/IntrinsicsNVVM.td index f035ac3c90ee..68f123df0430 100644 --- a/include/llvm/IR/IntrinsicsNVVM.td +++ b/include/llvm/IR/IntrinsicsNVVM.td @@ -11,6 +11,27 @@ // //===----------------------------------------------------------------------===// +// The following intrinsics were once defined here, but are now auto-upgraded +// to target-generic LLVM intrinsics. +// +// * llvm.nvvm.brev32 --> llvm.bitreverse.i32 +// * llvm.nvvm.brev64 --> llvm.bitreverse.i64 +// * llvm.nvvm.clz.i --> llvm.ctlz.i32 +// * llvm.nvvm.clz.ll --> trunc i64 llvm.ctlz.i64(x) to i32 +// * llvm.nvvm.popc.i --> llvm.ctpop.i32 +// * llvm.nvvm.popc.ll --> trunc i64 llvm.ctpop.i64 to i32 +// * llvm.nvvm.abs.i --> select(x >= -x, x, -x) +// * llvm.nvvm.abs.ll --> ibid. +// * llvm.nvvm.max.i --> select(x sge y, x, y) +// * llvm.nvvm.max.ll --> ibid. +// * llvm.nvvm.max.ui --> select(x uge y, x, y) +// * llvm.nvvm.max.ull --> ibid. +// * llvm.nvvm.max.i --> select(x sle y, x, y) +// * llvm.nvvm.max.ll --> ibid. +// * llvm.nvvm.max.ui --> select(x ule y, x, y) +// * llvm.nvvm.max.ull --> ibid. +// * llvm.nvvm.h2f --> llvm.convert.to.fp16.f32 + def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // @@ -18,16 +39,6 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType<llvm_i64_ty>; // (space)i64* // let TargetPrefix = "nvvm" in { - def int_nvvm_clz_i : GCCBuiltin<"__nvvm_clz_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_clz_ll : GCCBuiltin<"__nvvm_clz_ll">, - Intrinsic<[llvm_i32_ty], [llvm_i64_ty], [IntrNoMem]>; - - def int_nvvm_popc_i : GCCBuiltin<"__nvvm_popc_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_popc_ll : GCCBuiltin<"__nvvm_popc_ll">, - Intrinsic<[llvm_i32_ty], [llvm_i64_ty], [IntrNoMem]>; - def int_nvvm_prmt : GCCBuiltin<"__nvvm_prmt">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem, Commutative]>; @@ -36,34 +47,6 @@ let TargetPrefix = "nvvm" in { // Min Max // - def int_nvvm_min_i : GCCBuiltin<"__nvvm_min_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_min_ui : GCCBuiltin<"__nvvm_min_ui">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_min_ll : GCCBuiltin<"__nvvm_min_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_min_ull : GCCBuiltin<"__nvvm_min_ull">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_max_i : GCCBuiltin<"__nvvm_max_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_max_ui : GCCBuiltin<"__nvvm_max_ui">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem, Commutative]>; - - def int_nvvm_max_ll : GCCBuiltin<"__nvvm_max_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_max_ull : GCCBuiltin<"__nvvm_max_ull">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], - [IntrNoMem, Commutative]>; - def int_nvvm_fmin_f : GCCBuiltin<"__nvvm_fmin_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem, Commutative]>; @@ -201,15 +184,6 @@ let TargetPrefix = "nvvm" in { [IntrNoMem, Commutative]>; // -// Brev -// - - def int_nvvm_brev32 : GCCBuiltin<"__nvvm_brev32">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_brev64 : GCCBuiltin<"__nvvm_brev64">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty], [IntrNoMem]>; - -// // Sad // @@ -242,16 +216,10 @@ let TargetPrefix = "nvvm" in { // Abs // - def int_nvvm_abs_i : GCCBuiltin<"__nvvm_abs_i">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_nvvm_abs_ll : GCCBuiltin<"__nvvm_abs_ll">, - Intrinsic<[llvm_i64_ty], [llvm_i64_ty], [IntrNoMem]>; - def int_nvvm_fabs_ftz_f : GCCBuiltin<"__nvvm_fabs_ftz_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty], [IntrNoMem]>; def int_nvvm_fabs_f : GCCBuiltin<"__nvvm_fabs_f">, Intrinsic<[llvm_float_ty], [llvm_float_ty], [IntrNoMem]>; - def int_nvvm_fabs_d : GCCBuiltin<"__nvvm_fabs_d">, Intrinsic<[llvm_double_ty], [llvm_double_ty], [IntrNoMem]>; @@ -700,9 +668,6 @@ let TargetPrefix = "nvvm" in { def int_nvvm_f2h_rn : GCCBuiltin<"__nvvm_f2h_rn">, Intrinsic<[llvm_i16_ty], [llvm_float_ty], [IntrNoMem]>; - def int_nvvm_h2f : GCCBuiltin<"__nvvm_h2f">, - Intrinsic<[llvm_float_ty], [llvm_i16_ty], [IntrNoMem]>; - // // Bitcast // @@ -768,6 +733,13 @@ let TargetPrefix = "nvvm" in { // intrinsics in this file, this one is a user-facing API. def int_nvvm_barrier0 : GCCBuiltin<"__syncthreads">, Intrinsic<[], [], [IntrConvergent]>; + // Synchronize all threads in the CTA at barrier 'n'. + def int_nvvm_barrier_n : GCCBuiltin<"__nvvm_bar_n">, + Intrinsic<[], [llvm_i32_ty], [IntrConvergent]>; + // Synchronize 'm', a multiple of warp size, (arg 2) threads in + // the CTA at barrier 'n' (arg 1). + def int_nvvm_barrier : GCCBuiltin<"__nvvm_bar">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_popc : GCCBuiltin<"__nvvm_bar0_popc">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; def int_nvvm_barrier0_and : GCCBuiltin<"__nvvm_bar0_and">, diff --git a/include/llvm/IR/IntrinsicsPowerPC.td b/include/llvm/IR/IntrinsicsPowerPC.td index 12e23b681ca4..64240a929782 100644 --- a/include/llvm/IR/IntrinsicsPowerPC.td +++ b/include/llvm/IR/IntrinsicsPowerPC.td @@ -203,19 +203,19 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // source address with a single pointer. def int_ppc_altivec_stvx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvxl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvebx : Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvehx : Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_altivec_stvewx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; // Comparisons setting a vector. def int_ppc_altivec_vcmpbfp : GCCBuiltin<"__builtin_altivec_vcmpbfp">, @@ -749,20 +749,20 @@ def int_ppc_vsx_lxvll : IntrArgMemOnly]>; def int_ppc_vsx_stxvl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i64_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; def int_ppc_vsx_stxvll : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i64_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; // Vector store. -def int_ppc_vsx_stxvw4x : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvd2x : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvw4x_be : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; -def int_ppc_vsx_stxvd2x_be : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; +def int_ppc_vsx_stxvw4x : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvd2x : Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvw4x_be : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; +def int_ppc_vsx_stxvd2x_be : Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], + [IntrWriteMem, IntrArgMemOnly]>; // Vector and scalar maximum. def int_ppc_vsx_xvmaxdp : PowerPC_VSX_Vec_DDD_Intrinsic<"xvmaxdp">; def int_ppc_vsx_xvmaxsp : PowerPC_VSX_Vec_FFF_Intrinsic<"xvmaxsp">; @@ -953,7 +953,7 @@ class PowerPC_QPX_LoadPerm_Intrinsic<string GCCIntSuffix> class PowerPC_QPX_Store_Intrinsic<string GCCIntSuffix> : PowerPC_QPX_Intrinsic<GCCIntSuffix, [], [llvm_v4f64_ty, llvm_ptr_ty], - [IntrArgMemOnly]>; + [IntrWriteMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // PowerPC QPX Intrinsic Definitions. diff --git a/include/llvm/IR/IntrinsicsWebAssembly.td b/include/llvm/IR/IntrinsicsWebAssembly.td index 4234c466d973..3a0957dfa39b 100644 --- a/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/include/llvm/IR/IntrinsicsWebAssembly.td @@ -17,6 +17,6 @@ let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.". // Note that current_memory is not IntrNoMem because it must be sequenced with // respect to grow_memory calls. def int_wasm_current_memory : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; -def int_wasm_grow_memory : Intrinsic<[], [llvm_anyint_ty], []>; +def int_wasm_grow_memory : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], []>; } diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index 85966af9c820..97c756cf4b60 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -785,12 +785,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem, Commutative]>; } -// Cacheability support ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_movntdqa : GCCBuiltin<"__builtin_ia32_movntdqa">, - Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty], [IntrReadMem]>; -} - // Test instruction with bitwise comparison. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_ptestz : GCCBuiltin<"__builtin_ia32_ptestz128">, @@ -2346,8 +2340,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_mpsadbw : GCCBuiltin<"__builtin_ia32_mpsadbw256">, Intrinsic<[llvm_v16i16_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_movntdqa : GCCBuiltin<"__builtin_ia32_movntdqa256">, - Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty], [IntrReadMem]>; } //===----------------------------------------------------------------------===// @@ -3033,17 +3025,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xop_vfrcz_ps_256 : GCCBuiltin<"__builtin_ia32_vfrczps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty], [IntrNoMem]>; - def int_x86_xop_vpcmov : - GCCBuiltin<"__builtin_ia32_vpcmov">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty], - [IntrNoMem]>; - def int_x86_xop_vpcmov_256 : - GCCBuiltin<"__builtin_ia32_vpcmov_256">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty], - [IntrNoMem]>; - def int_x86_xop_vpcomb : GCCBuiltin<"__builtin_ia32_vpcomb">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i8_ty], [IntrNoMem]>; @@ -3881,74 +3862,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_cvtq2mask_512 : GCCBuiltin<"__builtin_ia32_cvtq2mask512">, Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_128 : GCCBuiltin<"__builtin_ia32_cvtmask2b128">, - Intrinsic<[llvm_v16i8_ty], [llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_256 : GCCBuiltin<"__builtin_ia32_cvtmask2b256">, - Intrinsic<[llvm_v32i8_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2b_512 : GCCBuiltin<"__builtin_ia32_cvtmask2b512">, - Intrinsic<[llvm_v64i8_ty], [llvm_i64_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2w_128 : GCCBuiltin<"__builtin_ia32_cvtmask2w128">, - Intrinsic<[llvm_v8i16_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2w_256 : GCCBuiltin<"__builtin_ia32_cvtmask2w256">, - Intrinsic<[llvm_v16i16_ty], [llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2w_512 : GCCBuiltin<"__builtin_ia32_cvtmask2w512">, - Intrinsic<[llvm_v32i16_ty], [llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2d_128 : GCCBuiltin<"__builtin_ia32_cvtmask2d128">, - Intrinsic<[llvm_v4i32_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2d_256 : GCCBuiltin<"__builtin_ia32_cvtmask2d256">, - Intrinsic<[llvm_v8i32_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2d_512 : GCCBuiltin<"__builtin_ia32_cvtmask2d512">, - Intrinsic<[llvm_v16i32_ty], [llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_cvtmask2q_128 : GCCBuiltin<"__builtin_ia32_cvtmask2q128">, - Intrinsic<[llvm_v2i64_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2q_256 : GCCBuiltin<"__builtin_ia32_cvtmask2q256">, - Intrinsic<[llvm_v4i64_ty], [llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_cvtmask2q_512 : GCCBuiltin<"__builtin_ia32_cvtmask2q512">, - Intrinsic<[llvm_v8i64_ty], [llvm_i8_ty], [IntrNoMem]>; - } // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_packsswb_128 : GCCBuiltin<"__builtin_ia32_packsswb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, - llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packsswb_256 : GCCBuiltin<"__builtin_ia32_packsswb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v16i16_ty,llvm_v16i16_ty, - llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packsswb_512 : GCCBuiltin<"__builtin_ia32_packsswb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty, - llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_128 : GCCBuiltin<"__builtin_ia32_packssdw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_256 : GCCBuiltin<"__builtin_ia32_packssdw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packssdw_512 : GCCBuiltin<"__builtin_ia32_packssdw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_128 : GCCBuiltin<"__builtin_ia32_packuswb128_mask">, - Intrinsic<[llvm_v16i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, - llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_256 : GCCBuiltin<"__builtin_ia32_packuswb256_mask">, - Intrinsic<[llvm_v32i8_ty], [llvm_v16i16_ty,llvm_v16i16_ty, - llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packuswb_512 : GCCBuiltin<"__builtin_ia32_packuswb512_mask">, - Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty, - llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_128 : GCCBuiltin<"__builtin_ia32_packusdw128_mask">, - Intrinsic<[llvm_v8i16_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_256 : GCCBuiltin<"__builtin_ia32_packusdw256_mask">, - Intrinsic<[llvm_v16i16_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_packusdw_512 : GCCBuiltin<"__builtin_ia32_packusdw512_mask">, - Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; + def int_x86_avx512_packsswb_512 : GCCBuiltin<"__builtin_ia32_packsswb512">, + Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty], + [IntrNoMem]>; + def int_x86_avx512_packssdw_512 : GCCBuiltin<"__builtin_ia32_packssdw512">, + Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty], + [IntrNoMem]>; + def int_x86_avx512_packuswb_512 : GCCBuiltin<"__builtin_ia32_packuswb512">, + Intrinsic<[llvm_v64i8_ty], [llvm_v32i16_ty,llvm_v32i16_ty], + [IntrNoMem]>; + def int_x86_avx512_packusdw_512 : GCCBuiltin<"__builtin_ia32_packusdw512">, + Intrinsic<[llvm_v32i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty], + [IntrNoMem]>; } // Vector convert @@ -4595,39 +4524,15 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_div_pd_512 : GCCBuiltin<"__builtin_ia32_divpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_ps_128 : GCCBuiltin<"__builtin_ia32_maxps_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_ps_256 : GCCBuiltin<"__builtin_ia32_maxps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_max_ps_512 : GCCBuiltin<"__builtin_ia32_maxps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_pd_128 : GCCBuiltin<"__builtin_ia32_maxpd_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_max_pd_256 : GCCBuiltin<"__builtin_ia32_maxpd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_max_pd_512 : GCCBuiltin<"__builtin_ia32_maxpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_ps_128 : GCCBuiltin<"__builtin_ia32_minps_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_ps_256 : GCCBuiltin<"__builtin_ia32_minps256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_min_ps_512 : GCCBuiltin<"__builtin_ia32_minps512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_pd_128 : GCCBuiltin<"__builtin_ia32_minpd_mask">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_min_pd_256 : GCCBuiltin<"__builtin_ia32_minpd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_min_pd_512 : GCCBuiltin<"__builtin_ia32_minpd512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; @@ -5481,32 +5386,6 @@ let TargetPrefix = "x86" in { Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_lzcnt_d_128 : - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_d_256 : - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_d_512 : - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_lzcnt_q_128 : - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_q_256 : - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_lzcnt_q_512 : - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; } // Compares @@ -6458,10 +6337,6 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_cmpsd_mask">, Intrinsic<[llvm_i8_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_movntdqa : - GCCBuiltin<"__builtin_ia32_movntdqa512">, - Intrinsic<[llvm_v8i64_ty], [llvm_ptr_ty], [IntrReadMem]>; } //===----------------------------------------------------------------------===// @@ -6495,3 +6370,10 @@ let TargetPrefix = "x86" in { : GCCBuiltin<"__builtin_ia32_mwaitx">, Intrinsic<[], [ llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], []>; } + +//===----------------------------------------------------------------------===// +// Cache-line zero +let TargetPrefix = "x86" in { + def int_x86_clzero : GCCBuiltin<"__builtin_ia32_clzero">, + Intrinsic<[], [llvm_ptr_ty], []>; +} diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 7f43d5df3c3f..d13d5ddaeb3c 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -78,6 +78,7 @@ public: MD_type = 19, // "type" MD_section_prefix = 20, // "section_prefix" MD_absolute_symbol = 21, // "absolute_symbol" + MD_associated = 22, // "associated" }; /// Known operand bundle tag IDs, which always have the same value. All diff --git a/include/llvm/IR/MDBuilder.h b/include/llvm/IR/MDBuilder.h index bab8728ed49f..899976a87bc7 100644 --- a/include/llvm/IR/MDBuilder.h +++ b/include/llvm/IR/MDBuilder.h @@ -15,7 +15,9 @@ #ifndef LLVM_IR_MDBUILDER_H #define LLVM_IR_MDBUILDER_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/Support/DataTypes.h" #include <utility> @@ -63,8 +65,11 @@ public: /// Return metadata specifying that a branch or switch is unpredictable. MDNode *createUnpredictable(); - /// Return metadata containing the entry count for a function. - MDNode *createFunctionEntryCount(uint64_t Count); + /// Return metadata containing the entry \p Count for a function, and the + /// GUIDs stored in \p Imports that need to be imported for sample PGO, to + /// enable the same inlines as the profiled optimized binary + MDNode *createFunctionEntryCount(uint64_t Count, + const DenseSet<GlobalValue::GUID> *Imports); /// Return metadata containing the section prefix for a function. MDNode *createFunctionSectionPrefix(StringRef Prefix); diff --git a/include/llvm/IR/Mangler.h b/include/llvm/IR/Mangler.h index 0eb91a3b0600..56ee21392ccd 100644 --- a/include/llvm/IR/Mangler.h +++ b/include/llvm/IR/Mangler.h @@ -21,6 +21,7 @@ namespace llvm { class DataLayout; template <typename T> class SmallVectorImpl; +class Triple; class Twine; class raw_ostream; @@ -46,6 +47,9 @@ public: const Twine &GVName, const DataLayout &DL); }; +void emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, + const Triple &TT, Mangler &Mangler); + } // End llvm namespace #endif diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 46c785a1c05d..fd79355bff1a 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -78,7 +78,7 @@ public: protected: Metadata(unsigned ID, StorageType Storage) : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) { - static_assert(sizeof(*this) == 8, "Metdata fields poorly packed"); + static_assert(sizeof(*this) == 8, "Metadata fields poorly packed"); } ~Metadata() = default; @@ -269,12 +269,11 @@ public: private: LLVMContext &Context; - uint64_t NextIndex; + uint64_t NextIndex = 0; SmallDenseMap<void *, std::pair<OwnerTy, uint64_t>, 4> UseMap; public: - ReplaceableMetadataImpl(LLVMContext &Context) - : Context(Context), NextIndex(0) {} + ReplaceableMetadataImpl(LLVMContext &Context) : Context(Context) {} ~ReplaceableMetadataImpl() { assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata"); @@ -586,8 +585,9 @@ dyn_extract_or_null(Y &&MD) { class MDString : public Metadata { friend class StringMapEntry<MDString>; - StringMapEntry<MDString> *Entry; - MDString() : Metadata(MDStringKind, Uniqued), Entry(nullptr) {} + StringMapEntry<MDString> *Entry = nullptr; + + MDString() : Metadata(MDStringKind, Uniqued) {} public: MDString(const MDString &) = delete; @@ -1062,7 +1062,6 @@ public: static MDNode *getMostGenericRange(MDNode *A, MDNode *B); static MDNode *getMostGenericAliasScope(MDNode *A, MDNode *B); static MDNode *getMostGenericAlignmentOrDereferenceable(MDNode *A, MDNode *B); - }; /// \brief Tuple of metadata. @@ -1284,7 +1283,7 @@ class NamedMDNode : public ilist_node<NamedMDNode> { friend class Module; std::string Name; - Module *Parent; + Module *Parent = nullptr; void *Operands; // SmallVector<TrackingMDRef, 4> void setParent(Module *M) { Parent = M; } diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 79870b9455a6..70c57cf90add 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -311,7 +311,7 @@ public: /// 4. Finally, the function exists but has the wrong prototype: return the /// function with a constantexpr cast to the right prototype. Constant *getOrInsertFunction(StringRef Name, FunctionType *T, - AttributeSet AttributeList); + AttributeList AttributeList); Constant *getOrInsertFunction(StringRef Name, FunctionType *T); @@ -321,13 +321,22 @@ public: /// or a ConstantExpr BitCast of that type if the named function has a /// different type. This version of the method takes a null terminated list of /// function arguments, which makes it easier for clients to use. + template<typename... ArgsTy> Constant *getOrInsertFunction(StringRef Name, - AttributeSet AttributeList, - Type *RetTy, ...) LLVM_END_WITH_NULL; + AttributeList AttributeList, + Type *RetTy, ArgsTy... Args) + { + SmallVector<Type*, sizeof...(ArgsTy)> ArgTys{Args...}; + return getOrInsertFunction(Name, + FunctionType::get(RetTy, ArgTys, false), + AttributeList); + } /// Same as above, but without the attributes. - Constant *getOrInsertFunction(StringRef Name, Type *RetTy, ...) - LLVM_END_WITH_NULL; + template<typename... ArgsTy> + Constant *getOrInsertFunction(StringRef Name, Type *RetTy, ArgsTy... Args) { + return getOrInsertFunction(Name, AttributeList{}, RetTy, Args...); + } /// Look up the specified function in the module symbol table. If it does not /// exist, return null. @@ -345,20 +354,23 @@ public: return getGlobalVariable(Name, false); } - GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal) const { - return const_cast<Module *>(this)->getGlobalVariable(Name, AllowInternal); - } + GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal) const; - GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal = false); + GlobalVariable *getGlobalVariable(StringRef Name, + bool AllowInternal = false) { + return static_cast<const Module *>(this)->getGlobalVariable(Name, + AllowInternal); + } /// Return the global variable in the module with the specified name, of /// arbitrary type. This method returns null if a global with the specified /// name is not found. - GlobalVariable *getNamedGlobal(StringRef Name) { + const GlobalVariable *getNamedGlobal(StringRef Name) const { return getGlobalVariable(Name, true); } - const GlobalVariable *getNamedGlobal(StringRef Name) const { - return const_cast<Module *>(this)->getNamedGlobal(Name); + GlobalVariable *getNamedGlobal(StringRef Name) { + return const_cast<GlobalVariable *>( + static_cast<const Module *>(this)->getNamedGlobal(Name)); } /// Look up the specified global in the module symbol table. @@ -615,6 +627,32 @@ public: return global_objects().end(); } + typedef concat_iterator<GlobalValue, iterator, global_iterator, + alias_iterator, ifunc_iterator> + global_value_iterator; + typedef concat_iterator<const GlobalValue, const_iterator, + const_global_iterator, const_alias_iterator, + const_ifunc_iterator> + const_global_value_iterator; + + iterator_range<global_value_iterator> global_values() { + return concat<GlobalValue>(functions(), globals(), aliases(), ifuncs()); + } + iterator_range<const_global_value_iterator> global_values() const { + return concat<const GlobalValue>(functions(), globals(), aliases(), + ifuncs()); + } + + global_value_iterator global_value_begin() { return global_values().begin(); } + global_value_iterator global_value_end() { return global_values().end(); } + + const_global_value_iterator global_value_begin() const { + return global_values().begin(); + } + const_global_value_iterator global_value_end() const { + return global_values().end(); + } + /// @} /// @name Named Metadata Iteration /// @{ @@ -726,6 +764,10 @@ public: /// @name Utility functions for querying Debug information. /// @{ + /// \brief Returns the Number of Register ParametersDwarf Version by checking + /// module flags. + unsigned getNumberRegisterParameters() const; + /// \brief Returns the Dwarf Version by checking module flags. unsigned getDwarfVersion() const; diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index 83c4ae011216..09f6c1897009 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -162,7 +162,7 @@ private: protected: /// GlobalValueSummary constructor. GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs) - : Kind(K), Flags(Flags), RefEdgeList(std::move(Refs)) {} + : Kind(K), Flags(Flags), OriginalName(0), RefEdgeList(std::move(Refs)) {} public: virtual ~GlobalValueSummary() = default; @@ -233,12 +233,13 @@ public: void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } const GlobalValueSummary &getAliasee() const { - return const_cast<AliasSummary *>(this)->getAliasee(); + assert(AliaseeSummary && "Unexpected missing aliasee summary"); + return *AliaseeSummary; } GlobalValueSummary &getAliasee() { - assert(AliaseeSummary && "Unexpected missing aliasee summary"); - return *AliaseeSummary; + return const_cast<GlobalValueSummary &>( + static_cast<const AliasSummary *>(this)->getAliasee()); } }; @@ -249,6 +250,23 @@ public: /// <CalleeValueInfo, CalleeInfo> call edge pair. typedef std::pair<ValueInfo, CalleeInfo> EdgeTy; + /// An "identifier" for a virtual function. This contains the type identifier + /// represented as a GUID and the offset from the address point to the virtual + /// function pointer, where "address point" is as defined in the Itanium ABI: + /// https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general + struct VFuncId { + GlobalValue::GUID GUID; + uint64_t Offset; + }; + + /// A specification for a virtual function call with all constant integer + /// arguments. This is used to perform virtual constant propagation on the + /// summary. + struct ConstVCall { + VFuncId VFunc; + std::vector<uint64_t> Args; + }; + private: /// Number of instructions (ignoring debug instructions, e.g.) computed /// during the initial compile step when the summary index is first built. @@ -257,17 +275,47 @@ private: /// List of <CalleeValueInfo, CalleeInfo> call edge pairs from this function. std::vector<EdgeTy> CallGraphEdgeList; - /// List of type identifiers used by this function, represented as GUIDs. - std::vector<GlobalValue::GUID> TypeIdList; + /// All type identifier related information. Because these fields are + /// relatively uncommon we only allocate space for them if necessary. + struct TypeIdInfo { + /// List of type identifiers used by this function in llvm.type.test + /// intrinsics other than by an llvm.assume intrinsic, represented as GUIDs. + std::vector<GlobalValue::GUID> TypeTests; + + /// List of virtual calls made by this function using (respectively) + /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics that do + /// not have all constant integer arguments. + std::vector<VFuncId> TypeTestAssumeVCalls, TypeCheckedLoadVCalls; + + /// List of virtual calls made by this function using (respectively) + /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics with + /// all constant integer arguments. + std::vector<ConstVCall> TypeTestAssumeConstVCalls, + TypeCheckedLoadConstVCalls; + }; + + std::unique_ptr<TypeIdInfo> TIdInfo; public: /// Summary constructors. FunctionSummary(GVFlags Flags, unsigned NumInsts, std::vector<ValueInfo> Refs, std::vector<EdgeTy> CGEdges, - std::vector<GlobalValue::GUID> TypeIds) + std::vector<GlobalValue::GUID> TypeTests, + std::vector<VFuncId> TypeTestAssumeVCalls, + std::vector<VFuncId> TypeCheckedLoadVCalls, + std::vector<ConstVCall> TypeTestAssumeConstVCalls, + std::vector<ConstVCall> TypeCheckedLoadConstVCalls) : GlobalValueSummary(FunctionKind, Flags, std::move(Refs)), - InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)), - TypeIdList(std::move(TypeIds)) {} + InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)) { + if (!TypeTests.empty() || !TypeTestAssumeVCalls.empty() || + !TypeCheckedLoadVCalls.empty() || !TypeTestAssumeConstVCalls.empty() || + !TypeCheckedLoadConstVCalls.empty()) + TIdInfo = llvm::make_unique<TypeIdInfo>(TypeIdInfo{ + std::move(TypeTests), std::move(TypeTestAssumeVCalls), + std::move(TypeCheckedLoadVCalls), + std::move(TypeTestAssumeConstVCalls), + std::move(TypeCheckedLoadConstVCalls)}); + } /// Check if this is a function summary. static bool classof(const GlobalValueSummary *GVS) { @@ -280,8 +328,85 @@ public: /// Return the list of <CalleeValueInfo, CalleeInfo> pairs. ArrayRef<EdgeTy> calls() const { return CallGraphEdgeList; } - /// Returns the list of type identifiers used by this function. - ArrayRef<GlobalValue::GUID> type_tests() const { return TypeIdList; } + /// Returns the list of type identifiers used by this function in + /// llvm.type.test intrinsics other than by an llvm.assume intrinsic, + /// represented as GUIDs. + ArrayRef<GlobalValue::GUID> type_tests() const { + if (TIdInfo) + return TIdInfo->TypeTests; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.assume(llvm.type.test) intrinsics that do not have all constant + /// integer arguments. + ArrayRef<VFuncId> type_test_assume_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeTestAssumeVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.type.checked.load intrinsics that do not have all constant integer + /// arguments. + ArrayRef<VFuncId> type_checked_load_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeCheckedLoadVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.assume(llvm.type.test) intrinsics with all constant integer + /// arguments. + ArrayRef<ConstVCall> type_test_assume_const_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeTestAssumeConstVCalls; + return {}; + } + + /// Returns the list of virtual calls made by this function using + /// llvm.type.checked.load intrinsics with all constant integer arguments. + ArrayRef<ConstVCall> type_checked_load_const_vcalls() const { + if (TIdInfo) + return TIdInfo->TypeCheckedLoadConstVCalls; + return {}; + } + + /// Add a type test to the summary. This is used by WholeProgramDevirt if we + /// were unable to devirtualize a checked call. + void addTypeTest(GlobalValue::GUID Guid) { + if (!TIdInfo) + TIdInfo = llvm::make_unique<TypeIdInfo>(); + TIdInfo->TypeTests.push_back(Guid); + } +}; + +template <> struct DenseMapInfo<FunctionSummary::VFuncId> { + static FunctionSummary::VFuncId getEmptyKey() { return {0, uint64_t(-1)}; } + static FunctionSummary::VFuncId getTombstoneKey() { + return {0, uint64_t(-2)}; + } + static bool isEqual(FunctionSummary::VFuncId L, FunctionSummary::VFuncId R) { + return L.GUID == R.GUID && L.Offset == R.Offset; + } + static unsigned getHashValue(FunctionSummary::VFuncId I) { return I.GUID; } +}; + +template <> struct DenseMapInfo<FunctionSummary::ConstVCall> { + static FunctionSummary::ConstVCall getEmptyKey() { + return {{0, uint64_t(-1)}, {}}; + } + static FunctionSummary::ConstVCall getTombstoneKey() { + return {{0, uint64_t(-2)}, {}}; + } + static bool isEqual(FunctionSummary::ConstVCall L, + FunctionSummary::ConstVCall R) { + return DenseMapInfo<FunctionSummary::VFuncId>::isEqual(L.VFunc, R.VFunc) && + L.Args == R.Args; + } + static unsigned getHashValue(FunctionSummary::ConstVCall I) { + return I.VFunc.GUID; + } }; /// \brief Global variable summary information to aid decisions and @@ -323,8 +448,40 @@ struct TypeTestResolution { unsigned SizeM1BitWidth = 0; }; +struct WholeProgramDevirtResolution { + enum Kind { + Indir, ///< Just do a regular virtual call + SingleImpl, ///< Single implementation devirtualization + } TheKind = Indir; + + std::string SingleImplName; + + struct ByArg { + enum Kind { + Indir, ///< Just do a regular virtual call + UniformRetVal, ///< Uniform return value optimization + UniqueRetVal, ///< Unique return value optimization + VirtualConstProp, ///< Virtual constant propagation + } TheKind = Indir; + + /// Additional information for the resolution: + /// - UniformRetVal: the uniform return value. + /// - UniqueRetVal: the return value associated with the unique vtable (0 or + /// 1). + uint64_t Info = 0; + }; + + /// Resolutions for calls with all constant integer arguments (excluding the + /// first argument, "this"), where the key is the argument vector. + std::map<std::vector<uint64_t>, ByArg> ResByArg; +}; + struct TypeIdSummary { TypeTestResolution TTRes; + + /// Mapping from byte offset to whole-program devirt resolution for that + /// (typeid, byte offset) pair. + std::map<uint64_t, WholeProgramDevirtResolution> WPDRes; }; /// 160 bits SHA1 @@ -372,6 +529,10 @@ private: // FIXME: Add bitcode read/write support for this field. std::map<std::string, TypeIdSummary> TypeIdMap; + /// Mapping from original ID to GUID. If original ID can map to multiple + /// GUIDs, it will be mapped to 0. + std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap; + // YAML I/O support. friend yaml::MappingTraits<ModuleSummaryIndex>; @@ -399,9 +560,17 @@ public: return GlobalValueMap.find(ValueGUID); } + /// Return the GUID for \p OriginalId in the OidGuidMap. + GlobalValue::GUID getGUIDFromOriginalID(GlobalValue::GUID OriginalID) const { + const auto I = OidGuidMap.find(OriginalID); + return I == OidGuidMap.end() ? 0 : I->second; + } + /// Add a global value summary for a value of the given name. void addGlobalValueSummary(StringRef ValueName, std::unique_ptr<GlobalValueSummary> Summary) { + addOriginalName(GlobalValue::getGUID(ValueName), + Summary->getOriginalName()); GlobalValueMap[GlobalValue::getGUID(ValueName)].push_back( std::move(Summary)); } @@ -409,9 +578,21 @@ public: /// Add a global value summary for a value of the given GUID. void addGlobalValueSummary(GlobalValue::GUID ValueGUID, std::unique_ptr<GlobalValueSummary> Summary) { + addOriginalName(ValueGUID, Summary->getOriginalName()); GlobalValueMap[ValueGUID].push_back(std::move(Summary)); } + /// Add an original name for the value of the given GUID. + void addOriginalName(GlobalValue::GUID ValueGUID, + GlobalValue::GUID OrigGUID) { + if (OrigGUID == 0 || ValueGUID == OrigGUID) + return; + if (OidGuidMap.count(OrigGUID) && OidGuidMap[OrigGUID] != ValueGUID) + OidGuidMap[OrigGUID] = 0; + else + OidGuidMap[OrigGUID] = ValueGUID; + } + /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if /// not found. GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, @@ -507,6 +688,25 @@ public: return ModulePathStringTable.count(M.getModuleIdentifier()); } + const std::map<std::string, TypeIdSummary> &typeIds() const { + return TypeIdMap; + } + + /// This accessor should only be used when exporting because it can mutate the + /// map. + TypeIdSummary &getOrInsertTypeIdSummary(StringRef TypeId) { + return TypeIdMap[TypeId]; + } + + /// This returns either a pointer to the type id summary (if present in the + /// summary map) or null (if not present). This may be used when importing. + const TypeIdSummary *getTypeIdSummary(StringRef TypeId) const { + auto I = TypeIdMap.find(TypeId); + if (I == TypeIdMap.end()) + return nullptr; + return &I->second; + } + /// Remove entries in the GlobalValueMap that have empty summaries due to the /// eager nature of map entry creation during VST parsing. These would /// also be suppressed during combined index generation in mergeFrom(), diff --git a/include/llvm/IR/ModuleSummaryIndexYAML.h b/include/llvm/IR/ModuleSummaryIndexYAML.h index e2880ec6fec8..80719c696935 100644 --- a/include/llvm/IR/ModuleSummaryIndexYAML.h +++ b/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -33,20 +33,135 @@ template <> struct MappingTraits<TypeTestResolution> { } }; +template <> +struct ScalarEnumerationTraits<WholeProgramDevirtResolution::ByArg::Kind> { + static void enumeration(IO &io, + WholeProgramDevirtResolution::ByArg::Kind &value) { + io.enumCase(value, "Indir", WholeProgramDevirtResolution::ByArg::Indir); + io.enumCase(value, "UniformRetVal", + WholeProgramDevirtResolution::ByArg::UniformRetVal); + io.enumCase(value, "UniqueRetVal", + WholeProgramDevirtResolution::ByArg::UniqueRetVal); + io.enumCase(value, "VirtualConstProp", + WholeProgramDevirtResolution::ByArg::VirtualConstProp); + } +}; + +template <> struct MappingTraits<WholeProgramDevirtResolution::ByArg> { + static void mapping(IO &io, WholeProgramDevirtResolution::ByArg &res) { + io.mapOptional("Kind", res.TheKind); + io.mapOptional("Info", res.Info); + } +}; + +template <> +struct CustomMappingTraits< + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>> { + static void inputOne( + IO &io, StringRef Key, + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) { + std::vector<uint64_t> Args; + std::pair<StringRef, StringRef> P = {"", Key}; + while (!P.second.empty()) { + P = P.second.split(','); + uint64_t Arg; + if (P.first.getAsInteger(0, Arg)) { + io.setError("key not an integer"); + return; + } + Args.push_back(Arg); + } + io.mapRequired(Key.str().c_str(), V[Args]); + } + static void output( + IO &io, + std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) { + for (auto &P : V) { + std::string Key; + for (uint64_t Arg : P.first) { + if (!Key.empty()) + Key += ','; + Key += llvm::utostr(Arg); + } + io.mapRequired(Key.c_str(), P.second); + } + } +}; + +template <> struct ScalarEnumerationTraits<WholeProgramDevirtResolution::Kind> { + static void enumeration(IO &io, WholeProgramDevirtResolution::Kind &value) { + io.enumCase(value, "Indir", WholeProgramDevirtResolution::Indir); + io.enumCase(value, "SingleImpl", WholeProgramDevirtResolution::SingleImpl); + } +}; + +template <> struct MappingTraits<WholeProgramDevirtResolution> { + static void mapping(IO &io, WholeProgramDevirtResolution &res) { + io.mapOptional("Kind", res.TheKind); + io.mapOptional("SingleImplName", res.SingleImplName); + io.mapOptional("ResByArg", res.ResByArg); + } +}; + +template <> +struct CustomMappingTraits<std::map<uint64_t, WholeProgramDevirtResolution>> { + static void inputOne(IO &io, StringRef Key, + std::map<uint64_t, WholeProgramDevirtResolution> &V) { + uint64_t KeyInt; + if (Key.getAsInteger(0, KeyInt)) { + io.setError("key not an integer"); + return; + } + io.mapRequired(Key.str().c_str(), V[KeyInt]); + } + static void output(IO &io, std::map<uint64_t, WholeProgramDevirtResolution> &V) { + for (auto &P : V) + io.mapRequired(llvm::utostr(P.first).c_str(), P.second); + } +}; + template <> struct MappingTraits<TypeIdSummary> { static void mapping(IO &io, TypeIdSummary& summary) { io.mapOptional("TTRes", summary.TTRes); + io.mapOptional("WPDRes", summary.WPDRes); } }; struct FunctionSummaryYaml { std::vector<uint64_t> TypeTests; + std::vector<FunctionSummary::VFuncId> TypeTestAssumeVCalls, + TypeCheckedLoadVCalls; + std::vector<FunctionSummary::ConstVCall> TypeTestAssumeConstVCalls, + TypeCheckedLoadConstVCalls; +}; + +} // End yaml namespace +} // End llvm namespace + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<FunctionSummary::VFuncId> { + static void mapping(IO &io, FunctionSummary::VFuncId& id) { + io.mapOptional("GUID", id.GUID); + io.mapOptional("Offset", id.Offset); + } +}; + +template <> struct MappingTraits<FunctionSummary::ConstVCall> { + static void mapping(IO &io, FunctionSummary::ConstVCall& id) { + io.mapOptional("VFunc", id.VFunc); + io.mapOptional("Args", id.Args); + } }; } // End yaml namespace } // End llvm namespace -LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::VFuncId) +LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::ConstVCall) namespace llvm { namespace yaml { @@ -54,6 +169,12 @@ namespace yaml { template <> struct MappingTraits<FunctionSummaryYaml> { static void mapping(IO &io, FunctionSummaryYaml& summary) { io.mapOptional("TypeTests", summary.TypeTests); + io.mapOptional("TypeTestAssumeVCalls", summary.TypeTestAssumeVCalls); + io.mapOptional("TypeCheckedLoadVCalls", summary.TypeCheckedLoadVCalls); + io.mapOptional("TypeTestAssumeConstVCalls", + summary.TypeTestAssumeConstVCalls); + io.mapOptional("TypeCheckedLoadConstVCalls", + summary.TypeCheckedLoadConstVCalls); } }; @@ -82,7 +203,11 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> { false); Elem.push_back(llvm::make_unique<FunctionSummary>( GVFlags, 0, ArrayRef<ValueInfo>{}, - ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests))); + ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests), + std::move(FSum.TypeTestAssumeVCalls), + std::move(FSum.TypeCheckedLoadVCalls), + std::move(FSum.TypeTestAssumeConstVCalls), + std::move(FSum.TypeCheckedLoadConstVCalls))); } } static void output(IO &io, GlobalValueSummaryMapTy &V) { @@ -90,7 +215,11 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> { std::vector<FunctionSummaryYaml> FSums; for (auto &Sum : P.second) { if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get())) - FSums.push_back(FunctionSummaryYaml{FSum->type_tests()}); + FSums.push_back(FunctionSummaryYaml{ + FSum->type_tests(), FSum->type_test_assume_vcalls(), + FSum->type_checked_load_vcalls(), + FSum->type_test_assume_const_vcalls(), + FSum->type_checked_load_const_vcalls()}); } if (!FSums.empty()) io.mapRequired(llvm::utostr(P.first).c_str(), FSums); diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 444ce93921f6..997a85340c25 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -18,8 +18,6 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -174,12 +172,15 @@ private: FastMathFlags(unsigned F) : Flags(F) { } public: + /// This is how the bits are used in Value::SubclassOptionalData so they + /// should fit there too. enum { UnsafeAlgebra = (1 << 0), NoNaNs = (1 << 1), NoInfs = (1 << 2), NoSignedZeros = (1 << 3), - AllowReciprocal = (1 << 4) + AllowReciprocal = (1 << 4), + AllowContract = (1 << 5) }; FastMathFlags() = default; @@ -195,6 +196,7 @@ public: bool noInfs() const { return 0 != (Flags & NoInfs); } bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } + bool allowContract() const { return 0 != (Flags & AllowContract); } bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); } /// Flag setters @@ -202,12 +204,16 @@ public: void setNoInfs() { Flags |= NoInfs; } void setNoSignedZeros() { Flags |= NoSignedZeros; } void setAllowReciprocal() { Flags |= AllowReciprocal; } + void setAllowContract(bool B) { + Flags = (Flags & ~AllowContract) | B * AllowContract; + } void setUnsafeAlgebra() { Flags |= UnsafeAlgebra; setNoNaNs(); setNoInfs(); setNoSignedZeros(); setAllowReciprocal(); + setAllowContract(true); } void operator&=(const FastMathFlags &OtherFlags) { @@ -259,6 +265,12 @@ private: (B * FastMathFlags::AllowReciprocal); } + void setHasAllowContract(bool B) { + SubclassOptionalData = + (SubclassOptionalData & ~FastMathFlags::AllowContract) | + (B * FastMathFlags::AllowContract); + } + /// Convenience function for setting multiple fast-math flags. /// FMF is a mask of the bits to set. void setFastMathFlags(FastMathFlags FMF) { @@ -302,6 +314,12 @@ public: return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0; } + /// Test whether this operation is permitted to + /// be floating-point contracted. + bool hasAllowContract() const { + return (SubclassOptionalData & FastMathFlags::AllowContract) != 0; + } + /// Convenience function for getting all the fast-math flags FastMathFlags getFastMathFlags() const { return FastMathFlags(SubclassOptionalData); diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h index 9eee65e93e52..185a5ac956f5 100644 --- a/include/llvm/IR/OptBisect.h +++ b/include/llvm/IR/OptBisect.h @@ -51,24 +51,6 @@ public: template <class UnitT> bool shouldRunPass(const Pass *P, const UnitT &U); - /// Checks the bisect limit to determine if the optimization described by the - /// /p Desc argument should run. - /// - /// This function will immediate return true if bisection is disabled. If the - /// bisect limit is set to -1, the function will print a message with the - /// bisect number assigned to the optimization along with the /p Desc - /// description and return true. Otherwise, the function will print a message - /// with the bisect number assigned to the optimization and indicating whether - /// or not the pass will be run and return true if the bisect limit has not - /// yet been exceded or false if it has. - /// - /// Passes may call this function to provide more fine grained control over - /// individual optimizations performed by the pass. Passes which cannot be - /// skipped entirely (such as non-optional code generation passes) may still - /// call this function to control whether or not individual optional - /// transformations are performed. - bool shouldRunCase(const Twine &Desc); - private: bool checkPass(const StringRef PassName, const StringRef TargetDesc); diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index b7811fdb7504..c845112baa45 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -73,6 +73,46 @@ struct alignas(8) AnalysisKey {}; /// if it is, the analysis knows that it itself is preserved. struct alignas(8) AnalysisSetKey {}; +/// This templated class represents "all analyses that operate over \<a +/// particular IR unit\>" (e.g. a Function or a Module) in instances of +/// PreservedAnalysis. +/// +/// This lets a transformation say e.g. "I preserved all function analyses". +/// +/// Note that you must provide an explicit instantiation declaration and +/// definition for this template in order to get the correct behavior on +/// Windows. Otherwise, the address of SetKey will not be stable. +template <typename IRUnitT> class AllAnalysesOn { +public: + static AnalysisSetKey *ID() { return &SetKey; } + +private: + static AnalysisSetKey SetKey; +}; + +template <typename IRUnitT> AnalysisSetKey AllAnalysesOn<IRUnitT>::SetKey; + +extern template class AllAnalysesOn<Module>; +extern template class AllAnalysesOn<Function>; + +/// Represents analyses that only rely on functions' control flow. +/// +/// This can be used with \c PreservedAnalyses to mark the CFG as preserved and +/// to query whether it has been preserved. +/// +/// The CFG of a function is defined as the set of basic blocks and the edges +/// between them. Changing the set of basic blocks in a function is enough to +/// mutate the CFG. Mutating the condition of a branch or argument of an +/// invoked function does not mutate the CFG, but changing the successor labels +/// of those instructions does. +class CFGAnalyses { +public: + static AnalysisSetKey *ID() { return &SetKey; } + +private: + static AnalysisSetKey SetKey; +}; + /// A set of analyses that are preserved following a run of a transformation /// pass. /// @@ -348,29 +388,6 @@ struct AnalysisInfoMixin : PassInfoMixin<DerivedT> { } }; -/// This templated class represents "all analyses that operate over \<a -/// particular IR unit\>" (e.g. a Function or a Module) in instances of -/// PreservedAnalysis. -/// -/// This lets a transformation say e.g. "I preserved all function analyses". -/// -/// Note that you must provide an explicit instantiation declaration and -/// definition for this template in order to get the correct behavior on -/// Windows. Otherwise, the address of SetKey will not be stable. -template <typename IRUnitT> -class AllAnalysesOn { -public: - static AnalysisSetKey *ID() { return &SetKey; } - -private: - static AnalysisSetKey SetKey; -}; - -template <typename IRUnitT> AnalysisSetKey AllAnalysesOn<IRUnitT>::SetKey; - -extern template class AllAnalysesOn<Module>; -extern template class AllAnalysesOn<Function>; - /// \brief Manages a sequence of passes over a particular unit of IR. /// /// A pass manager contains a sequence of passes to run over a particular unit @@ -780,7 +797,7 @@ public: if (DebugLogging) dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name() - << "\n"; + << " on " << IR.getName() << "\n"; I = ResultsList.erase(I); AnalysisResults.erase({ID, &IR}); @@ -821,7 +838,8 @@ private: if (Inserted) { auto &P = this->lookUpPass(ID); if (DebugLogging) - dbgs() << "Running analysis: " << P.name() << "\n"; + dbgs() << "Running analysis: " << P.name() << " on " << IR.getName() + << "\n"; AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; ResultList.emplace_back(ID, P.run(IR, *this, ExtraArgs...)); @@ -852,7 +870,7 @@ private: if (DebugLogging) dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name() - << "\n"; + << " on " << IR.getName() << "\n"; AnalysisResultLists[&IR].erase(RI->second); AnalysisResults.erase(RI); } diff --git a/include/llvm/IR/PassManagerInternal.h b/include/llvm/IR/PassManagerInternal.h index 02f21675fa9d..387dc4c65c43 100644 --- a/include/llvm/IR/PassManagerInternal.h +++ b/include/llvm/IR/PassManagerInternal.h @@ -291,7 +291,7 @@ struct AnalysisPassModel : AnalysisPassConcept<IRUnitT, PreservedAnalysesT, AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, ExtraArgTs... ExtraArgs) override { - return make_unique<ResultModelT>(Pass.run(IR, AM, ExtraArgs...)); + return llvm::make_unique<ResultModelT>(Pass.run(IR, AM, ExtraArgs...)); } /// \brief The model delegates to a static \c PassT::name method. diff --git a/include/llvm/IR/PatternMatch.h b/include/llvm/IR/PatternMatch.h index a30fc97e98ef..40f9c21f646b 100644 --- a/include/llvm/IR/PatternMatch.h +++ b/include/llvm/IR/PatternMatch.h @@ -157,6 +157,19 @@ inline match_combine_or<match_zero, match_neg_zero> m_AnyZero() { return m_CombineOr(m_Zero(), m_NegZero()); } +struct match_nan { + template <typename ITy> bool match(ITy *V) { + if (const auto *C = dyn_cast<ConstantFP>(V)) { + const APFloat &APF = C->getValueAPF(); + return APF.isNaN(); + } + return false; + } +}; + +/// Match an arbitrary NaN constant. This includes quiet and signalling nans. +inline match_nan m_NaN() { return match_nan(); } + struct apint_match { const APInt *&Res; apint_match(const APInt *&R) : Res(R) {} @@ -814,6 +827,13 @@ inline CastClass_match<OpTy, Instruction::ZExt> m_ZExt(const OpTy &Op) { return CastClass_match<OpTy, Instruction::ZExt>(Op); } +template <typename OpTy> +inline match_combine_or<CastClass_match<OpTy, Instruction::ZExt>, + CastClass_match<OpTy, Instruction::SExt>> +m_ZExtOrSExt(const OpTy &Op) { + return m_CombineOr(m_ZExt(Op), m_SExt(Op)); +} + /// \brief Matches UIToFP. template <typename OpTy> inline CastClass_match<OpTy, Instruction::UIToFP> m_UIToFP(const OpTy &Op) { @@ -826,6 +846,18 @@ inline CastClass_match<OpTy, Instruction::SIToFP> m_SIToFP(const OpTy &Op) { return CastClass_match<OpTy, Instruction::SIToFP>(Op); } +/// \brief Matches FPTrunc +template <typename OpTy> +inline CastClass_match<OpTy, Instruction::FPTrunc> m_FPTrunc(const OpTy &Op) { + return CastClass_match<OpTy, Instruction::FPTrunc>(Op); +} + +/// \brief Matches FPExt +template <typename OpTy> +inline CastClass_match<OpTy, Instruction::FPExt> m_FPExt(const OpTy &Op) { + return CastClass_match<OpTy, Instruction::FPExt>(Op); +} + //===----------------------------------------------------------------------===// // Matchers for unary operators // @@ -1316,6 +1348,14 @@ template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) { // Matchers for two-operands operators with the operators in either order // +/// \brief Matches a BinaryOperator with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<AnyBinaryOp_match<LHS, RHS>, + AnyBinaryOp_match<RHS, LHS>> +m_c_BinOp(const LHS &L, const RHS &R) { + return m_CombineOr(m_BinOp(L, R), m_BinOp(R, L)); +} + /// \brief Matches an ICmp with a predicate over LHS and RHS in either order. /// Does not swap the predicate. template<typename LHS, typename RHS> @@ -1325,6 +1365,22 @@ m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) { return m_CombineOr(m_ICmp(Pred, L, R), m_ICmp(Pred, R, L)); } +/// \brief Matches a Add with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Add>, + BinaryOp_match<RHS, LHS, Instruction::Add>> +m_c_Add(const LHS &L, const RHS &R) { + return m_CombineOr(m_Add(L, R), m_Add(R, L)); +} + +/// \brief Matches a Mul with LHS and RHS in either order. +template<typename LHS, typename RHS> +inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Mul>, + BinaryOp_match<RHS, LHS, Instruction::Mul>> +m_c_Mul(const LHS &L, const RHS &R) { + return m_CombineOr(m_Mul(L, R), m_Mul(R, L)); +} + /// \brief Matches an And with LHS and RHS in either order. template<typename LHS, typename RHS> inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::And>, diff --git a/include/llvm/IR/PredIteratorCache.h b/include/llvm/IR/PredIteratorCache.h index 118310aed1d0..81f535311431 100644 --- a/include/llvm/IR/PredIteratorCache.h +++ b/include/llvm/IR/PredIteratorCache.h @@ -27,8 +27,8 @@ namespace llvm { /// wants the predecessor list for the same blocks. class PredIteratorCache { /// BlockToPredsMap - Pointer to null-terminated list. - DenseMap<BasicBlock *, BasicBlock **> BlockToPredsMap; - DenseMap<BasicBlock *, unsigned> BlockToPredCountMap; + mutable DenseMap<BasicBlock *, BasicBlock **> BlockToPredsMap; + mutable DenseMap<BasicBlock *, unsigned> BlockToPredCountMap; /// Memory - This is the space that holds cached preds. BumpPtrAllocator Memory; @@ -55,13 +55,15 @@ private: return Entry; } - unsigned GetNumPreds(BasicBlock *BB) { - GetPreds(BB); - return BlockToPredCountMap[BB]; + unsigned GetNumPreds(BasicBlock *BB) const { + auto Result = BlockToPredCountMap.find(BB); + if (Result != BlockToPredCountMap.end()) + return Result->second; + return BlockToPredCountMap[BB] = std::distance(pred_begin(BB), pred_end(BB)); } public: - size_t size(BasicBlock *BB) { return GetNumPreds(BB); } + size_t size(BasicBlock *BB) const { return GetNumPreds(BB); } ArrayRef<BasicBlock *> get(BasicBlock *BB) { return makeArrayRef(GetPreds(BB), GetNumPreds(BB)); } diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h index 916faa4b327e..03151cd7c8f7 100644 --- a/include/llvm/IR/Statepoint.h +++ b/include/llvm/IR/Statepoint.h @@ -454,7 +454,7 @@ struct StatepointDirectives { /// Parse out statepoint directives from the function attributes present in \p /// AS. -StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeSet AS); +StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeList AS); /// Return \c true if the the \p Attr is an attribute that is a statepoint /// directive. diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index 5c6d58affd7a..49a5fb21297d 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -1,4 +1,4 @@ -//===-- llvm/SymbolTableListTraits.h - Traits for iplist --------*- C++ -*-===// +//===- llvm/SymbolTableListTraits.h - Traits for iplist ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -26,23 +26,27 @@ #define LLVM_IR_SYMBOLTABLELISTTRAITS_H #include "llvm/ADT/ilist.h" +#include "llvm/ADT/simple_ilist.h" +#include <cstddef> namespace llvm { -class ValueSymbolTable; -/// Template metafunction to get the parent type for a symbol table list. -/// -/// Implementations create a typedef called \c type so that we only need a -/// single template parameter for the list and traits. -template <typename NodeTy> struct SymbolTableListParentType {}; class Argument; class BasicBlock; class Function; -class Instruction; -class GlobalVariable; class GlobalAlias; class GlobalIFunc; +class GlobalVariable; +class Instruction; class Module; +class ValueSymbolTable; + +/// Template metafunction to get the parent type for a symbol table list. +/// +/// Implementations create a typedef called \c type so that we only need a +/// single template parameter for the list and traits. +template <typename NodeTy> struct SymbolTableListParentType {}; + #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \ template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; }; DEFINE_SYMBOL_TABLE_PARENT_TYPE(Instruction, BasicBlock) @@ -67,7 +71,7 @@ class SymbolTableListTraits : public ilist_alloc_traits<ValueSubClass> { typename SymbolTableListParentType<ValueSubClass>::type ItemParentClass; public: - SymbolTableListTraits() {} + SymbolTableListTraits() = default; private: /// getListOwner - Return the object that owns this list. If this is a list @@ -109,6 +113,6 @@ template <class T> class SymbolTableList : public iplist_impl<simple_ilist<T>, SymbolTableListTraits<T>> {}; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_SYMBOLTABLELISTTRAITS_H diff --git a/include/llvm/IR/TrackingMDRef.h b/include/llvm/IR/TrackingMDRef.h index fe513a8f9795..12b196432006 100644 --- a/include/llvm/IR/TrackingMDRef.h +++ b/include/llvm/IR/TrackingMDRef.h @@ -15,6 +15,8 @@ #define LLVM_IR_TRACKINGMDREF_H #include "llvm/IR/Metadata.h" +#include <algorithm> +#include <cassert> namespace llvm { @@ -22,14 +24,15 @@ namespace llvm { /// /// This class behaves like \a TrackingVH, but for metadata. class TrackingMDRef { - Metadata *MD; + Metadata *MD = nullptr; public: - TrackingMDRef() : MD(nullptr) {} + TrackingMDRef() = default; explicit TrackingMDRef(Metadata *MD) : MD(MD) { track(); } TrackingMDRef(TrackingMDRef &&X) : MD(X.MD) { retrack(X); } TrackingMDRef(const TrackingMDRef &X) : MD(X.MD) { track(); } + TrackingMDRef &operator=(TrackingMDRef &&X) { if (&X == this) return *this; @@ -39,6 +42,7 @@ public: retrack(X); return *this; } + TrackingMDRef &operator=(const TrackingMDRef &X) { if (&X == this) return *this; @@ -48,6 +52,7 @@ public: track(); return *this; } + ~TrackingMDRef() { untrack(); } Metadata *get() const { return MD; } @@ -80,10 +85,12 @@ private: if (MD) MetadataTracking::track(MD); } + void untrack() { if (MD) MetadataTracking::untrack(MD); } + void retrack(TrackingMDRef &X) { assert(MD == X.MD && "Expected values to match"); if (X.MD) { @@ -101,15 +108,17 @@ template <class T> class TypedTrackingMDRef { TrackingMDRef Ref; public: - TypedTrackingMDRef() {} + TypedTrackingMDRef() = default; explicit TypedTrackingMDRef(T *MD) : Ref(static_cast<Metadata *>(MD)) {} TypedTrackingMDRef(TypedTrackingMDRef &&X) : Ref(std::move(X.Ref)) {} TypedTrackingMDRef(const TypedTrackingMDRef &X) : Ref(X.Ref) {} + TypedTrackingMDRef &operator=(TypedTrackingMDRef &&X) { Ref = std::move(X.Ref); return *this; } + TypedTrackingMDRef &operator=(const TypedTrackingMDRef &X) { Ref = X.Ref; return *this; @@ -162,4 +171,4 @@ template <class T> struct simplify_type<const TypedTrackingMDRef<T>> { } // end namespace llvm -#endif +#endif // LLVM_IR_TRACKINGMDREF_H diff --git a/include/llvm/IR/Type.h b/include/llvm/IR/Type.h index 778ee06169f1..e6a0df937e9b 100644 --- a/include/llvm/IR/Type.h +++ b/include/llvm/IR/Type.h @@ -290,7 +290,11 @@ public: /// If this is a vector type, return the element type, otherwise return /// 'this'. - Type *getScalarType() const LLVM_READONLY; + Type *getScalarType() const { + if (isVectorTy()) + return getVectorElementType(); + return const_cast<Type*>(this); + } //===--------------------------------------------------------------------===// // Type Iteration support. @@ -423,7 +427,7 @@ private: }; // Printing of types. -static inline raw_ostream &operator<<(raw_ostream &OS, Type &T) { +static inline raw_ostream &operator<<(raw_ostream &OS, const Type &T) { T.print(OS); return OS; } diff --git a/include/llvm/IR/TypeFinder.h b/include/llvm/IR/TypeFinder.h index 046f85caec9d..48c4f1161aa1 100644 --- a/include/llvm/IR/TypeFinder.h +++ b/include/llvm/IR/TypeFinder.h @@ -1,4 +1,4 @@ -//===-- llvm/IR/TypeFinder.h - Class to find used struct types --*- C++ -*-===// +//===- llvm/IR/TypeFinder.h - Class to find used struct types ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,8 +15,7 @@ #define LLVM_IR_TYPEFINDER_H #include "llvm/ADT/DenseSet.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/Type.h" +#include <cstddef> #include <vector> namespace llvm { @@ -24,6 +23,7 @@ namespace llvm { class MDNode; class Module; class StructType; +class Type; class Value; /// TypeFinder - Walk over a module, identifying all of the types that are @@ -36,10 +36,10 @@ class TypeFinder { DenseSet<Type*> VisitedTypes; std::vector<StructType*> StructTypes; - bool OnlyNamed; + bool OnlyNamed = false; public: - TypeFinder() : OnlyNamed(false) {} + TypeFinder() = default; void run(const Module &M, bool onlyNamed); void clear(); @@ -77,6 +77,6 @@ private: void incorporateMDNode(const MDNode *V); }; -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_TYPEFINDER_H diff --git a/include/llvm/IR/Use.h b/include/llvm/IR/Use.h index ff6b2e1f1e22..05b68ccbb38e 100644 --- a/include/llvm/IR/Use.h +++ b/include/llvm/IR/Use.h @@ -85,7 +85,7 @@ public: /// /// For an instruction operand, for example, this will return the /// instruction. - User *getUser() const; + User *getUser() const LLVM_READONLY; inline void set(Value *Val); @@ -111,7 +111,7 @@ public: static void zap(Use *Start, const Use *Stop, bool del = false); private: - const Use *getImpliedUser() const; + const Use *getImpliedUser() const LLVM_READONLY; Value *Val; Use *Next; diff --git a/include/llvm/IR/UseListOrder.h b/include/llvm/IR/UseListOrder.h index efff208295b6..ebe99223facd 100644 --- a/include/llvm/IR/UseListOrder.h +++ b/include/llvm/IR/UseListOrder.h @@ -20,20 +20,19 @@ namespace llvm { -class Module; class Function; class Value; /// \brief Structure to hold a use-list order. struct UseListOrder { - const Value *V; - const Function *F; + const Value *V = nullptr; + const Function *F = nullptr; std::vector<unsigned> Shuffle; UseListOrder(const Value *V, const Function *F, size_t ShuffleSize) : V(V), F(F), Shuffle(ShuffleSize) {} - UseListOrder() : V(nullptr), F(nullptr) {} + UseListOrder() = default; UseListOrder(UseListOrder &&) = default; UseListOrder &operator=(UseListOrder &&) = default; }; diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index c907d6b670b5..54758a9b6d6a 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -122,8 +122,16 @@ protected: } private: + const Use *getHungOffOperands() const { + return *(reinterpret_cast<const Use *const *>(this) - 1); + } + Use *&getHungOffOperands() { return *(reinterpret_cast<Use **>(this) - 1); } + const Use *getIntrusiveOperands() const { + return reinterpret_cast<const Use *>(this) - NumUserOperands; + } + Use *getIntrusiveOperands() { return reinterpret_cast<Use *>(this) - NumUserOperands; } @@ -135,11 +143,11 @@ private: } public: - Use *getOperandList() { + const Use *getOperandList() const { return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands(); } - const Use *getOperandList() const { - return const_cast<User *>(this)->getOperandList(); + Use *getOperandList() { + return const_cast<Use *>(static_cast<const User *>(this)->getOperandList()); } Value *getOperand(unsigned i) const { diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index bdafbbf58cc4..a4b48d7f3539 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -294,7 +294,15 @@ public: // when using them since you might not get all uses. // The methods that don't start with materialized_ assert that modules is // fully materialized. - void assertModuleIsMaterialized() const; + void assertModuleIsMaterializedImpl() const; + // This indirection exists so we can keep assertModuleIsMaterializedImpl() + // around in release builds of Value.cpp to be linked with other code built + // in debug mode. But this avoids calling it in any of the release built code. + void assertModuleIsMaterialized() const { +#ifndef NDEBUG + assertModuleIsMaterializedImpl(); +#endif + } bool use_empty() const { assertModuleIsMaterialized(); @@ -468,27 +476,30 @@ public: /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCasts(); - const Value *stripPointerCasts() const { - return const_cast<Value*>(this)->stripPointerCasts(); + const Value *stripPointerCasts() const; + Value *stripPointerCasts() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripPointerCasts()); } /// \brief Strip off pointer casts and all-zero GEPs. /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCastsNoFollowAliases(); - const Value *stripPointerCastsNoFollowAliases() const { - return const_cast<Value*>(this)->stripPointerCastsNoFollowAliases(); + const Value *stripPointerCastsNoFollowAliases() const; + Value *stripPointerCastsNoFollowAliases() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripPointerCastsNoFollowAliases()); } /// \brief Strip off pointer casts and all-constant inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsConstantOffsets(); - const Value *stripInBoundsConstantOffsets() const { - return const_cast<Value*>(this)->stripInBoundsConstantOffsets(); + const Value *stripInBoundsConstantOffsets() const; + Value *stripInBoundsConstantOffsets() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripInBoundsConstantOffsets()); } /// \brief Accumulate offsets from \a stripInBoundsConstantOffsets(). @@ -498,21 +509,22 @@ public: /// correct bitwidth for an offset of this pointer type. /// /// If this is called on a non-pointer value, it returns 'this'. - Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset); const Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset) const { - return const_cast<Value *>(this) - ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + APInt &Offset) const; + Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, + APInt &Offset) { + return const_cast<Value *>(static_cast<const Value *>(this) + ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); } /// \brief Strip off pointer casts and inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsOffsets(); - const Value *stripInBoundsOffsets() const { - return const_cast<Value*>(this)->stripInBoundsOffsets(); + const Value *stripInBoundsOffsets() const; + Value *stripInBoundsOffsets() { + return const_cast<Value *>( + static_cast<const Value *>(this)->stripInBoundsOffsets()); } /// \brief Returns the number of bytes known to be dereferenceable for the @@ -535,11 +547,12 @@ public: /// the PHI node corresponding to PredBB. If not, return ourself. This is /// useful if you want to know the value something has in a predecessor /// block. - Value *DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB); - const Value *DoPHITranslation(const BasicBlock *CurBB, - const BasicBlock *PredBB) const{ - return const_cast<Value*>(this)->DoPHITranslation(CurBB, PredBB); + const BasicBlock *PredBB) const; + + Value *DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB) { + return const_cast<Value *>( + static_cast<const Value *>(this)->DoPHITranslation(CurBB, PredBB)); } /// \brief The maximum alignment for instructions. diff --git a/include/llvm/IR/ValueHandle.h b/include/llvm/IR/ValueHandle.h index a4d4893a9bc9..4838bac9e0f7 100644 --- a/include/llvm/IR/ValueHandle.h +++ b/include/llvm/IR/ValueHandle.h @@ -98,6 +98,15 @@ protected: V != DenseMapInfo<Value *>::getTombstoneKey(); } + /// \brief Remove this ValueHandle from its current use list. + void RemoveFromUseList(); + + /// \brief Clear the underlying pointer without clearing the use list. + /// + /// This should only be used if a derived class has manually removed the + /// handle from the use list. + void clearValPtr() { V = nullptr; } + public: // Callbacks made from Value. static void ValueIsDeleted(Value *V); @@ -120,8 +129,6 @@ private: /// \brief Add this ValueHandle to the use list for V. void AddToUseList(); - /// \brief Remove this ValueHandle from its current use list. - void RemoveFromUseList(); }; /// \brief Value handle that is nullable, but tries to track the Value. @@ -259,7 +266,6 @@ struct isPodLike<AssertingVH<T> > { #endif }; - /// \brief Value handle that tracks a Value across RAUW. /// /// TrackingVH is designed for situations where a client needs to hold a handle @@ -370,6 +376,130 @@ public: virtual void allUsesReplacedWith(Value *) {} }; +/// Value handle that poisons itself if the Value is deleted. +/// +/// This is a Value Handle that points to a value and poisons itself if the +/// value is destroyed while the handle is still live. This is very useful for +/// catching dangling pointer bugs where an \c AssertingVH cannot be used +/// because the dangling handle needs to outlive the value without ever being +/// used. +/// +/// One particularly useful place to use this is as the Key of a map. Dangling +/// pointer bugs often lead to really subtle bugs that only occur if another +/// object happens to get allocated to the same address as the old one. Using +/// a PoisoningVH ensures that an assert is triggered if looking up a new value +/// in the map finds a handle from the old value. +/// +/// Note that a PoisoningVH handle does *not* follow values across RAUW +/// operations. This means that RAUW's need to explicitly update the +/// PoisoningVH's as it moves. This is required because in non-assert mode this +/// class turns into a trivial wrapper around a pointer. +template <typename ValueTy> +class PoisoningVH +#ifndef NDEBUG + final : public CallbackVH +#endif +{ + friend struct DenseMapInfo<PoisoningVH<ValueTy>>; + + // Convert a ValueTy*, which may be const, to the raw Value*. + static Value *GetAsValue(Value *V) { return V; } + static Value *GetAsValue(const Value *V) { return const_cast<Value *>(V); } + +#ifndef NDEBUG + /// A flag tracking whether this value has been poisoned. + /// + /// On delete and RAUW, we leave the value pointer alone so that as a raw + /// pointer it produces the same value (and we fit into the same key of + /// a hash table, etc), but we poison the handle so that any top-level usage + /// will fail. + bool Poisoned = false; + + Value *getRawValPtr() const { return ValueHandleBase::getValPtr(); } + void setRawValPtr(Value *P) { ValueHandleBase::operator=(P); } + + /// Handle deletion by poisoning the handle. + void deleted() override { + assert(!Poisoned && "Tried to delete an already poisoned handle!"); + Poisoned = true; + RemoveFromUseList(); + } + + /// Handle RAUW by poisoning the handle. + void allUsesReplacedWith(Value *) override { + assert(!Poisoned && "Tried to RAUW an already poisoned handle!"); + Poisoned = true; + RemoveFromUseList(); + } +#else // NDEBUG + Value *ThePtr = nullptr; + + Value *getRawValPtr() const { return ThePtr; } + void setRawValPtr(Value *P) { ThePtr = P; } +#endif + + ValueTy *getValPtr() const { + assert(!Poisoned && "Accessed a poisoned value handle!"); + return static_cast<ValueTy *>(getRawValPtr()); + } + void setValPtr(ValueTy *P) { setRawValPtr(GetAsValue(P)); } + +public: + PoisoningVH() = default; +#ifndef NDEBUG + PoisoningVH(ValueTy *P) : CallbackVH(GetAsValue(P)) {} + PoisoningVH(const PoisoningVH &RHS) + : CallbackVH(RHS), Poisoned(RHS.Poisoned) {} + ~PoisoningVH() { + if (Poisoned) + clearValPtr(); + } + PoisoningVH &operator=(const PoisoningVH &RHS) { + if (Poisoned) + clearValPtr(); + CallbackVH::operator=(RHS); + Poisoned = RHS.Poisoned; + return *this; + } +#else + PoisoningVH(ValueTy *P) : ThePtr(GetAsValue(P)) {} +#endif + + operator ValueTy *() const { return getValPtr(); } + + ValueTy *operator->() const { return getValPtr(); } + ValueTy &operator*() const { return *getValPtr(); } +}; + +// Specialize DenseMapInfo to allow PoisoningVH to participate in DenseMap. +template <typename T> struct DenseMapInfo<PoisoningVH<T>> { + static inline PoisoningVH<T> getEmptyKey() { + PoisoningVH<T> Res; + Res.setRawValPtr(DenseMapInfo<Value *>::getEmptyKey()); + return Res; + } + static inline PoisoningVH<T> getTombstoneKey() { + PoisoningVH<T> Res; + Res.setRawValPtr(DenseMapInfo<Value *>::getTombstoneKey()); + return Res; + } + static unsigned getHashValue(const PoisoningVH<T> &Val) { + return DenseMapInfo<Value *>::getHashValue(Val.getRawValPtr()); + } + static bool isEqual(const PoisoningVH<T> &LHS, const PoisoningVH<T> &RHS) { + return DenseMapInfo<Value *>::isEqual(LHS.getRawValPtr(), + RHS.getRawValPtr()); + } +}; + +template <typename T> struct isPodLike<PoisoningVH<T>> { +#ifdef NDEBUG + static const bool value = true; +#else + static const bool value = false; +#endif +}; + } // End llvm namespace #endif diff --git a/include/llvm/IR/ValueSymbolTable.h b/include/llvm/IR/ValueSymbolTable.h index 61a12db403ea..9e86751dae6f 100644 --- a/include/llvm/IR/ValueSymbolTable.h +++ b/include/llvm/IR/ValueSymbolTable.h @@ -1,4 +1,4 @@ -//===-- llvm/ValueSymbolTable.h - Implement a Value Symtab ------*- C++ -*-===// +//===- llvm/ValueSymbolTable.h - Implement a Value Symtab -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,31 +15,36 @@ #define LLVM_IR_VALUESYMBOLTABLE_H #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Value.h" -#include "llvm/Support/DataTypes.h" +#include <cstdint> namespace llvm { - template <typename ValueSubClass> class SymbolTableListTraits; - template <unsigned InternalLen> class SmallString; - class BasicBlock; - class Function; - class NamedMDNode; - class Module; - class StringRef; + +class Argument; +class BasicBlock; +class Function; +class GlobalAlias; +class GlobalIFunc; +class GlobalVariable; +class Instruction; +template <unsigned InternalLen> class SmallString; +template <typename ValueSubClass> class SymbolTableListTraits; /// This class provides a symbol table of name/value pairs. It is essentially /// a std::map<std::string,Value*> but has a controlled interface provided by /// LLVM as well as ensuring uniqueness of names. /// class ValueSymbolTable { - friend class Value; friend class SymbolTableListTraits<Argument>; friend class SymbolTableListTraits<BasicBlock>; - friend class SymbolTableListTraits<Instruction>; friend class SymbolTableListTraits<Function>; - friend class SymbolTableListTraits<GlobalVariable>; friend class SymbolTableListTraits<GlobalAlias>; friend class SymbolTableListTraits<GlobalIFunc>; + friend class SymbolTableListTraits<GlobalVariable>; + friend class SymbolTableListTraits<Instruction>; + friend class Value; + /// @name Types /// @{ public: @@ -55,14 +60,14 @@ public: /// @} /// @name Constructors /// @{ -public: - ValueSymbolTable() : vmap(0), LastUnique(0) {} + + ValueSymbolTable() : vmap(0) {} ~ValueSymbolTable(); /// @} /// @name Accessors /// @{ -public: + /// This method finds the value with the given \p Name in the /// the symbol table. /// @returns the value associated with the \p Name @@ -84,7 +89,7 @@ public: /// @} /// @name Iteration /// @{ -public: + /// @brief Get an iterator that from the beginning of the symbol table. inline iterator begin() { return vmap.begin(); } @@ -122,13 +127,13 @@ private: /// @} /// @name Internal Data /// @{ -private: + ValueMap vmap; ///< The map that holds the symbol table. - mutable uint32_t LastUnique; ///< Counter for tracking unique names + mutable uint32_t LastUnique = 0; ///< Counter for tracking unique names /// @} }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_VALUESYMBOLTABLE_H diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index a34ebaf18a03..15c8ff6d04de 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -53,13 +53,13 @@ void initializeCoroutines(PassRegistry&); void initializeCodeGen(PassRegistry&); /// Initialize all passes linked into the GlobalISel library. -void initializeGlobalISel(PassRegistry &Registry); +void initializeGlobalISel(PassRegistry&); /// Initialize all passes linked into the CodeGen library. void initializeTarget(PassRegistry&); void initializeAAEvalLegacyPassPass(PassRegistry&); -void initializeAAResultsWrapperPassPass(PassRegistry &); +void initializeAAResultsWrapperPassPass(PassRegistry&); void initializeADCELegacyPassPass(PassRegistry&); void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&); void initializeAddressSanitizerModulePass(PassRegistry&); @@ -68,37 +68,39 @@ void initializeAliasSetPrinterPass(PassRegistry&); void initializeAlignmentFromAssumptionsPass(PassRegistry&); void initializeAlwaysInlinerLegacyPassPass(PassRegistry&); void initializeArgPromotionPass(PassRegistry&); -void initializeAssumptionCacheTrackerPass(PassRegistry &); +void initializeAssumptionCacheTrackerPass(PassRegistry&); void initializeAtomicExpandPass(PassRegistry&); void initializeBBVectorizePass(PassRegistry&); -void initializeBDCELegacyPassPass(PassRegistry &); +void initializeBDCELegacyPassPass(PassRegistry&); void initializeBarrierNoopPass(PassRegistry&); void initializeBasicAAWrapperPassPass(PassRegistry&); void initializeBlockExtractorPassPass(PassRegistry&); void initializeBlockFrequencyInfoWrapperPassPass(PassRegistry&); void initializeBoundsCheckingPass(PassRegistry&); +void initializeBranchCoalescingPass(PassRegistry&); void initializeBranchFolderPassPass(PassRegistry&); void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry&); void initializeBranchRelaxationPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); +void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&); void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&); void initializeCFGPrinterLegacyPassPass(PassRegistry&); -void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&); void initializeCFGSimplifyPassPass(PassRegistry&); +void initializeLateCFGSimplifyPassPass(PassRegistry&); void initializeCFGViewerLegacyPassPass(PassRegistry&); void initializeCFLAndersAAWrapperPassPass(PassRegistry&); void initializeCFLSteensAAWrapperPassPass(PassRegistry&); void initializeCallGraphDOTPrinterPass(PassRegistry&); void initializeCallGraphPrinterLegacyPassPass(PassRegistry&); void initializeCallGraphViewerPass(PassRegistry&); -void initializeCallGraphWrapperPassPass(PassRegistry &); +void initializeCallGraphWrapperPassPass(PassRegistry&); void initializeCodeGenPreparePass(PassRegistry&); -void initializeCountingFunctionInserterPass(PassRegistry&); void initializeConstantHoistingLegacyPassPass(PassRegistry&); -void initializeConstantMergeLegacyPassPass(PassRegistry &); +void initializeConstantMergeLegacyPassPass(PassRegistry&); void initializeConstantPropagationPass(PassRegistry&); void initializeCorrelatedValuePropagationPass(PassRegistry&); void initializeCostModelAnalysisPass(PassRegistry&); +void initializeCountingFunctionInserterPass(PassRegistry&); void initializeCrossDSOCFIPass(PassRegistry&); void initializeDAEPass(PassRegistry&); void initializeDAHPass(PassRegistry&); @@ -107,7 +109,7 @@ void initializeDSELegacyPassPass(PassRegistry&); void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); -void initializeDelinearizationPass(PassRegistry &); +void initializeDelinearizationPass(PassRegistry&); void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); void initializeDependenceAnalysisWrapperPassPass(PassRegistry&); @@ -120,27 +122,27 @@ void initializeDomViewerPass(PassRegistry&); void initializeDominanceFrontierWrapperPassPass(PassRegistry&); void initializeDominatorTreeWrapperPassPass(PassRegistry&); void initializeDwarfEHPreparePass(PassRegistry&); -void initializeEarlyCSELegacyPassPass(PassRegistry &); -void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry &); +void initializeEarlyCSELegacyPassPass(PassRegistry&); +void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry&); void initializeEarlyIfConverterPass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); void initializeEfficiencySanitizerPass(PassRegistry&); -void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry &); -void initializeRAGreedyPass(PassRegistry&); -void initializeGVNHoistLegacyPassPass(PassRegistry &); +void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry&); void initializeExpandISelPseudosPass(PassRegistry&); void initializeExpandPostRAPass(PassRegistry&); void initializeExternalAAWrapperPassPass(PassRegistry&); +void initializeFEntryInserterPass(PassRegistry&); void initializeFinalizeMachineBundlesPass(PassRegistry&); void initializeFlattenCFGPassPass(PassRegistry&); void initializeFloat2IntLegacyPassPass(PassRegistry&); void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&); void initializeForwardControlFlowIntegrityPass(PassRegistry&); -void initializeFuncletLayoutPass(PassRegistry &); -void initializeFunctionImportLegacyPassPass(PassRegistry &); +void initializeFuncletLayoutPass(PassRegistry&); +void initializeFunctionImportLegacyPassPass(PassRegistry&); void initializeGCMachineCodeAnalysisPass(PassRegistry&); void initializeGCModuleInfoPass(PassRegistry&); void initializeGCOVProfilerLegacyPassPass(PassRegistry&); +void initializeGVNHoistLegacyPassPass(PassRegistry&); void initializeGVNLegacyPassPass(PassRegistry&); void initializeGlobalDCELegacyPassPass(PassRegistry&); void initializeGlobalMergePass(PassRegistry&); @@ -149,32 +151,35 @@ void initializeGlobalSplitPass(PassRegistry&); void initializeGlobalsAAWrapperPassPass(PassRegistry&); void initializeGuardWideningLegacyPassPass(PassRegistry&); void initializeIPCPPass(PassRegistry&); -void initializeIPSCCPLegacyPassPass(PassRegistry &); -void initializeIRTranslatorPass(PassRegistry &); +void initializeIPSCCPLegacyPassPass(PassRegistry&); +void initializeIRTranslatorPass(PassRegistry&); void initializeIVUsersWrapperPassPass(PassRegistry&); void initializeIfConverterPass(PassRegistry&); void initializeImplicitNullChecksPass(PassRegistry&); void initializeIndVarSimplifyLegacyPassPass(PassRegistry&); void initializeInductiveRangeCheckEliminationPass(PassRegistry&); +void initializeInferAddressSpacesPass(PassRegistry&); void initializeInferFunctionAttrsLegacyPassPass(PassRegistry&); void initializeInlineCostAnalysisPass(PassRegistry&); void initializeInstCountPass(PassRegistry&); void initializeInstNamerPass(PassRegistry&); void initializeInstSimplifierPass(PassRegistry&); -void initializeInstrProfilingLegacyPassPass(PassRegistry &); +void initializeInstrProfilingLegacyPassPass(PassRegistry&); void initializeInstructionCombiningPassPass(PassRegistry&); -void initializeInstructionSelectPass(PassRegistry &); -void initializeInterleavedAccessPass(PassRegistry &); +void initializeInstructionSelectPass(PassRegistry&); +void initializeInterleavedAccessPass(PassRegistry&); void initializeInternalizeLegacyPassPass(PassRegistry&); void initializeIntervalPartitionPass(PassRegistry&); void initializeJumpThreadingPass(PassRegistry&); -void initializeLCSSAWrapperPassPass(PassRegistry&); void initializeLCSSAVerificationPassPass(PassRegistry&); -void initializeLegacyLICMPassPass(PassRegistry&); -void initializeLegacyLoopSinkPassPass(PassRegistry&); -void initializeLazyBranchProbabilityInfoPassPass(PassRegistry&); +void initializeLCSSAWrapperPassPass(PassRegistry&); void initializeLazyBlockFrequencyInfoPassPass(PassRegistry&); +void initializeLazyBranchProbabilityInfoPassPass(PassRegistry&); +void initializeLazyMachineBlockFrequencyInfoPassPass(PassRegistry&); void initializeLazyValueInfoWrapperPassPass(PassRegistry&); +void initializeLegacyLICMPassPass(PassRegistry&); +void initializeLegacyLoopSinkPassPass(PassRegistry&); +void initializeLazyValueInfoPrinterPass(PassRegistry&); void initializeLegalizerPass(PassRegistry&); void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&); void initializeLintPass(PassRegistry&); @@ -185,20 +190,21 @@ void initializeLiveRegMatrixPass(PassRegistry&); void initializeLiveStacksPass(PassRegistry&); void initializeLiveVariablesPass(PassRegistry&); void initializeLoadCombinePass(PassRegistry&); -void initializeLoaderPassPass(PassRegistry&); void initializeLoadStoreVectorizerPass(PassRegistry&); +void initializeLoaderPassPass(PassRegistry&); void initializeLocalStackSlotPassPass(PassRegistry&); void initializeLoopAccessLegacyAnalysisPass(PassRegistry&); -void initializeLoopDataPrefetchLegacyPassPass(PassRegistry &); +void initializeLoopDataPrefetchLegacyPassPass(PassRegistry&); void initializeLoopDeletionLegacyPassPass(PassRegistry&); void initializeLoopDistributeLegacyPass(PassRegistry&); void initializeLoopExtractorPass(PassRegistry&); void initializeLoopIdiomRecognizeLegacyPassPass(PassRegistry&); void initializeLoopInfoWrapperPassPass(PassRegistry&); void initializeLoopInstSimplifyLegacyPassPass(PassRegistry&); -void initializeLoopInterchangePass(PassRegistry &); +void initializeLoopInterchangePass(PassRegistry&); void initializeLoopLoadEliminationPass(PassRegistry&); void initializeLoopPassPass(PassRegistry&); +void initializeLoopPredicationLegacyPassPass(PassRegistry&); void initializeLoopRerollPass(PassRegistry&); void initializeLoopRotateLegacyPassPass(PassRegistry&); void initializeLoopSimplifyCFGLegacyPassPass(PassRegistry&); @@ -208,8 +214,8 @@ void initializeLoopUnrollPass(PassRegistry&); void initializeLoopUnswitchPass(PassRegistry&); void initializeLoopVectorizePass(PassRegistry&); void initializeLoopVersioningLICMPass(PassRegistry&); -void initializeLoopVersioningPassPass(PassRegistry &); -void initializeLowerAtomicLegacyPassPass(PassRegistry &); +void initializeLoopVersioningPassPass(PassRegistry&); +void initializeLowerAtomicLegacyPassPass(PassRegistry&); void initializeLowerEmuTLSPass(PassRegistry&); void initializeLowerExpectIntrinsicPass(PassRegistry&); void initializeLowerGuardIntrinsicLegacyPassPass(PassRegistry&); @@ -223,7 +229,7 @@ void initializeMachineBlockPlacementPass(PassRegistry&); void initializeMachineBlockPlacementStatsPass(PassRegistry&); void initializeMachineBranchProbabilityInfoPass(PassRegistry&); void initializeMachineCSEPass(PassRegistry&); -void initializeMachineCombinerPass(PassRegistry &); +void initializeMachineCombinerPass(PassRegistry&); void initializeMachineCopyPropagationPass(PassRegistry&); void initializeMachineDominanceFrontierPass(PassRegistry&); void initializeMachineDominatorTreePass(PassRegistry&); @@ -231,6 +237,8 @@ void initializeMachineFunctionPrinterPassPass(PassRegistry&); void initializeMachineLICMPass(PassRegistry&); void initializeMachineLoopInfoPass(PassRegistry&); void initializeMachineModuleInfoPass(PassRegistry&); +void initializeMachineOptimizationRemarkEmitterPassPass(PassRegistry&); +void initializeMachineOutlinerPass(PassRegistry&); void initializeMachinePipelinerPass(PassRegistry&); void initializeMachinePostDominatorTreePass(PassRegistry&); void initializeMachineRegionInfoPassPass(PassRegistry&); @@ -242,17 +250,17 @@ void initializeMemCpyOptLegacyPassPass(PassRegistry&); void initializeMemDepPrinterPass(PassRegistry&); void initializeMemDerefPrinterPass(PassRegistry&); void initializeMemoryDependenceWrapperPassPass(PassRegistry&); +void initializeMemorySSAPrinterLegacyPassPass(PassRegistry&); void initializeMemorySSAWrapperPassPass(PassRegistry&); -void initializeMemorySSAPrinterLegacyPassPass(PassRegistry &); void initializeMemorySanitizerPass(PassRegistry&); void initializeMergeFunctionsPass(PassRegistry&); -void initializeMergedLoadStoreMotionLegacyPassPass(PassRegistry &); +void initializeMergedLoadStoreMotionLegacyPassPass(PassRegistry&); void initializeMetaRenamerPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&); -void initializeModuleSummaryIndexWrapperPassPass(PassRegistry &); -void initializeNameAnonGlobalLegacyPassPass(PassRegistry &); -void initializeNaryReassociateLegacyPassPass(PassRegistry &); -void initializeNewGVNPass(PassRegistry&); +void initializeModuleSummaryIndexWrapperPassPass(PassRegistry&); +void initializeNameAnonGlobalLegacyPassPass(PassRegistry&); +void initializeNaryReassociateLegacyPassPass(PassRegistry&); +void initializeNewGVNLegacyPassPass(PassRegistry&); void initializeObjCARCAAWrapperPassPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&); void initializeObjCARCContractPass(PassRegistry&); @@ -260,17 +268,18 @@ void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCOptPass(PassRegistry&); void initializeOptimizationRemarkEmitterWrapperPassPass(PassRegistry&); void initializeOptimizePHIsPass(PassRegistry&); -void initializePAEvalPass(PassRegistry &); +void initializePAEvalPass(PassRegistry&); void initializePEIPass(PassRegistry&); void initializePGOIndirectCallPromotionLegacyPassPass(PassRegistry&); void initializePGOInstrumentationGenLegacyPassPass(PassRegistry&); void initializePGOInstrumentationUseLegacyPassPass(PassRegistry&); +void initializePGOMemOPSizeOptLegacyPassPass(PassRegistry&); void initializePHIEliminationPass(PassRegistry&); -void initializePhysicalRegisterUsageInfoPass(PassRegistry &); -void initializePartialInlinerLegacyPassPass(PassRegistry &); -void initializePartiallyInlineLibCallsLegacyPassPass(PassRegistry &); -void initializePatchableFunctionPass(PassRegistry &); +void initializePartialInlinerLegacyPassPass(PassRegistry&); +void initializePartiallyInlineLibCallsLegacyPassPass(PassRegistry&); +void initializePatchableFunctionPass(PassRegistry&); void initializePeepholeOptimizerPass(PassRegistry&); +void initializePhysicalRegisterUsageInfoPass(PassRegistry&); void initializePlaceBackedgeSafepointsImplPass(PassRegistry&); void initializePlaceSafepointsPass(PassRegistry&); void initializePostDomOnlyPrinterPass(PassRegistry&); @@ -283,15 +292,17 @@ void initializePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); void initializePostRAHazardRecognizerPass(PassRegistry&); void initializePostRASchedulerPass(PassRegistry&); void initializePreISelIntrinsicLoweringLegacyPassPass(PassRegistry&); +void initializePredicateInfoPrinterLegacyPassPass(PassRegistry&); void initializePrintBasicBlockPassPass(PassRegistry&); void initializePrintFunctionPassWrapperPass(PassRegistry&); void initializePrintModulePassWrapperPass(PassRegistry&); void initializeProcessImplicitDefsPass(PassRegistry&); -void initializeProfileSummaryInfoWrapperPassPass(PassRegistry &); -void initializePromoteLegacyPassPass(PassRegistry &); +void initializeProfileSummaryInfoWrapperPassPass(PassRegistry&); +void initializePromoteLegacyPassPass(PassRegistry&); void initializePruneEHPass(PassRegistry&); +void initializeRAGreedyPass(PassRegistry&); void initializeReassociateLegacyPassPass(PassRegistry&); -void initializeRegBankSelectPass(PassRegistry &); +void initializeRegBankSelectPass(PassRegistry&); void initializeRegToMemPass(PassRegistry&); void initializeRegionInfoPassPass(PassRegistry&); void initializeRegionOnlyPrinterPass(PassRegistry&); @@ -299,13 +310,12 @@ void initializeRegionOnlyViewerPass(PassRegistry&); void initializeRegionPrinterPass(PassRegistry&); void initializeRegionViewerPass(PassRegistry&); void initializeRegisterCoalescerPass(PassRegistry&); -void initializeStripGCRelocatesPass(PassRegistry&); void initializeRenameIndependentSubregsPass(PassRegistry&); -void initializeResetMachineFunctionPass(PassRegistry &); +void initializeResetMachineFunctionPass(PassRegistry&); void initializeReversePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); void initializeRewriteStatepointsForGCPass(PassRegistry&); void initializeRewriteSymbolsLegacyPassPass(PassRegistry&); -void initializeSCCPLegacyPassPass(PassRegistry &); +void initializeSCCPLegacyPassPass(PassRegistry&); void initializeSCEVAAWrapperPassPass(PassRegistry&); void initializeSLPVectorizerPass(PassRegistry&); void initializeSROALegacyPassPass(PassRegistry&); @@ -315,9 +325,9 @@ void initializeSanitizerCoverageModulePass(PassRegistry&); void initializeScalarEvolutionWrapperPassPass(PassRegistry&); void initializeScalarizerPass(PassRegistry&); void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); -void initializeSeparateConstOffsetFromGEPPass(PassRegistry &); +void initializeSeparateConstOffsetFromGEPPass(PassRegistry&); void initializeShadowStackGCLoweringPass(PassRegistry&); -void initializeShrinkWrapPass(PassRegistry &); +void initializeShrinkWrapPass(PassRegistry&); void initializeSimpleInlinerPass(PassRegistry&); void initializeSingleLoopExtractorPass(PassRegistry&); void initializeSinkingLegacyPassPass(PassRegistry&); @@ -329,19 +339,20 @@ void initializeStackColoringPass(PassRegistry&); void initializeStackMapLivenessPass(PassRegistry&); void initializeStackProtectorPass(PassRegistry&); void initializeStackSlotColoringPass(PassRegistry&); -void initializeStraightLineStrengthReducePass(PassRegistry &); +void initializeStraightLineStrengthReducePass(PassRegistry&); void initializeStripDeadDebugInfoPass(PassRegistry&); void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); +void initializeStripGCRelocatesPass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripNonLineTableDebugInfoPass(PassRegistry&); void initializeStripSymbolsPass(PassRegistry&); void initializeStructurizeCFGPass(PassRegistry&); void initializeTailCallElimPass(PassRegistry&); void initializeTailDuplicatePassPass(PassRegistry&); -void initializeTargetLibraryInfoWrapperPassPass(PassRegistry &); +void initializeTargetLibraryInfoWrapperPassPass(PassRegistry&); void initializeTargetPassConfigPass(PassRegistry&); -void initializeTargetTransformInfoWrapperPassPass(PassRegistry &); +void initializeTargetTransformInfoWrapperPassPass(PassRegistry&); void initializeThreadSanitizerPass(PassRegistry&); void initializeTwoAddressInstructionPassPass(PassRegistry&); void initializeTypeBasedAAWrapperPassPass(PassRegistry&); @@ -352,11 +363,11 @@ void initializeUnreachableMachineBlockElimPass(PassRegistry&); void initializeVerifierLegacyPassPass(PassRegistry&); void initializeVirtRegMapPass(PassRegistry&); void initializeVirtRegRewriterPass(PassRegistry&); -void initializeWholeProgramDevirtPass(PassRegistry &); +void initializeWholeProgramDevirtPass(PassRegistry&); void initializeWinEHPreparePass(PassRegistry&); -void initializeWriteBitcodePassPass(PassRegistry &); -void initializeWriteThinLTOBitcodePass(PassRegistry &); -void initializeXRayInstrumentationPass(PassRegistry &); +void initializeWriteBitcodePassPass(PassRegistry&); +void initializeWriteThinLTOBitcodePass(PassRegistry&); +void initializeXRayInstrumentationPass(PassRegistry&); } #endif diff --git a/include/llvm/LTO/Caching.h b/include/llvm/LTO/Caching.h index 3b96bd1dc301..f5ec70e081c1 100644 --- a/include/llvm/LTO/Caching.h +++ b/include/llvm/LTO/Caching.h @@ -24,12 +24,19 @@ namespace lto { /// This type defines the callback to add a pre-existing native object file /// (e.g. in a cache). /// -/// File callbacks must be thread safe. -typedef std::function<void(unsigned Task, StringRef Path)> AddFileFn; +/// MB->getBufferIdentifier() is a valid path for the file at the time that it +/// was opened, but clients should prefer to access MB directly in order to +/// avoid a potential race condition. +/// +/// Buffer callbacks must be thread safe. +typedef std::function<void(unsigned Task, std::unique_ptr<MemoryBuffer> MB)> + AddBufferFn; /// Create a local file system cache which uses the given cache directory and -/// file callback. -NativeObjectCache localCache(std::string CacheDirectoryPath, AddFileFn AddFile); +/// file callback. This function also creates the cache directory if it does not +/// already exist. +Expected<NativeObjectCache> localCache(StringRef CacheDirectoryPath, + AddBufferFn AddBuffer); } // namespace lto } // namespace llvm diff --git a/include/llvm/LTO/Config.h b/include/llvm/LTO/Config.h index 3aa48c9f7c28..ede6637dfa4d 100644 --- a/include/llvm/LTO/Config.h +++ b/include/llvm/LTO/Config.h @@ -17,6 +17,7 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include <functional> @@ -41,6 +42,7 @@ struct Config { Reloc::Model RelocModel = Reloc::PIC_; CodeModel::Model CodeModel = CodeModel::Default; CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default; + TargetMachine::CodeGenFileType CGFileType = TargetMachine::CGFT_ObjectFile; unsigned OptLevel = 2; bool DisableVerify = false; @@ -68,6 +70,12 @@ struct Config { /// Sample PGO profile path. std::string SampleProfile; + /// Optimization remarks file path. + std::string RemarksFilename = ""; + + /// Whether to emit optimization remarks with hotness informations. + bool RemarksWithHotness = false; + bool ShouldDiscardValueNames = true; DiagnosticHandlerFunction DiagHandler; diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index 78ac73a7418c..3772592757be 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -19,12 +19,14 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" -#include "llvm/CodeGen/Analysis.h" +#include "llvm/Analysis/ObjectUtils.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/LTO/Config.h" #include "llvm/Linker/IRMover.h" -#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/IRSymtab.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/thread.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/IPO/FunctionImport.h" @@ -68,25 +70,35 @@ std::string getThinLTOOutputFile(const std::string &Path, const std::string &OldPrefix, const std::string &NewPrefix); +/// Setup optimization remarks. +Expected<std::unique_ptr<tool_output_file>> +setupOptimizationRemarks(LLVMContext &Context, StringRef LTORemarksFilename, + bool LTOPassRemarksWithHotness, int Count = -1); + class LTO; struct SymbolResolution; class ThinBackendProc; -/// An input file. This is a wrapper for ModuleSymbolTable that exposes only the +/// An input file. This is a symbol table wrapper that only exposes the /// information that an LTO client should need in order to do symbol resolution. class InputFile { +public: + class Symbol; + +private: // FIXME: Remove LTO class friendship once we have bitcode symbol tables. friend LTO; InputFile() = default; - // FIXME: Remove the LLVMContext once we have bitcode symbol tables. - LLVMContext Ctx; - struct InputModule; - std::vector<InputModule> Mods; - ModuleSymbolTable SymTab; + std::vector<BitcodeModule> Mods; + SmallVector<char, 0> Strtab; + std::vector<Symbol> Symbols; - std::vector<StringRef> Comdats; - DenseMap<const Comdat *, unsigned> ComdatMap; + // [begin, end) for each module + std::vector<std::pair<size_t, size_t>> ModuleSymIndices; + + StringRef TargetTriple, SourceFileName, COFFLinkerOpts; + std::vector<StringRef> ComdatTable; public: ~InputFile(); @@ -94,143 +106,52 @@ public: /// Create an InputFile. static Expected<std::unique_ptr<InputFile>> create(MemoryBufferRef Object); - class symbol_iterator; - - /// This is a wrapper for ArrayRef<ModuleSymbolTable::Symbol>::iterator that - /// exposes only the information that an LTO client should need in order to do - /// symbol resolution. - /// - /// This object is ephemeral; it is only valid as long as an iterator obtained - /// from symbols() refers to it. - class Symbol { - friend symbol_iterator; + /// The purpose of this class is to only expose the symbol information that an + /// LTO client should need in order to do symbol resolution. + class Symbol : irsymtab::Symbol { friend LTO; - ArrayRef<ModuleSymbolTable::Symbol>::iterator I; - const ModuleSymbolTable &SymTab; - const InputFile *File; - uint32_t Flags; - SmallString<64> Name; - - bool shouldSkip() { - return !(Flags & object::BasicSymbolRef::SF_Global) || - (Flags & object::BasicSymbolRef::SF_FormatSpecific); - } - - void skip() { - ArrayRef<ModuleSymbolTable::Symbol>::iterator E = SymTab.symbols().end(); - while (I != E) { - Flags = SymTab.getSymbolFlags(*I); - if (!shouldSkip()) - break; - ++I; - } - if (I == E) - return; - - Name.clear(); - { - raw_svector_ostream OS(Name); - SymTab.printSymbolName(OS, *I); - } - } - - bool isGV() const { return I->is<GlobalValue *>(); } - GlobalValue *getGV() const { return I->get<GlobalValue *>(); } - public: - Symbol(ArrayRef<ModuleSymbolTable::Symbol>::iterator I, - const ModuleSymbolTable &SymTab, const InputFile *File) - : I(I), SymTab(SymTab), File(File) { - skip(); - } - - /// Returns the mangled name of the global. - StringRef getName() const { return Name; } - - uint32_t getFlags() const { return Flags; } - GlobalValue::VisibilityTypes getVisibility() const { - if (isGV()) - return getGV()->getVisibility(); - return GlobalValue::DefaultVisibility; - } - bool canBeOmittedFromSymbolTable() const { - return isGV() && llvm::canBeOmittedFromSymbolTable(getGV()); - } - bool isTLS() const { - // FIXME: Expose a thread-local flag for module asm symbols. - return isGV() && getGV()->isThreadLocal(); - } - - // Returns the index of the comdat this symbol is in or -1 if the symbol - // is not in a comdat. - // FIXME: We have to return Expected<int> because aliases point to an - // arbitrary ConstantExpr and that might not actually be a constant. That - // means we might not be able to find what an alias is aliased to and - // so find its comdat. - Expected<int> getComdatIndex() const; - - uint64_t getCommonSize() const { - assert(Flags & object::BasicSymbolRef::SF_Common); - if (!isGV()) - return 0; - return getGV()->getParent()->getDataLayout().getTypeAllocSize( - getGV()->getType()->getElementType()); - } - unsigned getCommonAlignment() const { - assert(Flags & object::BasicSymbolRef::SF_Common); - if (!isGV()) - return 0; - return getGV()->getAlignment(); - } - }; - - class symbol_iterator { - Symbol Sym; - - public: - symbol_iterator(ArrayRef<ModuleSymbolTable::Symbol>::iterator I, - const ModuleSymbolTable &SymTab, const InputFile *File) - : Sym(I, SymTab, File) {} - - symbol_iterator &operator++() { - ++Sym.I; - Sym.skip(); - return *this; - } - - symbol_iterator operator++(int) { - symbol_iterator I = *this; - ++*this; - return I; - } - - const Symbol &operator*() const { return Sym; } - const Symbol *operator->() const { return &Sym; } - - bool operator!=(const symbol_iterator &Other) const { - return Sym.I != Other.Sym.I; - } + Symbol(const irsymtab::Symbol &S) : irsymtab::Symbol(S) {} + + using irsymtab::Symbol::isUndefined; + using irsymtab::Symbol::isCommon; + using irsymtab::Symbol::isWeak; + using irsymtab::Symbol::isIndirect; + using irsymtab::Symbol::getName; + using irsymtab::Symbol::getVisibility; + using irsymtab::Symbol::canBeOmittedFromSymbolTable; + using irsymtab::Symbol::isTLS; + using irsymtab::Symbol::getComdatIndex; + using irsymtab::Symbol::getCommonSize; + using irsymtab::Symbol::getCommonAlignment; + using irsymtab::Symbol::getCOFFWeakExternalFallback; + using irsymtab::Symbol::isExecutable; }; /// A range over the symbols in this InputFile. - iterator_range<symbol_iterator> symbols() { - return llvm::make_range( - symbol_iterator(SymTab.symbols().begin(), SymTab, this), - symbol_iterator(SymTab.symbols().end(), SymTab, this)); - } + ArrayRef<Symbol> symbols() const { return Symbols; } + + /// Returns linker options specified in the input file. + StringRef getCOFFLinkerOpts() const { return COFFLinkerOpts; } /// Returns the path to the InputFile. StringRef getName() const; + /// Returns the input file's target triple. + StringRef getTargetTriple() const { return TargetTriple; } + /// Returns the source file path specified at compile time. - StringRef getSourceFileName() const; + StringRef getSourceFileName() const { return SourceFileName; } // Returns a table with all the comdats used by this file. - ArrayRef<StringRef> getComdatTable() const { return Comdats; } + ArrayRef<StringRef> getComdatTable() const { return ComdatTable; } private: - iterator_range<symbol_iterator> module_symbols(InputModule &IM); + ArrayRef<Symbol> module_symbols(unsigned I) const { + const auto &Indices = ModuleSymIndices[I]; + return {Symbols.data() + Indices.first, Symbols.data() + Indices.second}; + } }; /// This class wraps an output stream for a native object. Most clients should @@ -418,20 +339,20 @@ private: // Global mapping from mangled symbol names to resolutions. StringMap<GlobalResolution> GlobalResolutions; - void addSymbolToGlobalRes(SmallPtrSet<GlobalValue *, 8> &Used, - const InputFile::Symbol &Sym, SymbolResolution Res, + void addSymbolToGlobalRes(const InputFile::Symbol &Sym, SymbolResolution Res, unsigned Partition); // These functions take a range of symbol resolutions [ResI, ResE) and consume // the resolutions used by a single input module by incrementing ResI. After // these functions return, [ResI, ResE) will refer to the resolution range for // the remaining modules in the InputFile. - Error addModule(InputFile &Input, InputFile::InputModule &IM, + Error addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE); - Error addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, + Error addRegularLTO(BitcodeModule BM, + ArrayRef<InputFile::Symbol> Syms, + const SymbolResolution *&ResI, const SymbolResolution *ResE); - Error addThinLTO(BitcodeModule BM, Module &M, - iterator_range<InputFile::symbol_iterator> Syms, + Error addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE); Error runRegularLTO(AddStreamFn AddStream); diff --git a/include/llvm/LTO/LTOBackend.h b/include/llvm/LTO/LTOBackend.h index 933503afddc8..d4743f6940ff 100644 --- a/include/llvm/LTO/LTOBackend.h +++ b/include/llvm/LTO/LTOBackend.h @@ -34,14 +34,15 @@ class Target; namespace lto { -/// Runs a regular LTO backend. +/// Runs a regular LTO backend. The regular LTO backend can also act as the +/// regular LTO phase of ThinLTO, which may need to access the combined index. Error backend(Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, - std::unique_ptr<Module> M); + std::unique_ptr<Module> M, ModuleSummaryIndex &CombinedIndex); /// Runs a ThinLTO backend. Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M, - ModuleSummaryIndex &CombinedIndex, + const ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector<StringRef, BitcodeModule> &ModuleMap); diff --git a/include/llvm/LTO/legacy/LTOCodeGenerator.h b/include/llvm/LTO/legacy/LTOCodeGenerator.h index f14682111280..952875fc854e 100644 --- a/include/llvm/LTO/legacy/LTOCodeGenerator.h +++ b/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -41,6 +41,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -174,6 +175,10 @@ struct LTOCodeGenerator { /// Calls \a verifyMergedModuleOnce(). bool compileOptimized(ArrayRef<raw_pwrite_stream *> Out); + /// Enable the Freestanding mode: indicate that the optimizer should not + /// assume builtins are present on the target. + void setFreestanding(bool Enabled) { Freestanding = Enabled; } + void setDiagnosticHandler(lto_diagnostic_handler_t, void *); LLVMContext &getContext() { return Context; } @@ -206,7 +211,6 @@ private: void emitError(const std::string &ErrMsg); void emitWarning(const std::string &ErrMsg); - bool setupOptimizationRemarks(); void finishOptimizationRemarks(); LLVMContext &Context; @@ -237,6 +241,7 @@ private: bool ShouldRestoreGlobalsLinkage = false; TargetMachine::CodeGenFileType FileType = TargetMachine::CGFT_ObjectFile; std::unique_ptr<tool_output_file> DiagnosticOutputFile; + bool Freestanding = false; }; } #endif diff --git a/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h index 0cc3b26e9659..f9545333aabd 100644 --- a/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h +++ b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -20,6 +20,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Target/TargetOptions.h" @@ -140,9 +141,7 @@ public: 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. + CachePruningPolicy Policy; }; /// Provide a path to a directory where to store the cached files for @@ -153,14 +152,14 @@ public: /// negative value (default) to disable pruning. A value of 0 will be ignored. void setCachePruningInterval(int Interval) { if (Interval) - CacheOptions.PruningInterval = Interval; + CacheOptions.Policy.Interval = std::chrono::seconds(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; + CacheOptions.Policy.Expiration = std::chrono::seconds(Expiration); } /** @@ -178,7 +177,7 @@ public: */ void setMaxCacheSizeRelativeToAvailableSpace(unsigned Percentage) { if (Percentage) - CacheOptions.MaxPercentageOfAvailableSpace = Percentage; + CacheOptions.Policy.PercentageOfAvailableSpace = Percentage; } /**@}*/ @@ -206,6 +205,10 @@ public: TMBuilder.Options = std::move(Options); } + /// Enable the Freestanding mode: indicate that the optimizer should not + /// assume builtins are present on the target. + void setFreestanding(bool Enabled) { Freestanding = Enabled; } + /// CodeModel void setCodePICModel(Optional<Reloc::Model> Model) { TMBuilder.RelocModel = Model; @@ -323,6 +326,10 @@ private: /// importing or optimization. bool CodeGenOnly = false; + /// Flag to indicate that the optimizer should not assume builtins are present + /// on the target. + bool Freestanding = false; + /// IR Optimization Level [0-3]. unsigned OptLevel = 3; }; diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index e50137f8e02e..39a86e838bde 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -75,6 +75,7 @@ namespace { (void) llvm::createCallGraphDOTPrinterPass(); (void) llvm::createCallGraphViewerPass(); (void) llvm::createCFGSimplificationPass(); + (void) llvm::createLateCFGSimplificationPass(); (void) llvm::createCFLAndersAAWrapperPass(); (void) llvm::createCFLSteensAAWrapperPass(); (void) llvm::createStructurizeCFGPass(); @@ -96,6 +97,7 @@ namespace { (void) llvm::createPGOInstrumentationGenLegacyPass(); (void) llvm::createPGOInstrumentationUseLegacyPass(); (void) llvm::createPGOIndirectCallPromotionLegacyPass(); + (void) llvm::createPGOMemOPSizeOptLegacyPass(); (void) llvm::createInstrProfilingLegacyPass(); (void) llvm::createFunctionImportPass(); (void) llvm::createFunctionInliningPass(); @@ -116,6 +118,7 @@ namespace { (void) llvm::createLazyValueInfoPass(); (void) llvm::createLoopExtractorPass(); (void) llvm::createLoopInterchangePass(); + (void) llvm::createLoopPredicationPass(); (void) llvm::createLoopSimplifyPass(); (void) llvm::createLoopSimplifyCFGPass(); (void) llvm::createLoopStrengthReducePass(); diff --git a/include/llvm/Linker/IRMover.h b/include/llvm/Linker/IRMover.h index 2a187cbc42f5..235ada47cef4 100644 --- a/include/llvm/Linker/IRMover.h +++ b/include/llvm/Linker/IRMover.h @@ -71,15 +71,11 @@ public: /// 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. - /// - \p LinkModuleInlineAsm is true if the ModuleInlineAsm string in Src - /// should be linked with (concatenated into) the ModuleInlineAsm string - /// for the destination module. It should be true for full LTO, but not - /// when importing for ThinLTO, otherwise we can have duplicate symbols. /// - \p IsPerformingImport is true when this IR link is to perform ThinLTO /// function importing from Src. Error move(std::unique_ptr<Module> Src, ArrayRef<GlobalValue *> ValuesToLink, std::function<void(GlobalValue &GV, ValueAdder Add)> AddLazyFor, - bool LinkModuleInlineAsm, bool IsPerformingImport); + bool IsPerformingImport); Module &getModule() { return Composite; } private: diff --git a/include/llvm/Linker/Linker.h b/include/llvm/Linker/Linker.h index b077c373326f..628e0112bd9d 100644 --- a/include/llvm/Linker/Linker.h +++ b/include/llvm/Linker/Linker.h @@ -10,6 +10,7 @@ #ifndef LLVM_LINKER_LINKER_H #define LLVM_LINKER_LINKER_H +#include "llvm/ADT/StringSet.h" #include "llvm/Linker/IRMover.h" namespace llvm { @@ -29,10 +30,6 @@ public: None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2), - /// Don't force link referenced linkonce definitions, import declaration. - DontForceLinkLinkonceODR = (1 << 3) - }; Linker(Module &M); @@ -41,16 +38,20 @@ public: /// /// Passing OverrideSymbols as true will have symbols from Src /// shadow those in the Dest. - /// 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. + /// + /// Passing InternalizeCallback will have the linker call the function with + /// the new module and a list of global value names to be internalized by the + /// callback. /// /// Returns true on error. bool linkInModule(std::unique_ptr<Module> Src, unsigned Flags = Flags::None, - DenseSet<const GlobalValue *> *GlobalsToImport = nullptr); + std::function<void(Module &, const StringSet<> &)> + InternalizeCallback = {}); static bool linkModules(Module &Dest, std::unique_ptr<Module> Src, - unsigned Flags = Flags::None); + unsigned Flags = Flags::None, + std::function<void(Module &, const StringSet<> &)> + InternalizeCallback = {}); }; } // End llvm namespace diff --git a/include/llvm/MC/ConstantPools.h b/include/llvm/MC/ConstantPools.h index f0c445dbe59f..643902377dd3 100644 --- a/include/llvm/MC/ConstantPools.h +++ b/include/llvm/MC/ConstantPools.h @@ -11,15 +11,17 @@ // //===----------------------------------------------------------------------===// - #ifndef LLVM_MC_CONSTANTPOOLS_H #define LLVM_MC_CONSTANTPOOLS_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/SMLoc.h" +#include <cstdint> namespace llvm { + class MCContext; class MCExpr; class MCSection; @@ -30,6 +32,7 @@ class MCSymbolRefExpr; struct ConstantPoolEntry { ConstantPoolEntry(MCSymbol *L, const MCExpr *Val, unsigned Sz, SMLoc Loc_) : Label(L), Value(Val), Size(Sz), Loc(Loc_) {} + MCSymbol *Label; const MCExpr *Value; unsigned Size; @@ -45,7 +48,7 @@ class ConstantPool { public: // Initialize a new empty constant pool - ConstantPool() {} + ConstantPool() = default; // Add a new entry to the constant pool in the next slot. // \param Value is the new entry to put in the constant pool. @@ -90,6 +93,7 @@ private: ConstantPool *getConstantPool(MCSection *Section); ConstantPool &getOrCreateConstantPool(MCSection *Section); }; + } // end namespace llvm -#endif +#endif // LLVM_MC_CONSTANTPOOLS_H diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index d4bdbcd2baa3..fb21e195b1df 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCAsmBackend.h - MC Asm Backend -----------------*- C++ -*-===// +//===- llvm/MC/MCAsmBackend.h - MC Asm Backend ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,35 +12,33 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCFixup.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/ErrorHandling.h" +#include <cstdint> namespace llvm { + class MCAsmLayout; class MCAssembler; class MCCFIInstruction; -class MCELFObjectTargetWriter; struct MCFixupKindInfo; class MCFragment; class MCInst; -class MCRelaxableFragment; class MCObjectWriter; -class MCSection; +class MCRelaxableFragment; class MCSubtargetInfo; class MCValue; class raw_pwrite_stream; /// Generic interface to target specific assembler backends. class MCAsmBackend { - MCAsmBackend(const MCAsmBackend &) = delete; - void operator=(const MCAsmBackend &) = delete; - protected: // Can only create subclasses. MCAsmBackend(); public: + MCAsmBackend(const MCAsmBackend &) = delete; + MCAsmBackend &operator=(const MCAsmBackend &) = delete; virtual ~MCAsmBackend(); /// lifetime management @@ -73,9 +71,11 @@ public: /// Apply the \p Value for given \p Fixup into the provided data fragment, at /// the offset specified by the fixup and following the fixup kind as - /// appropriate. + /// appropriate. Errors (such as an out of range fixup value) should be + /// reported via \p Ctx. virtual void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel) const = 0; + uint64_t Value, bool IsPCRel, + MCContext &Ctx) const = 0; /// @} @@ -136,6 +136,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCASMBACKEND_H diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index f898bf5288d6..bd2717de9960 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -16,20 +16,22 @@ #ifndef LLVM_MC_MCASMINFO_H #define LLVM_MC_MCASMINFO_H +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCTargetOptions.h" -#include <cassert> #include <vector> namespace llvm { + +class MCContext; class MCExpr; class MCSection; class MCStreamer; class MCSymbol; -class MCContext; namespace WinEH { + enum class EncodingType { Invalid, /// Invalid Alpha, /// Windows Alpha @@ -40,11 +42,14 @@ enum class EncodingType { X86, /// Windows x86, uses no CFI, just EH tables MIPS = Alpha, }; -} + +} // end namespace WinEH namespace LCOMM { + enum LCOMMType { NoAlignment, ByteAlignment, Log2Alignment }; -} + +} // end namespace LCOMM enum class DebugCompressionType { DCT_None, // no compression @@ -61,41 +66,41 @@ protected: // /// Pointer size in bytes. Default is 4. - unsigned PointerSize; + unsigned PointerSize = 4; /// Size of the stack slot reserved for callee-saved registers, in bytes. /// Default is same as pointer size. - unsigned CalleeSaveStackSlotSize; + unsigned CalleeSaveStackSlotSize = 4; /// True if target is little endian. Default is true. - bool IsLittleEndian; + bool IsLittleEndian = true; /// True if target stack grow up. Default is false. - bool StackGrowsUp; + bool StackGrowsUp = false; /// True if this target has the MachO .subsections_via_symbols directive. /// Default is false. - bool HasSubsectionsViaSymbols; + bool HasSubsectionsViaSymbols = false; /// True if this is a MachO target that supports the macho-specific .zerofill /// directive for emitting BSS Symbols. Default is false. - bool HasMachoZeroFillDirective; + bool HasMachoZeroFillDirective = false; /// True if this is a MachO target that supports the macho-specific .tbss /// directive for emitting thread local BSS Symbols. Default is false. - bool HasMachoTBSSDirective; + bool HasMachoTBSSDirective = false; /// This is the maximum possible length of an instruction, which is needed to /// compute the size of an inline asm. Defaults to 4. - unsigned MaxInstLength; + unsigned MaxInstLength = 4; /// Every possible instruction length is a multiple of this value. Factored /// out in .debug_frame and .debug_line. Defaults to 1. - unsigned MinInstAlignment; + unsigned MinInstAlignment = 1; /// The '$' token, when not referencing an identifier or constant, refers to /// the current PC. Defaults to false. - bool DollarIsPC; + bool DollarIsPC = false; /// This string, if specified, is used to separate instructions from each /// other when on the same line. Defaults to ';' @@ -109,10 +114,10 @@ protected: const char *LabelSuffix; // Print the EH begin symbol with an assignment. Defaults to false. - bool UseAssignmentForEHBegin; + bool UseAssignmentForEHBegin = false; // Do we need to create a local symbol for .size? - bool NeedsLocalForSize; + bool NeedsLocalForSize = false; /// This prefix is used for globals like constant pool entries that are /// completely private to the .s file and should not have names in the .o @@ -142,20 +147,20 @@ protected: const char *Code64Directive; /// Which dialect of an assembler variant to use. Defaults to 0 - unsigned AssemblerDialect; + unsigned AssemblerDialect = 0; /// This is true if the assembler allows @ characters in symbol names. /// Defaults to false. - bool AllowAtInName; + bool AllowAtInName = false; /// If this is true, symbol names with invalid characters will be printed in /// quotes. - bool SupportsQuotedNames; + bool SupportsQuotedNames = true; /// This is true if data region markers should be printed as /// ".data_region/.end_data_region" directives. If false, use "$d/$a" labels /// instead. - bool UseDataRegionDirectives; + bool UseDataRegionDirectives = false; //===--- Data Emission Directives -------------------------------------===// @@ -185,13 +190,13 @@ protected: /// If non-null, a directive that is used to emit a word which should be /// relocated as a 64-bit GP-relative offset, e.g. .gpdword on Mips. Defaults - /// to NULL. - const char *GPRel64Directive; + /// to nullptr. + const char *GPRel64Directive = nullptr; /// If non-null, a directive that is used to emit a word which should be /// relocated as a 32-bit GP-relative offset, e.g. .gpword on Mips or .gprel32 - /// on Alpha. Defaults to NULL. - const char *GPRel32Directive; + /// on Alpha. Defaults to nullptr. + const char *GPRel32Directive = nullptr; /// If non-null, directives that are used to emit a word/dword which should /// be relocated as a 32/64-bit DTP/TP-relative offset, e.g. .dtprelword/ @@ -204,14 +209,14 @@ protected: /// This is true if this target uses "Sun Style" syntax for section switching /// ("#alloc,#write" etc) instead of the normal ELF syntax (,"a,w") in /// .section directives. Defaults to false. - bool SunStyleELFSectionSwitchSyntax; + bool SunStyleELFSectionSwitchSyntax = false; /// This is true if this target uses ELF '.section' directive before the /// '.bss' one. It's used for PPC/Linux which doesn't support the '.bss' /// directive only. Defaults to false. - bool UsesELFSectionDirectiveForBSS; + bool UsesELFSectionDirectiveForBSS = false; - bool NeedsDwarfSectionOffsetDirective; + bool NeedsDwarfSectionOffsetDirective = false; //===--- Alignment Information ----------------------------------------===// @@ -219,11 +224,11 @@ protected: /// directives, where N is the number of bytes to align to. Otherwise, it /// emits ".align log2(N)", e.g. 3 to align to an 8 byte boundary. Defaults /// to true. - bool AlignmentIsInBytes; + bool AlignmentIsInBytes = true; /// If non-zero, this is used to fill the executable space created as the /// result of a alignment directive. Defaults to 0 - unsigned TextAlignFillValue; + unsigned TextAlignFillValue = 0; //===--- Global Variable Emission Directives --------------------------===// @@ -236,7 +241,7 @@ protected: /// uses a relocation but it can be suppressed by writing /// a = f - g /// .long a - bool SetDirectiveSuppressesReloc; + bool SetDirectiveSuppressesReloc = false; /// False if the assembler requires that we use /// \code @@ -251,98 +256,98 @@ protected: /// \endcode /// /// Defaults to true. - bool HasAggressiveSymbolFolding; + bool HasAggressiveSymbolFolding = true; /// True is .comm's and .lcomms optional alignment is to be specified in bytes /// instead of log2(n). Defaults to true. - bool COMMDirectiveAlignmentIsInBytes; + bool COMMDirectiveAlignmentIsInBytes = true; /// Describes if the .lcomm directive for the target supports an alignment /// argument and how it is interpreted. Defaults to NoAlignment. - LCOMM::LCOMMType LCOMMDirectiveAlignmentType; + LCOMM::LCOMMType LCOMMDirectiveAlignmentType = LCOMM::NoAlignment; // True if the target allows .align directives on functions. This is true for // most targets, so defaults to true. - bool HasFunctionAlignment; + bool HasFunctionAlignment = true; /// True if the target has .type and .size directives, this is true for most /// ELF targets. Defaults to true. - bool HasDotTypeDotSizeDirective; + bool HasDotTypeDotSizeDirective = true; /// True if the target has a single parameter .file directive, this is true /// for ELF targets. Defaults to true. - bool HasSingleParameterDotFile; + bool HasSingleParameterDotFile = true; /// True if the target has a .ident directive, this is true for ELF targets. /// Defaults to false. - bool HasIdentDirective; + bool HasIdentDirective = false; /// True if this target supports the MachO .no_dead_strip directive. Defaults /// to false. - bool HasNoDeadStrip; + bool HasNoDeadStrip = false; /// True if this target supports the MachO .alt_entry directive. Defaults to /// false. - bool HasAltEntry; + bool HasAltEntry = false; /// Used to declare a global as being a weak symbol. Defaults to ".weak". const char *WeakDirective; /// This directive, if non-null, is used to declare a global as being a weak - /// undefined symbol. Defaults to NULL. - const char *WeakRefDirective; + /// undefined symbol. Defaults to nullptr. + const char *WeakRefDirective = nullptr; /// True if we have a directive to declare a global as being a weak defined /// symbol. Defaults to false. - bool HasWeakDefDirective; + bool HasWeakDefDirective = false; /// True if we have a directive to declare a global as being a weak defined /// symbol that can be hidden (unexported). Defaults to false. - bool HasWeakDefCanBeHiddenDirective; + bool HasWeakDefCanBeHiddenDirective = false; /// True if we have a .linkonce directive. This is used on cygwin/mingw. /// Defaults to false. - bool HasLinkOnceDirective; + bool HasLinkOnceDirective = false; /// This attribute, if not MCSA_Invalid, is used to declare a symbol as having /// hidden visibility. Defaults to MCSA_Hidden. - MCSymbolAttr HiddenVisibilityAttr; + MCSymbolAttr HiddenVisibilityAttr = MCSA_Hidden; /// This attribute, if not MCSA_Invalid, is used to declare an undefined /// symbol as having hidden visibility. Defaults to MCSA_Hidden. - MCSymbolAttr HiddenDeclarationVisibilityAttr; + MCSymbolAttr HiddenDeclarationVisibilityAttr = MCSA_Hidden; /// This attribute, if not MCSA_Invalid, is used to declare a symbol as having /// protected visibility. Defaults to MCSA_Protected - MCSymbolAttr ProtectedVisibilityAttr; + MCSymbolAttr ProtectedVisibilityAttr = MCSA_Protected; //===--- Dwarf Emission Directives -----------------------------------===// /// True if target supports emission of debugging information. Defaults to /// false. - bool SupportsDebugInformation; + bool SupportsDebugInformation = false; /// Exception handling format for the target. Defaults to None. - ExceptionHandling ExceptionsType; + ExceptionHandling ExceptionsType = ExceptionHandling::None; /// Windows exception handling data (.pdata) encoding. Defaults to Invalid. - WinEH::EncodingType WinEHEncodingType; + WinEH::EncodingType WinEHEncodingType = WinEH::EncodingType::Invalid; /// True if Dwarf2 output generally uses relocations for references to other /// .debug_* sections. - bool DwarfUsesRelocationsAcrossSections; + bool DwarfUsesRelocationsAcrossSections = true; /// True if DWARF FDE symbol reference relocations should be replaced by an /// absolute difference. - bool DwarfFDESymbolsUseAbsDiff; + bool DwarfFDESymbolsUseAbsDiff = false; /// True if dwarf register numbers are printed instead of symbolic register /// names in .cfi_* directives. Defaults to false. - bool DwarfRegNumForCFI; + bool DwarfRegNumForCFI = false; /// True if target uses parens to indicate the symbol variant instead of @. /// For example, foo(plt) instead of foo@plt. Defaults to false. - bool UseParensForSymbolVariant; + bool UseParensForSymbolVariant = false; //===--- Prologue State ----------------------------------------------===// @@ -361,11 +366,11 @@ protected: bool PreserveAsmComments; /// Compress DWARF debug sections. Defaults to no compression. - DebugCompressionType CompressDebugSections; + DebugCompressionType CompressDebugSections = DebugCompressionType::DCT_None; /// True if the integrated assembler should interpret 'a >> b' constant /// expressions as logical rather than arithmetic. - bool UseLogicalShr; + bool UseLogicalShr = true; // If true, emit GOTPCRELX/REX_GOTPCRELX instead of GOTPCREL, on // X86_64 ELF. @@ -475,14 +480,17 @@ public: bool needsLocalForSize() const { return NeedsLocalForSize; } StringRef getPrivateGlobalPrefix() const { return PrivateGlobalPrefix; } StringRef getPrivateLabelPrefix() const { return PrivateLabelPrefix; } + bool hasLinkerPrivateGlobalPrefix() const { return LinkerPrivateGlobalPrefix[0] != '\0'; } + StringRef getLinkerPrivateGlobalPrefix() const { if (hasLinkerPrivateGlobalPrefix()) return LinkerPrivateGlobalPrefix; return getPrivateGlobalPrefix(); } + const char *getInlineAsmStart() const { return InlineAsmStart; } const char *getInlineAsmEnd() const { return InlineAsmEnd; } const char *getCode16Directive() const { return Code16Directive; } @@ -491,25 +499,32 @@ public: unsigned getAssemblerDialect() const { return AssemblerDialect; } bool doesAllowAtInName() const { return AllowAtInName; } bool supportsNameQuoting() const { return SupportsQuotedNames; } + bool doesSupportDataRegionDirectives() const { return UseDataRegionDirectives; } + const char *getZeroDirective() const { return ZeroDirective; } const char *getAsciiDirective() const { return AsciiDirective; } const char *getAscizDirective() const { return AscizDirective; } bool getAlignmentIsInBytes() const { return AlignmentIsInBytes; } unsigned getTextAlignFillValue() const { return TextAlignFillValue; } const char *getGlobalDirective() const { return GlobalDirective; } + bool doesSetDirectiveSuppressReloc() const { return SetDirectiveSuppressesReloc; } + bool hasAggressiveSymbolFolding() const { return HasAggressiveSymbolFolding; } + bool getCOMMDirectiveAlignmentIsInBytes() const { return COMMDirectiveAlignmentIsInBytes; } + LCOMM::LCOMMType getLCOMMDirectiveAlignmentType() const { return LCOMMDirectiveAlignmentType; } + bool hasFunctionAlignment() const { return HasFunctionAlignment; } bool hasDotTypeDotSizeDirective() const { return HasDotTypeDotSizeDirective; } bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } @@ -519,22 +534,29 @@ public: const char *getWeakDirective() const { return WeakDirective; } const char *getWeakRefDirective() const { return WeakRefDirective; } bool hasWeakDefDirective() const { return HasWeakDefDirective; } + bool hasWeakDefCanBeHiddenDirective() const { return HasWeakDefCanBeHiddenDirective; } + bool hasLinkOnceDirective() const { return HasLinkOnceDirective; } MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr; } + MCSymbolAttr getHiddenDeclarationVisibilityAttr() const { return HiddenDeclarationVisibilityAttr; } + MCSymbolAttr getProtectedVisibilityAttr() const { return ProtectedVisibilityAttr; } + bool doesSupportDebugInformation() const { return SupportsDebugInformation; } + bool doesSupportExceptionHandling() const { return ExceptionsType != ExceptionHandling::None; } + ExceptionHandling getExceptionHandlingType() const { return ExceptionsType; } WinEH::EncodingType getWinEHEncodingType() const { return WinEHEncodingType; } @@ -558,6 +580,7 @@ public: bool doesDwarfUseRelocationsAcrossSections() const { return DwarfUsesRelocationsAcrossSections; } + bool doDwarfFDESymbolsUseAbsDiff() const { return DwarfFDESymbolsUseAbsDiff; } bool useDwarfRegNumForCFI() const { return DwarfRegNumForCFI; } bool useParensForSymbolVariant() const { return UseParensForSymbolVariant; } @@ -600,6 +623,7 @@ public: void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; } bool hasMipsExpressions() const { return HasMipsExpressions; } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_MC_MCASMINFO_H diff --git a/include/llvm/MC/MCAsmInfoCOFF.h b/include/llvm/MC/MCAsmInfoCOFF.h index 56444f3c7cf5..01c8ae49a6fc 100644 --- a/include/llvm/MC/MCAsmInfoCOFF.h +++ b/include/llvm/MC/MCAsmInfoCOFF.h @@ -1,4 +1,4 @@ -//===-- MCAsmInfoCOFF.h - COFF asm properties -------------------*- C++ -*-===// +//===- MCAsmInfoCOFF.h - COFF asm properties --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -13,24 +13,28 @@ #include "llvm/MC/MCAsmInfo.h" namespace llvm { - class MCAsmInfoCOFF : public MCAsmInfo { - virtual void anchor(); - protected: - explicit MCAsmInfoCOFF(); - }; - - class MCAsmInfoMicrosoft : public MCAsmInfoCOFF { - void anchor() override; - protected: - explicit MCAsmInfoMicrosoft(); - }; - - class MCAsmInfoGNUCOFF : public MCAsmInfoCOFF { - void anchor() override; - protected: - explicit MCAsmInfoGNUCOFF(); - }; -} +class MCAsmInfoCOFF : public MCAsmInfo { + virtual void anchor(); + +protected: + explicit MCAsmInfoCOFF(); +}; + +class MCAsmInfoMicrosoft : public MCAsmInfoCOFF { + void anchor() override; + +protected: + explicit MCAsmInfoMicrosoft(); +}; + +class MCAsmInfoGNUCOFF : public MCAsmInfoCOFF { + void anchor() override; + +protected: + explicit MCAsmInfoGNUCOFF(); +}; + +} // end namespace llvm #endif // LLVM_MC_MCASMINFOCOFF_H diff --git a/include/llvm/MC/MCAsmInfoDarwin.h b/include/llvm/MC/MCAsmInfoDarwin.h index d587c3ce9d54..a533d604a89e 100644 --- a/include/llvm/MC/MCAsmInfoDarwin.h +++ b/include/llvm/MC/MCAsmInfoDarwin.h @@ -1,4 +1,4 @@ -//===---- MCAsmInfoDarwin.h - Darwin asm properties -------------*- C++ -*-===// +//===- MCAsmInfoDarwin.h - Darwin asm properties ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,12 +18,14 @@ #include "llvm/MC/MCAsmInfo.h" namespace llvm { - class MCAsmInfoDarwin : public MCAsmInfo { - public: - explicit MCAsmInfoDarwin(); - bool isSectionAtomizableBySymbols(const MCSection &Section) const override; - }; -} +class MCAsmInfoDarwin : public MCAsmInfo { +public: + explicit MCAsmInfoDarwin(); + + bool isSectionAtomizableBySymbols(const MCSection &Section) const override; +}; + +} // end namespace llvm #endif // LLVM_MC_MCASMINFODARWIN_H diff --git a/include/llvm/MC/MCAsmInfoELF.h b/include/llvm/MC/MCAsmInfoELF.h index f8bb943aac4e..f113afc9885e 100644 --- a/include/llvm/MC/MCAsmInfoELF.h +++ b/include/llvm/MC/MCAsmInfoELF.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCAsmInfoELF.h - ELF Asm info -------------------*- C++ -*-===// +//===- llvm/MC/MCAsmInfoELF.h - ELF Asm info --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -13,6 +13,7 @@ #include "llvm/MC/MCAsmInfo.h" namespace llvm { + class MCAsmInfoELF : public MCAsmInfo { virtual void anchor(); MCSection *getNonexecutableStackSection(MCContext &Ctx) const final; @@ -20,10 +21,11 @@ class MCAsmInfoELF : public MCAsmInfo { 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; + bool UsesNonexecutableStackSection = true; MCAsmInfoELF(); }; -} -#endif +} // end namespace llvm + +#endif // LLVM_MC_MCASMINFOELF_H diff --git a/include/llvm/MC/MCAsmInfoWasm.h b/include/llvm/MC/MCAsmInfoWasm.h new file mode 100644 index 000000000000..bc46cfdf4c4c --- /dev/null +++ b/include/llvm/MC/MCAsmInfoWasm.h @@ -0,0 +1,24 @@ +//===-- llvm/MC/MCAsmInfoWasm.h - Wasm Asm info -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCASMINFOWASM_H +#define LLVM_MC_MCASMINFOWASM_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { +class MCAsmInfoWasm : public MCAsmInfo { + virtual void anchor(); + +protected: + MCAsmInfoWasm(); +}; +} + +#endif diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 641e78994768..c29abaa03a6d 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -10,33 +10,35 @@ #ifndef LLVM_MC_MCASSEMBLER_H #define LLVM_MC_MCASSEMBLER_H -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFragment.h" -#include "llvm/MC/MCInst.h" #include "llvm/MC/MCLinkerOptimizationHint.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <string> +#include <utility> +#include <vector> namespace llvm { -class raw_ostream; + +class MCAsmBackend; class MCAsmLayout; -class MCAssembler; class MCContext; class MCCodeEmitter; -class MCExpr; class MCFragment; class MCObjectWriter; class MCSection; -class MCSubtargetInfo; class MCValue; -class MCAsmBackend; // FIXME: This really doesn't belong here. See comments below. struct IndirectSymbolData { @@ -90,9 +92,6 @@ public: } VersionMinInfoType; private: - MCAssembler(const MCAssembler &) = delete; - void operator=(const MCAssembler &) = delete; - MCContext &Context; MCAsmBackend &Backend; @@ -131,9 +130,9 @@ private: /// By default it's 0, which means bundling is disabled. unsigned BundleAlignSize; - unsigned RelaxAll : 1; - unsigned SubsectionsViaSymbols : 1; - unsigned IncrementalLinkerCompatible : 1; + bool RelaxAll : 1; + bool SubsectionsViaSymbols : 1; + bool IncrementalLinkerCompatible : 1; /// ELF specific e_header flags // It would be good if there were an MCELFAssembler class to hold this. @@ -148,7 +147,6 @@ private: VersionMinInfoType VersionMinInfo; -private: /// Evaluate a fixup to a relocatable expression and the value which should be /// placed into the fixup. /// @@ -201,6 +199,18 @@ private: MCFragment &F, const MCFixup &Fixup); public: + /// Construct a new assembler instance. + // + // FIXME: How are we going to parameterize this? Two obvious options are stay + // 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(const MCAssembler &) = delete; + MCAssembler &operator=(const MCAssembler &) = delete; + ~MCAssembler(); + /// Compute the effective fragment size assuming it is laid out at the given /// \p SectionAddress and \p FragmentOffset. uint64_t computeFragmentSize(const MCAsmLayout &Layout, @@ -240,17 +250,6 @@ public: VersionMinInfo.Update = Update; } -public: - /// Construct a new assembler instance. - // - // FIXME: How are we going to parameterize this? Two obvious options are stay - // 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(); - /// Reuse an assembler instance /// void reset(); @@ -425,4 +424,4 @@ uint64_t computeBundlePadding(const MCAssembler &Assembler, const MCFragment *F, } // end namespace llvm -#endif +#endif // LLVM_MC_MCASSEMBLER_H diff --git a/include/llvm/MC/MCCodeEmitter.h b/include/llvm/MC/MCCodeEmitter.h index b6c19150c12a..f1b0b784a2df 100644 --- a/include/llvm/MC/MCCodeEmitter.h +++ b/include/llvm/MC/MCCodeEmitter.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCCodeEmitter.h - Instruction Encoding ----------*- C++ -*-===// +//===- llvm/MC/MCCodeEmitter.h - Instruction Encoding -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,9 +10,8 @@ #ifndef LLVM_MC_MCCODEEMITTER_H #define LLVM_MC_MCCODEEMITTER_H -#include "llvm/Support/Compiler.h" - namespace llvm { + class MCFixup; class MCInst; class MCSubtargetInfo; @@ -21,14 +20,12 @@ template<typename T> class SmallVectorImpl; /// MCCodeEmitter - Generic instruction encoding interface. class MCCodeEmitter { -private: - MCCodeEmitter(const MCCodeEmitter &) = delete; - void operator=(const MCCodeEmitter &) = delete; - protected: // Can only create subclasses. MCCodeEmitter(); public: + MCCodeEmitter(const MCCodeEmitter &) = delete; + MCCodeEmitter &operator=(const MCCodeEmitter &) = delete; virtual ~MCCodeEmitter(); /// Lifetime management @@ -41,6 +38,6 @@ public: const MCSubtargetInfo &STI) const = 0; }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCCODEEMITTER_H diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index f846b632f112..b3106936e27f 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -23,35 +24,37 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> #include <map> -#include <tuple> -#include <vector> // FIXME: Shouldn't be needed. +#include <memory> +#include <string> +#include <utility> +#include <vector> namespace llvm { + + class CodeViewContext; class MCAsmInfo; - class MCExpr; - class MCSection; - class MCSymbol; - class MCSymbolELF; class MCLabel; - struct MCDwarfFile; - class MCDwarfLoc; class MCObjectFileInfo; class MCRegisterInfo; - class MCLineSection; - class SMLoc; - class MCSectionMachO; - class MCSectionELF; + class MCSection; class MCSectionCOFF; - class CodeViewContext; + class MCSectionELF; + class MCSectionMachO; + class MCSectionWasm; + class MCSymbol; + class MCSymbolELF; + class MCSymbolWasm; + class SMLoc; /// Context object for machine code objects. This class owns all of the /// sections that it creates. /// class MCContext { - MCContext(const MCContext &) = delete; - MCContext &operator=(const MCContext &) = delete; - public: typedef StringMap<MCSymbol *, BumpPtrAllocator &> SymbolTable; @@ -59,6 +62,9 @@ namespace llvm { /// The SourceMgr for this object, if any. const SourceMgr *SrcMgr; + /// The SourceMgr for inline assembly, if any. + SourceMgr *InlineSrcMgr; + /// The MCAsmInfo for this target. const MCAsmInfo *MAI; @@ -79,14 +85,11 @@ namespace llvm { SpecificBumpPtrAllocator<MCSectionCOFF> COFFAllocator; SpecificBumpPtrAllocator<MCSectionELF> ELFAllocator; SpecificBumpPtrAllocator<MCSectionMachO> MachOAllocator; + SpecificBumpPtrAllocator<MCSectionWasm> WasmAllocator; /// Bindings of names to symbols. SymbolTable Symbols; - /// Sections can have a corresponding symbol. This maps one to the - /// other. - DenseMap<const MCSection *, MCSymbol *> SectionSymbols; - /// A mapping from a local label number and an instance count to a symbol. /// For example, in the assembly /// 1: @@ -123,7 +126,7 @@ namespace llvm { /// Boolean toggled when .secure_log_unique / .secure_log_reset is seen to /// catch errors if .secure_log_unique appears twice without /// .secure_log_reset appearing between them. - bool SecureLogUsed; + bool SecureLogUsed = false; /// The compilation directory to use for DW_AT_comp_dir. SmallString<128> CompilationDir; @@ -139,14 +142,14 @@ namespace llvm { /// The current dwarf line information from the last dwarf .loc directive. MCDwarfLoc CurrentDwarfLoc; - bool DwarfLocSeen; + bool DwarfLocSeen = false; /// Generate dwarf debugging info for assembly source files. - bool GenDwarfForAssembly; + bool GenDwarfForAssembly = false; /// The current dwarf file number when generate dwarf debugging info for /// assembly source files. - unsigned GenDwarfFileNumber; + unsigned GenDwarfFileNumber = 0; /// Sections for generating the .debug_ranges and .debug_aranges sections. SetVector<MCSection *> SectionsForRanges; @@ -164,25 +167,27 @@ namespace llvm { StringRef DwarfDebugProducer; /// The maximum version of dwarf that we should emit. - uint16_t DwarfVersion; + uint16_t DwarfVersion = 4; /// Honor temporary labels, this is useful for debugging semantic /// differences between temporary and non-temporary labels (primarily on /// Darwin). - bool AllowTemporaryLabels; + bool AllowTemporaryLabels = true; bool UseNamesOnTempLabels = true; /// The Compile Unit ID that we are currently processing. - unsigned DwarfCompileUnitID; + unsigned DwarfCompileUnitID = 0; struct ELFSectionKey { std::string SectionName; StringRef GroupName; unsigned UniqueID; + ELFSectionKey(StringRef SectionName, StringRef GroupName, unsigned UniqueID) : SectionName(SectionName), GroupName(GroupName), UniqueID(UniqueID) { } + bool operator<(const ELFSectionKey &Other) const { if (SectionName != Other.SectionName) return SectionName < Other.SectionName; @@ -197,10 +202,12 @@ namespace llvm { StringRef GroupName; int SelectionKey; unsigned UniqueID; + COFFSectionKey(StringRef SectionName, StringRef GroupName, int SelectionKey, unsigned UniqueID) : SectionName(SectionName), GroupName(GroupName), SelectionKey(SelectionKey), UniqueID(UniqueID) {} + bool operator<(const COFFSectionKey &Other) const { if (SectionName != Other.SectionName) return SectionName < Other.SectionName; @@ -212,17 +219,35 @@ namespace llvm { } }; + struct WasmSectionKey { + std::string SectionName; + StringRef GroupName; + unsigned UniqueID; + WasmSectionKey(StringRef SectionName, StringRef GroupName, + unsigned UniqueID) + : SectionName(SectionName), GroupName(GroupName), UniqueID(UniqueID) { + } + bool operator<(const WasmSectionKey &Other) const { + if (SectionName != Other.SectionName) + return SectionName < Other.SectionName; + if (GroupName != Other.GroupName) + return GroupName < Other.GroupName; + return UniqueID < Other.UniqueID; + } + }; + StringMap<MCSectionMachO *> MachOUniquingMap; std::map<ELFSectionKey, MCSectionELF *> ELFUniquingMap; std::map<COFFSectionKey, MCSectionCOFF *> COFFUniquingMap; - StringMap<bool> ELFRelSecNames; + std::map<WasmSectionKey, MCSectionWasm *> WasmUniquingMap; + StringMap<bool> RelSecNames; SpecificBumpPtrAllocator<MCSubtargetInfo> MCSubtargetAllocator; /// Do automatic reset in destructor bool AutoReset; - bool HadError; + bool HadError = false; MCSymbol *createSymbolImpl(const StringMapEntry<bool> *Name, bool CanBeUnnamed); @@ -232,14 +257,25 @@ namespace llvm { MCSymbol *getOrCreateDirectionalLocalSymbol(unsigned LocalLabelVal, unsigned Instance); + MCSectionELF *createELFSectionImpl(StringRef Section, unsigned Type, + unsigned Flags, SectionKind K, + unsigned EntrySize, + const MCSymbolELF *Group, + unsigned UniqueID, + const MCSymbolELF *Associated); + public: explicit MCContext(const MCAsmInfo *MAI, const MCRegisterInfo *MRI, const MCObjectFileInfo *MOFI, const SourceMgr *Mgr = nullptr, bool DoAutoReset = true); + MCContext(const MCContext &) = delete; + MCContext &operator=(const MCContext &) = delete; ~MCContext(); const SourceMgr *getSourceManager() const { return SrcMgr; } + void setInlineSourceManager(SourceMgr *SM) { InlineSrcMgr = SM; } + const MCAsmInfo *getAsmInfo() const { return MAI; } const MCRegisterInfo *getRegisterInfo() const { return MRI; } @@ -288,8 +324,6 @@ namespace llvm { /// \param Name - The symbol name, which must be unique across all symbols. MCSymbol *getOrCreateSymbol(const Twine &Name); - MCSymbolELF *getOrCreateSectionSymbol(const MCSectionELF &Section); - /// Gets a symbol that will be defined to the final stack offset of a local /// variable after codegen. /// @@ -340,25 +374,13 @@ namespace llvm { MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags) { - return getELFSection(Section, Type, Flags, nullptr); - } - - MCSectionELF *getELFSection(const Twine &Section, unsigned Type, - unsigned Flags, const char *BeginSymName) { - return getELFSection(Section, Type, Flags, 0, "", BeginSymName); + return getELFSection(Section, Type, Flags, 0, ""); } MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const Twine &Group) { - return getELFSection(Section, Type, Flags, EntrySize, Group, nullptr); - } - - MCSectionELF *getELFSection(const Twine &Section, unsigned Type, - unsigned Flags, unsigned EntrySize, - const Twine &Group, const char *BeginSymName) { - return getELFSection(Section, Type, Flags, EntrySize, Group, ~0, - BeginSymName); + return getELFSection(Section, Type, Flags, EntrySize, Group, ~0); } MCSectionELF *getELFSection(const Twine &Section, unsigned Type, @@ -371,13 +393,12 @@ namespace llvm { MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const Twine &Group, unsigned UniqueID, - const char *BeginSymName); + const MCSymbolELF *Associated); MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, - const char *BeginSymName, - const MCSectionELF *Associated); + const MCSymbolELF *Associated); /// Get a section with the provided group identifier. This section is /// named by concatenating \p Prefix with '.' then \p Suffix. The \p Type @@ -390,7 +411,7 @@ namespace llvm { MCSectionELF *createELFRelSection(const Twine &Name, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, - const MCSectionELF *Associated); + const MCSectionELF *RelInfoSection); void renameELFSection(MCSectionELF *Section, StringRef Name); @@ -416,6 +437,54 @@ namespace llvm { getAssociativeCOFFSection(MCSectionCOFF *Sec, const MCSymbol *KeySym, unsigned UniqueID = GenericSectionID); + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags) { + return getWasmSection(Section, Type, Flags, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const char *BeginSymName) { + return getWasmSection(Section, Type, Flags, "", BeginSymName); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group) { + return getWasmSection(Section, Type, Flags, Group, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + const char *BeginSymName) { + return getWasmSection(Section, Type, Flags, Group, ~0, BeginSymName); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + unsigned UniqueID) { + return getWasmSection(Section, Type, Flags, Group, UniqueID, nullptr); + } + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const Twine &Group, + unsigned UniqueID, const char *BeginSymName); + + MCSectionWasm *getWasmSection(const Twine &Section, unsigned Type, + unsigned Flags, const MCSymbolWasm *Group, + unsigned UniqueID, const char *BeginSymName); + + /// 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. + MCSectionWasm *getWasmNamedSection(const Twine &Prefix, const Twine &Suffix, + unsigned Type, unsigned Flags); + + MCSectionWasm *createWasmRelSection(const Twine &Name, unsigned Type, + unsigned Flags, + const MCSymbolWasm *Group); + + void renameWasmSection(MCSectionWasm *Section, StringRef Name); + // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); @@ -463,6 +532,7 @@ namespace llvm { const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles(unsigned CUID = 0) { return getMCDwarfLineTable(CUID).getMCDwarfFiles(); } + const SmallVectorImpl<std::string> &getMCDwarfDirs(unsigned CUID = 0) { return getMCDwarfLineTable(CUID).getMCDwarfDirs(); } @@ -473,10 +543,13 @@ namespace llvm { return true; return false; } + unsigned getDwarfCompileUnitID() { return DwarfCompileUnitID; } + void setDwarfCompileUnitID(unsigned CUIndex) { DwarfCompileUnitID = CUIndex; } + void setMCLineTableCompilationDir(unsigned CUID, StringRef CompilationDir) { getMCDwarfLineTable(CUID).setCompilationDir(CompilationDir); } @@ -496,6 +569,7 @@ namespace llvm { CurrentDwarfLoc.setDiscriminator(Discriminator); DwarfLocSeen = true; } + void clearDwarfLocSeen() { DwarfLocSeen = false; } bool getDwarfLocSeen() { return DwarfLocSeen; } @@ -504,20 +578,25 @@ namespace llvm { bool getGenDwarfForAssembly() { return GenDwarfForAssembly; } void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; } unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; } + void setGenDwarfFileNumber(unsigned FileNumber) { GenDwarfFileNumber = FileNumber; } + const SetVector<MCSection *> &getGenDwarfSectionSyms() { return SectionsForRanges; } + bool addGenDwarfSection(MCSection *Sec) { return SectionsForRanges.insert(Sec); } void finalizeDwarfSections(MCStreamer &MCOS); + const std::vector<MCGenDwarfLabelEntry> &getMCGenDwarfLabelEntries() const { return MCGenDwarfLabelEntries; } + void addMCGenDwarfLabelEntry(const MCGenDwarfLabelEntry &E) { MCGenDwarfLabelEntries.push_back(E); } @@ -527,10 +606,12 @@ namespace llvm { void setDwarfDebugProducer(StringRef S) { DwarfDebugProducer = S; } StringRef getDwarfDebugProducer() { return DwarfDebugProducer; } + dwarf::DwarfFormat getDwarfFormat() const { // TODO: Support DWARF64 return dwarf::DWARF32; } + void setDwarfVersion(uint16_t v) { DwarfVersion = v; } uint16_t getDwarfVersion() const { return DwarfVersion; } @@ -538,15 +619,18 @@ namespace llvm { char *getSecureLogFile() { return SecureLogFile; } raw_fd_ostream *getSecureLog() { return SecureLog.get(); } - bool getSecureLogUsed() { return SecureLogUsed; } + void setSecureLog(std::unique_ptr<raw_fd_ostream> Value) { SecureLog = std::move(Value); } + + bool getSecureLogUsed() { return SecureLogUsed; } void setSecureLogUsed(bool Value) { SecureLogUsed = Value; } void *allocate(unsigned Size, unsigned Align = 8) { return Allocator.Allocate(Size, Align); } + void deallocate(void *Ptr) {} bool hadError() { return HadError; } @@ -632,4 +716,4 @@ inline void operator delete[](void *Ptr, llvm::MCContext &C) noexcept { C.deallocate(Ptr); } -#endif +#endif // LLVM_MC_MCCONTEXT_H diff --git a/include/llvm/MC/MCDisassembler/MCDisassembler.h b/include/llvm/MC/MCDisassembler/MCDisassembler.h index 9006d87abb43..5e626f186986 100644 --- a/include/llvm/MC/MCDisassembler/MCDisassembler.h +++ b/include/llvm/MC/MCDisassembler/MCDisassembler.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCDisassembler.h - Disassembler interface -------*- C++ -*-===// +//===- llvm/MC/MCDisassembler.h - Disassembler interface --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,20 +6,21 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// + #ifndef LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H #define LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H -#include "llvm-c/Disassembler.h" #include "llvm/MC/MCDisassembler/MCSymbolizer.h" -#include "llvm/Support/DataTypes.h" +#include <cstdint> +#include <memory> namespace llvm { template <typename T> class ArrayRef; +class MCContext; class MCInst; class MCSubtargetInfo; class raw_ostream; -class MCContext; /// Superclass for all disassemblers. Consumes a memory region and provides an /// array of assembly instructions. @@ -54,7 +55,7 @@ public: }; MCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) - : Ctx(Ctx), STI(STI), Symbolizer(), CommentStream(nullptr) {} + : Ctx(Ctx), STI(STI) {} virtual ~MCDisassembler(); @@ -105,9 +106,9 @@ public: // Marked mutable because we cache it inside the disassembler, rather than // having to pass it around as an argument through all the autogenerated code. - mutable raw_ostream *CommentStream; + mutable raw_ostream *CommentStream = nullptr; }; -} // namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H diff --git a/include/llvm/MC/MCDisassembler/MCRelocationInfo.h b/include/llvm/MC/MCDisassembler/MCRelocationInfo.h index 25334f755ee6..7836e886c303 100644 --- a/include/llvm/MC/MCDisassembler/MCRelocationInfo.h +++ b/include/llvm/MC/MCDisassembler/MCRelocationInfo.h @@ -1,4 +1,4 @@ -//==-- llvm/MC/MCRelocationInfo.h --------------------------------*- C++ -*-==// +//===- llvm/MC/MCRelocationInfo.h -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,26 +16,20 @@ #ifndef LLVM_MC_MCDISASSEMBLER_MCRELOCATIONINFO_H #define LLVM_MC_MCDISASSEMBLER_MCRELOCATIONINFO_H -#include "llvm/Support/Compiler.h" - namespace llvm { -namespace object { -class RelocationRef; -} -class MCExpr; class MCContext; +class MCExpr; /// \brief Create MCExprs from relocations found in an object file. class MCRelocationInfo { - MCRelocationInfo(const MCRelocationInfo &) = delete; - void operator=(const MCRelocationInfo &) = delete; - protected: MCContext &Ctx; public: MCRelocationInfo(MCContext &Ctx); + MCRelocationInfo(const MCRelocationInfo &) = delete; + MCRelocationInfo &operator=(const MCRelocationInfo &) = delete; virtual ~MCRelocationInfo(); /// \brief Create an MCExpr for the target-specific \p VariantKind. @@ -46,6 +40,6 @@ public: unsigned VariantKind); }; -} +} // end namespace llvm -#endif +#endif // LLVM_MC_MCDISASSEMBLER_MCRELOCATIONINFO_H diff --git a/include/llvm/MC/MCDisassembler/MCSymbolizer.h b/include/llvm/MC/MCDisassembler/MCSymbolizer.h index 713467c0a3e7..d85cf5e066f5 100644 --- a/include/llvm/MC/MCDisassembler/MCSymbolizer.h +++ b/include/llvm/MC/MCDisassembler/MCSymbolizer.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCSymbolizer.h - MCSymbolizer class -------------*- C++ -*-===// +//===- llvm/MC/MCSymbolizer.h - MCSymbolizer class --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,9 +17,8 @@ #define LLVM_MC_MCDISASSEMBLER_MCSYMBOLIZER_H #include "llvm/MC/MCDisassembler/MCRelocationInfo.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" -#include <cassert> +#include <algorithm> +#include <cstdint> #include <memory> namespace llvm { @@ -38,9 +37,6 @@ class raw_ostream; /// operands are actually symbolizable, and in what way. I don't think this /// information exists right now. class MCSymbolizer { - MCSymbolizer(const MCSymbolizer &) = delete; - void operator=(const MCSymbolizer &) = delete; - protected: MCContext &Ctx; std::unique_ptr<MCRelocationInfo> RelInfo; @@ -51,6 +47,8 @@ public: : Ctx(Ctx), RelInfo(std::move(RelInfo)) { } + MCSymbolizer(const MCSymbolizer &) = delete; + MCSymbolizer &operator=(const MCSymbolizer &) = delete; virtual ~MCSymbolizer(); /// \brief Try to add a symbolic operand instead of \p Value to the MCInst. @@ -80,6 +78,6 @@ public: uint64_t Address) = 0; }; -} +} // end namespace llvm -#endif +#endif // LLVM_MC_MCDISASSEMBLER_MCSYMBOLIZER_H diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index 0c555d377d8b..0d69c2005cb4 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -16,24 +16,27 @@ #define LLVM_MC_MCDWARF_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" -#include "llvm/Support/Dwarf.h" +#include <cassert> +#include <cstdint> #include <string> #include <utility> #include <vector> namespace llvm { + template <typename T> class ArrayRef; -class raw_ostream; class MCAsmBackend; class MCContext; class MCObjectStreamer; class MCStreamer; class MCSymbol; -class SourceMgr; +class raw_ostream; class SMLoc; +class SourceMgr; /// \brief Instances of this class represent the name of the dwarf /// .file directive and its associated dwarf file number in the MC file, @@ -71,6 +74,7 @@ class MCDwarfLoc { private: // MCContext manages these friend class MCContext; 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), @@ -194,13 +198,14 @@ struct MCDwarfLineTableParams { }; struct MCDwarfLineTableHeader { - MCSymbol *Label; + MCSymbol *Label = nullptr; SmallVector<std::string, 3> MCDwarfDirs; SmallVector<MCDwarfFile, 3> MCDwarfFiles; StringMap<unsigned> SourceIdMap; StringRef CompilationDir; - MCDwarfLineTableHeader() : Label(nullptr) {} + MCDwarfLineTableHeader() = default; + unsigned getFile(StringRef &Directory, StringRef &FileName, unsigned FileNumber = 0); std::pair<MCSymbol *, MCSymbol *> Emit(MCStreamer *MCOS, @@ -212,13 +217,16 @@ struct MCDwarfLineTableHeader { class MCDwarfDwoLineTable { MCDwarfLineTableHeader Header; + public: void setCompilationDir(StringRef CompilationDir) { Header.CompilationDir = CompilationDir; } + unsigned getFile(StringRef Directory, StringRef FileName) { return Header.getFile(Directory, FileName); } + void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params) const; }; @@ -488,22 +496,19 @@ public: }; struct MCDwarfFrameInfo { - MCDwarfFrameInfo() - : Begin(nullptr), End(nullptr), Personality(nullptr), Lsda(nullptr), - Instructions(), CurrentCfaRegister(0), PersonalityEncoding(), - LsdaEncoding(0), CompactUnwindEncoding(0), IsSignalFrame(false), - IsSimple(false) {} - MCSymbol *Begin; - MCSymbol *End; - const MCSymbol *Personality; - const MCSymbol *Lsda; + MCDwarfFrameInfo() = default; + + MCSymbol *Begin = nullptr; + MCSymbol *End = nullptr; + const MCSymbol *Personality = nullptr; + const MCSymbol *Lsda = nullptr; std::vector<MCCFIInstruction> Instructions; - unsigned CurrentCfaRegister; - unsigned PersonalityEncoding; - unsigned LsdaEncoding; - uint32_t CompactUnwindEncoding; - bool IsSignalFrame; - bool IsSimple; + unsigned CurrentCfaRegister = 0; + unsigned PersonalityEncoding = 0; + unsigned LsdaEncoding = 0; + uint32_t CompactUnwindEncoding = 0; + bool IsSignalFrame = false; + bool IsSimple = false; }; class MCDwarfFrameEmitter { @@ -516,6 +521,7 @@ public: static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta, raw_ostream &OS); }; + } // end namespace llvm -#endif +#endif // LLVM_MC_MCDWARF_H diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h index 376e21821316..f22fc11f9b07 100644 --- a/include/llvm/MC/MCELFObjectWriter.h +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ---------*- C++ -*-===// +//===- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,22 +11,21 @@ #define LLVM_MC_MCELFOBJECTWRITER_H #include "llvm/ADT/Triple.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> #include <vector> namespace llvm { + class MCAssembler; class MCContext; class MCFixup; -class MCFragment; class MCObjectWriter; class MCSymbol; class MCSymbolELF; class MCValue; -class raw_pwrite_stream; struct ELFRelocationEntry { uint64_t Offset; // Where is the relocation. @@ -47,6 +46,7 @@ struct ELFRelocationEntry { << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol << ", OriginalAddend=" << OriginalAddend; } + void dump() const { print(errs()); } }; @@ -58,12 +58,12 @@ class MCELFObjectTargetWriter { const unsigned IsN64 : 1; protected: - - MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, - uint16_t EMachine_, bool HasRelocationAddend, - bool IsN64=false); + MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, uint16_t EMachine_, + bool HasRelocationAddend, bool IsN64 = false); public: + virtual ~MCELFObjectTargetWriter() = default; + static uint8_t getOSABI(Triple::OSType OSType) { switch (OSType) { case Triple::CloudABI: @@ -76,8 +76,6 @@ public: } } - virtual ~MCELFObjectTargetWriter() {} - virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const = 0; @@ -144,6 +142,7 @@ public: MCObjectWriter *createELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian); -} // End llvm namespace -#endif +} // end namespace llvm + +#endif // LLVM_MC_MCELFOBJECTWRITER_H diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index a5c263844352..90434f34da5f 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -10,27 +10,24 @@ #ifndef LLVM_MC_MCELFSTREAMER_H #define LLVM_MC_MCELFSTREAMER_H -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCObjectStreamer.h" -#include "llvm/MC/SectionKind.h" -#include "llvm/Support/DataTypes.h" namespace llvm { + class MCAsmBackend; -class MCAssembler; class MCCodeEmitter; class MCExpr; class MCInst; -class raw_ostream; class MCELFStreamer : public MCObjectStreamer { public: MCELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter) - : MCObjectStreamer(Context, TAB, OS, Emitter), SeenIdent(false) {} + : MCObjectStreamer(Context, TAB, OS, Emitter) {} - ~MCELFStreamer() override; + ~MCELFStreamer() override = default; /// state management void reset() override { @@ -44,7 +41,8 @@ public: void InitSections(bool NoExecStack) override; void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; - void EmitLabel(MCSymbol *Symbol) override; + void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; + void EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; @@ -52,10 +50,6 @@ public: void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; - void BeginCOFFSymbolDef(const MCSymbol *Symbol) override; - void EmitCOFFSymbolStorageClass(int StorageClass) override; - void EmitCOFFSymbolType(int Type) override; - void EndCOFFSymbolDef() override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; @@ -69,8 +63,6 @@ public: void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()) override; - void EmitFileDirective(StringRef Filename) override; - void EmitIdent(StringRef IdentString) override; void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override; @@ -91,11 +83,11 @@ private: /// \brief Merge the content of the fragment \p EF into the fragment \p DF. void mergeFragment(MCDataFragment *, MCDataFragment *); - bool SeenIdent; + bool SeenIdent = false; /// BundleGroups - The stack of fragments holding the bundle-locked /// instructions. - llvm::SmallVector<MCDataFragment *, 4> BundleGroups; + SmallVector<MCDataFragment *, 4> BundleGroups; }; MCELFStreamer *createARMELFStreamer(MCContext &Context, MCAsmBackend &TAB, @@ -105,4 +97,4 @@ MCELFStreamer *createARMELFStreamer(MCContext &Context, MCAsmBackend &TAB, } // end namespace llvm -#endif +#endif // LLVM_MC_MCELFSTREAMER_H diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 0d1e675da459..c850abf42e2c 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -11,10 +11,11 @@ #define LLVM_MC_MCEXPR_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/Support/SMLoc.h" +#include <cstdint> namespace llvm { + class MCAsmInfo; class MCAsmLayout; class MCAssembler; @@ -43,9 +44,7 @@ public: private: ExprKind Kind; - - MCExpr(const MCExpr&) = delete; - void operator=(const MCExpr&) = delete; + SMLoc Loc; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, @@ -56,7 +55,7 @@ private: const SectionAddrMap *Addrs, bool InSet) const; protected: - explicit MCExpr(ExprKind Kind) : Kind(Kind) {} + explicit MCExpr(ExprKind Kind, SMLoc Loc) : Kind(Kind), Loc(Loc) {} bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, @@ -64,10 +63,14 @@ protected: const SectionAddrMap *Addrs, bool InSet) const; public: + MCExpr(const MCExpr &) = delete; + MCExpr &operator=(const MCExpr &) = delete; + /// \name Accessors /// @{ ExprKind getKind() const { return Kind; } + SMLoc getLoc() const { return Loc; } /// @} /// \name Utility Methods @@ -132,7 +135,7 @@ class MCConstantExpr : public MCExpr { int64_t Value; explicit MCConstantExpr(int64_t Value) - : MCExpr(MCExpr::Constant), Value(Value) {} + : MCExpr(MCExpr::Constant, SMLoc()), Value(Value) {} public: /// \name Construction @@ -191,6 +194,8 @@ public: VK_SIZE, // symbol@SIZE VK_WEAKREF, // The link between the symbols in .weakref foo, bar + VK_X86_ABS8, + VK_ARM_NONE, VK_ARM_GOT_PREL, VK_ARM_TARGET1, @@ -265,6 +270,7 @@ public: VK_Hexagon_IE_GOT, VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr + VK_WebAssembly_TYPEINDEX,// Type table index VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi @@ -289,7 +295,7 @@ private: const MCSymbol *Symbol; explicit MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind, - const MCAsmInfo *MAI); + const MCAsmInfo *MAI, SMLoc Loc = SMLoc()); public: /// \name Construction @@ -300,7 +306,7 @@ public: } static const MCSymbolRefExpr *create(const MCSymbol *Symbol, VariantKind Kind, - MCContext &Ctx); + MCContext &Ctx, SMLoc Loc = SMLoc()); static const MCSymbolRefExpr *create(StringRef Name, VariantKind Kind, MCContext &Ctx); @@ -345,26 +351,30 @@ private: Opcode Op; const MCExpr *Expr; - MCUnaryExpr(Opcode Op, const MCExpr *Expr) - : MCExpr(MCExpr::Unary), Op(Op), Expr(Expr) {} + MCUnaryExpr(Opcode Op, const MCExpr *Expr, SMLoc Loc) + : MCExpr(MCExpr::Unary, Loc), Op(Op), Expr(Expr) {} public: /// \name Construction /// @{ static const MCUnaryExpr *create(Opcode Op, const MCExpr *Expr, - MCContext &Ctx); - static const MCUnaryExpr *createLNot(const MCExpr *Expr, MCContext &Ctx) { - return create(LNot, Expr, Ctx); + MCContext &Ctx, SMLoc Loc = SMLoc()); + + static const MCUnaryExpr *createLNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { + return create(LNot, Expr, Ctx, Loc); } - static const MCUnaryExpr *createMinus(const MCExpr *Expr, MCContext &Ctx) { - return create(Minus, Expr, Ctx); + + static const MCUnaryExpr *createMinus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { + return create(Minus, Expr, Ctx, Loc); } - static const MCUnaryExpr *createNot(const MCExpr *Expr, MCContext &Ctx) { - return create(Not, Expr, Ctx); + + static const MCUnaryExpr *createNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { + return create(Not, Expr, Ctx, Loc); } - static const MCUnaryExpr *createPlus(const MCExpr *Expr, MCContext &Ctx) { - return create(Plus, Expr, Ctx); + + static const MCUnaryExpr *createPlus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { + return create(Plus, Expr, Ctx, Loc); } /// @} @@ -417,87 +427,108 @@ private: Opcode Op; const MCExpr *LHS, *RHS; - MCBinaryExpr(Opcode Op, const MCExpr *LHS, const MCExpr *RHS) - : MCExpr(MCExpr::Binary), Op(Op), LHS(LHS), RHS(RHS) {} + MCBinaryExpr(Opcode Op, const MCExpr *LHS, const MCExpr *RHS, + SMLoc Loc = SMLoc()) + : MCExpr(MCExpr::Binary, Loc), Op(Op), LHS(LHS), RHS(RHS) {} public: /// \name Construction /// @{ static const MCBinaryExpr *create(Opcode Op, const MCExpr *LHS, - const MCExpr *RHS, MCContext &Ctx); + const MCExpr *RHS, MCContext &Ctx, + SMLoc Loc = SMLoc()); + static const MCBinaryExpr *createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Add, LHS, RHS, Ctx); } + static const MCBinaryExpr *createAnd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(And, LHS, RHS, Ctx); } + static const MCBinaryExpr *createDiv(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Div, LHS, RHS, Ctx); } + static const MCBinaryExpr *createEQ(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(EQ, LHS, RHS, Ctx); } + static const MCBinaryExpr *createGT(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(GT, LHS, RHS, Ctx); } + static const MCBinaryExpr *createGTE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(GTE, LHS, RHS, Ctx); } + static const MCBinaryExpr *createLAnd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LAnd, LHS, RHS, Ctx); } + static const MCBinaryExpr *createLOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LOr, LHS, RHS, Ctx); } + static const MCBinaryExpr *createLT(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LT, LHS, RHS, Ctx); } + static const MCBinaryExpr *createLTE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LTE, LHS, RHS, Ctx); } + static const MCBinaryExpr *createMod(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Mod, LHS, RHS, Ctx); } + static const MCBinaryExpr *createMul(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Mul, LHS, RHS, Ctx); } + static const MCBinaryExpr *createNE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(NE, LHS, RHS, Ctx); } + static const MCBinaryExpr *createOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Or, LHS, RHS, Ctx); } + static const MCBinaryExpr *createShl(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Shl, LHS, RHS, Ctx); } + static const MCBinaryExpr *createAShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(AShr, LHS, RHS, Ctx); } + static const MCBinaryExpr *createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LShr, LHS, RHS, Ctx); } + static const MCBinaryExpr *createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Sub, LHS, RHS, Ctx); } + static const MCBinaryExpr *createXor(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Xor, LHS, RHS, Ctx); @@ -530,9 +561,11 @@ public: /// MCExprs are bump pointer allocated and not destructed. class MCTargetExpr : public MCExpr { virtual void anchor(); + protected: - MCTargetExpr() : MCExpr(Target) {} - virtual ~MCTargetExpr() {} + MCTargetExpr() : MCExpr(Target, SMLoc()) {} + virtual ~MCTargetExpr() = default; + public: virtual void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const = 0; virtual bool evaluateAsRelocatableImpl(MCValue &Res, @@ -550,4 +583,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_MC_MCEXPR_H diff --git a/include/llvm/MC/MCFragment.h b/include/llvm/MC/MCFragment.h index edb740f36d91..fc8257f90a9f 100644 --- a/include/llvm/MC/MCFragment.h +++ b/include/llvm/MC/MCFragment.h @@ -10,25 +10,26 @@ #ifndef LLVM_MC_MCFRAGMENT_H #define LLVM_MC_MCFRAGMENT_H -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/ADT/iterator.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" +#include "llvm/Support/SMLoc.h" +#include <cstdint> +#include <utility> namespace llvm { + class MCSection; -class MCSymbol; class MCSubtargetInfo; +class MCSymbol; class MCFragment : public ilist_node_with_parent<MCFragment, MCSection> { friend class MCAsmLayout; - MCFragment() = delete; - MCFragment(const MCFragment &) = delete; - void operator=(const MCFragment &) = delete; - public: enum FragmentType : uint8_t { FT_Align, @@ -86,6 +87,10 @@ protected: ~MCFragment(); public: + MCFragment() = delete; + MCFragment(const MCFragment &) = delete; + MCFragment &operator=(const MCFragment &) = delete; + /// Destroys the current fragment. /// /// This must be used instead of delete as MCFragment is non-virtual. @@ -131,7 +136,8 @@ public: class MCDummyFragment : public MCFragment { public: explicit MCDummyFragment(MCSection *Sec) - : MCFragment(FT_Dummy, false, 0, Sec){}; + : MCFragment(FT_Dummy, false, 0, Sec) {} + static bool classof(const MCFragment *F) { return F->getKind() == FT_Dummy; } }; @@ -271,7 +277,6 @@ public: }; class MCAlignFragment : public MCFragment { - /// Alignment - The alignment to ensure, in bytes. unsigned Alignment; @@ -319,7 +324,6 @@ public: }; class MCFillFragment : public MCFragment { - /// Value to use for filling bytes. uint8_t Value; @@ -339,7 +343,6 @@ public: }; class MCOrgFragment : public MCFragment { - /// Offset - The offset this fragment should start at. const MCExpr *Offset; @@ -371,7 +374,6 @@ public: }; class MCLEBFragment : public MCFragment { - /// Value - The value this fragment should contain. const MCExpr *Value; @@ -404,7 +406,6 @@ public: }; class MCDwarfLineAddrFragment : public MCFragment { - /// LineDelta - the value of the difference between the two line numbers /// between two .loc dwarf directives. int64_t LineDelta; @@ -441,7 +442,6 @@ public: }; class MCDwarfCallFrameFragment : public MCFragment { - /// AddrDelta - The expression for the difference of the two symbols that /// make up the address delta between two .cfi_* dwarf directives. const MCExpr *AddrDelta; @@ -561,4 +561,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_MC_MCFRAGMENT_H diff --git a/include/llvm/MC/MCInst.h b/include/llvm/MC/MCInst.h index 4688b5f2b6e9..702279659371 100644 --- a/include/llvm/MC/MCInst.h +++ b/include/llvm/MC/MCInst.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCInst.h - MCInst class -------------------------*- C++ -*-===// +//===- llvm/MC/MCInst.h - MCInst class --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,15 +18,17 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" +#include <cassert> +#include <cstddef> +#include <cstdint> namespace llvm { -class raw_ostream; -class MCAsmInfo; -class MCInstPrinter; + class MCExpr; class MCInst; +class MCInstPrinter; +class raw_ostream; /// \brief Instances of this class represent operands of the MCInst class. /// This is a simple discriminated union. @@ -39,7 +41,7 @@ class MCOperand { kExpr, ///< Relocatable immediate operand. kInst ///< Sub-instruction operand. }; - MachineOperandType Kind; + MachineOperandType Kind = kInvalid; union { unsigned RegVal; @@ -50,7 +52,7 @@ class MCOperand { }; public: - MCOperand() : Kind(kInvalid), FPImmVal(0.0) {} + MCOperand() : FPImmVal(0.0) {} bool isValid() const { return Kind != kInvalid; } bool isReg() const { return Kind == kRegister; } @@ -75,6 +77,7 @@ public: assert(isImm() && "This is not an immediate"); return ImmVal; } + void setImm(int64_t Val) { assert(isImm() && "This is not an immediate"); ImmVal = Val; @@ -94,6 +97,7 @@ public: assert(isExpr() && "This is not an expression"); return ExprVal; } + void setExpr(const MCExpr *Val) { assert(isExpr() && "This is not an expression"); ExprVal = Val; @@ -103,6 +107,7 @@ public: assert(isInst() && "This is not a sub-instruction"); return InstVal; } + void setInst(const MCInst *Val) { assert(isInst() && "This is not a sub-instruction"); InstVal = Val; @@ -114,24 +119,28 @@ public: Op.RegVal = Reg; return Op; } + static MCOperand createImm(int64_t Val) { MCOperand Op; Op.Kind = kImmediate; Op.ImmVal = Val; return Op; } + static MCOperand createFPImm(double Val) { MCOperand Op; Op.Kind = kFPImmediate; Op.FPImmVal = Val; return Op; } + static MCOperand createExpr(const MCExpr *Val) { MCOperand Op; Op.Kind = kExpr; Op.ExprVal = Val; return Op; } + static MCOperand createInst(const MCInst *Val) { MCOperand Op; Op.Kind = kInst; @@ -148,12 +157,12 @@ template <> struct isPodLike<MCOperand> { static const bool value = true; }; /// \brief Instances of this class represent a single low-level machine /// instruction. class MCInst { - unsigned Opcode; + unsigned Opcode = 0; SMLoc Loc; SmallVector<MCOperand, 8> Operands; public: - MCInst() : Opcode(0) {} + MCInst() = default; void setOpcode(unsigned Op) { Opcode = Op; } unsigned getOpcode() const { return Opcode; } @@ -176,6 +185,7 @@ public: const_iterator begin() const { return Operands.begin(); } iterator end() { return Operands.end(); } const_iterator end() const { return Operands.end(); } + iterator insert(iterator I, const MCOperand &Op) { return Operands.insert(I, Op); } @@ -202,4 +212,4 @@ inline raw_ostream& operator<<(raw_ostream &OS, const MCInst &MI) { } // end namespace llvm -#endif +#endif // LLVM_MC_MCINST_H diff --git a/include/llvm/MC/MCInstPrinter.h b/include/llvm/MC/MCInstPrinter.h index 320b280cc756..069403074b31 100644 --- a/include/llvm/MC/MCInstPrinter.h +++ b/include/llvm/MC/MCInstPrinter.h @@ -16,12 +16,12 @@ namespace llvm { template <typename T> class ArrayRef; -class MCInst; -class raw_ostream; class MCAsmInfo; +class MCInst; class MCInstrInfo; class MCRegisterInfo; class MCSubtargetInfo; +class raw_ostream; class StringRef; /// Convert `Bytes' to a hex string and output to `OS' @@ -43,28 +43,26 @@ protected: /// \brief A stream that comments can be emitted to if desired. Each comment /// must end with a newline. This will be null if verbose assembly emission /// is disable. - raw_ostream *CommentStream; + raw_ostream *CommentStream = nullptr; const MCAsmInfo &MAI; const MCInstrInfo &MII; const MCRegisterInfo &MRI; /// True if we are printing marked up assembly. - bool UseMarkup; + bool UseMarkup = false; /// True if we are printing immediates as hex. - bool PrintImmHex; + bool PrintImmHex = false; /// Which style to use for printing hexadecimal values. - HexStyle::Style PrintHexStyle; + HexStyle::Style PrintHexStyle = HexStyle::C; /// Utility function for printing annotations. void printAnnotation(raw_ostream &OS, StringRef Annot); public: MCInstPrinter(const MCAsmInfo &mai, const MCInstrInfo &mii, - const MCRegisterInfo &mri) - : CommentStream(nullptr), MAI(mai), MII(mii), MRI(mri), UseMarkup(false), - PrintImmHex(false), PrintHexStyle(HexStyle::C) {} + const MCRegisterInfo &mri) : MAI(mai), MII(mii), MRI(mri) {} virtual ~MCInstPrinter(); diff --git a/include/llvm/MC/MCInstrAnalysis.h b/include/llvm/MC/MCInstrAnalysis.h index 8f5159e9e1c8..dd3e1df477b4 100644 --- a/include/llvm/MC/MCInstrAnalysis.h +++ b/include/llvm/MC/MCInstrAnalysis.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCInstrAnalysis.h - InstrDesc target hooks ------*- C++ -*-===// +//===- llvm/MC/MCInstrAnalysis.h - InstrDesc target hooks -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,18 +18,19 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" +#include <cstdint> namespace llvm { class MCInstrAnalysis { protected: friend class Target; + const MCInstrInfo *Info; public: MCInstrAnalysis(const MCInstrInfo *Info) : Info(Info) {} - - virtual ~MCInstrAnalysis() {} + virtual ~MCInstrAnalysis() = default; virtual bool isBranch(const MCInst &Inst) const { return Info->get(Inst.getOpcode()).isBranch(); @@ -66,6 +67,6 @@ public: uint64_t &Target) const; }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCINSTRANALYSIS_H diff --git a/include/llvm/MC/MCInstrItineraries.h b/include/llvm/MC/MCInstrItineraries.h index 1fb276a302b9..4443dd113715 100644 --- a/include/llvm/MC/MCInstrItineraries.h +++ b/include/llvm/MC/MCInstrItineraries.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCInstrItineraries.h - Scheduling ---------------*- C++ -*-===// +//===- llvm/MC/MCInstrItineraries.h - Scheduling ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -88,7 +88,6 @@ struct InstrStage { } }; - //===----------------------------------------------------------------------===// /// An itinerary represents the scheduling information for an instruction. /// This includes a set of stages occupied by the instruction and the pipeline @@ -102,23 +101,20 @@ struct InstrItinerary { unsigned LastOperandCycle; ///< Index of last + 1 operand rd/wr }; - //===----------------------------------------------------------------------===// /// Itinerary data supplied by a subtarget to be used by a target. /// class InstrItineraryData { public: - MCSchedModel SchedModel; ///< Basic machine properties. - const InstrStage *Stages; ///< Array of stages selected - const unsigned *OperandCycles; ///< Array of operand cycles selected - const unsigned *Forwardings; ///< Array of pipeline forwarding paths - const InstrItinerary *Itineraries; ///< Array of itineraries selected - - /// Ctors. - InstrItineraryData() : SchedModel(MCSchedModel::GetDefaultSchedModel()), - Stages(nullptr), OperandCycles(nullptr), - Forwardings(nullptr), Itineraries(nullptr) {} - + MCSchedModel SchedModel = + MCSchedModel::GetDefaultSchedModel(); ///< Basic machine properties. + const InstrStage *Stages = nullptr; ///< Array of stages selected + const unsigned *OperandCycles = nullptr; ///< Array of operand cycles selected + const unsigned *Forwardings = nullptr; ///< Array of pipeline forwarding paths + const InstrItinerary *Itineraries = + nullptr; ///< Array of itineraries selected + + InstrItineraryData() = default; InstrItineraryData(const MCSchedModel &SM, const InstrStage *S, const unsigned *OS, const unsigned *F) : SchedModel(SM), Stages(S), OperandCycles(OS), Forwardings(F), @@ -234,6 +230,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCINSTRITINERARIES_H diff --git a/include/llvm/MC/MCLabel.h b/include/llvm/MC/MCLabel.h index a12473fdad02..b6579fd654ab 100644 --- a/include/llvm/MC/MCLabel.h +++ b/include/llvm/MC/MCLabel.h @@ -14,10 +14,8 @@ #ifndef LLVM_MC_MCLABEL_H #define LLVM_MC_MCLABEL_H -#include "llvm/Support/Compiler.h" - namespace llvm { -class MCContext; + class raw_ostream; /// \brief Instances of this class represent a label name in the MC file, @@ -29,12 +27,13 @@ class MCLabel { private: // MCContext creates and uniques these. friend class MCContext; + MCLabel(unsigned instance) : Instance(instance) {} +public: MCLabel(const MCLabel &) = delete; - void operator=(const MCLabel &) = delete; + MCLabel &operator=(const MCLabel &) = delete; -public: /// \brief Get the current instance of this Directional Local Label. unsigned getInstance() const { return Instance; } @@ -52,6 +51,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MCLabel &Label) { Label.print(OS); return OS; } + } // end namespace llvm -#endif +#endif // LLVM_MC_MCLABEL_H diff --git a/include/llvm/MC/MCLinkerOptimizationHint.h b/include/llvm/MC/MCLinkerOptimizationHint.h index 200bb93f64c8..0c3525bbeda6 100644 --- a/include/llvm/MC/MCLinkerOptimizationHint.h +++ b/include/llvm/MC/MCLinkerOptimizationHint.h @@ -21,13 +21,14 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdint> namespace llvm { -// Forward declarations. +class MachObjectWriter; class MCAsmLayout; class MCSymbol; -class MachObjectWriter; /// Linker Optimization Hint Type. enum MCLOHType { @@ -133,7 +134,7 @@ public: class MCLOHContainer { /// Keep track of the emit size of all the LOHs. - mutable uint64_t EmitSize; + mutable uint64_t EmitSize = 0; /// Keep track of all LOH directives. SmallVector<MCLOHDirective, 32> Directives; @@ -141,7 +142,7 @@ class MCLOHContainer { public: typedef SmallVectorImpl<MCLOHDirective> LOHDirectives; - MCLOHContainer() : EmitSize(0) {} + MCLOHContainer() = default; /// Const accessor to the directives. const LOHDirectives &getDirectives() const { @@ -183,4 +184,4 @@ typedef MCLOHContainer::LOHDirectives MCLOHDirectives; } // end namespace llvm -#endif +#endif // LLVM_MC_MCLINKEROPTIMIZATIONHINT_H diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h index 1a685dbd608e..b93638f86408 100644 --- a/include/llvm/MC/MCMachObjectWriter.h +++ b/include/llvm/MC/MCMachObjectWriter.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCMachObjectWriter.h - Mach Object Writer -------*- C++ -*-===// +//===- llvm/MC/MCMachObjectWriter.h - Mach Object Writer --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,12 +11,15 @@ #define LLVM_MC_MCMACHOBJECTWRITER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/StringTableBuilder.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/MachO.h" +#include <cstdint> +#include <memory> +#include <string> #include <vector> namespace llvm { @@ -95,8 +98,8 @@ class MachObjectWriter : public MCObjectWriter { : Sym(Sym), MRE(MRE) {} }; - llvm::DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations; - llvm::DenseMap<const MCSection *, unsigned> IndirectSymBase; + DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations; + DenseMap<const MCSection *, unsigned> IndirectSymBase; SectionAddrMap SectionAddress; @@ -271,6 +274,6 @@ MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCMACHOBJECTWRITER_H diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index 9aa8812c7bb3..8b2a1261b220 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -129,7 +129,7 @@ protected: /// it'll go here. MCSection *TLSExtraDataSection; - /// Section directive for Thread Local data. ELF, MachO and COFF. + /// Section directive for Thread Local data. ELF, MachO, COFF, and Wasm. MCSection *TLSDataSection; // Defaults to ".tdata". /// Section directive for Thread Local uninitialized data. @@ -338,7 +338,7 @@ public: return EHFrameSection; } - enum Environment { IsMachO, IsELF, IsCOFF }; + enum Environment { IsMachO, IsELF, IsCOFF, IsWasm }; Environment getObjectFileType() const { return Env; } bool isPositionIndependent() const { return PositionIndependent; } @@ -353,6 +353,7 @@ private: void initMachOMCObjectFileInfo(const Triple &T); void initELFMCObjectFileInfo(const Triple &T); void initCOFFMCObjectFileInfo(const Triple &T); + void initWasmMCObjectFileInfo(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 f9111b7f47ea..7c1189e46ab2 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -89,7 +89,8 @@ public: /// \name MCStreamer Interface /// @{ - void EmitLabel(MCSymbol *Symbol) override; + void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; + virtual void EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F); void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()) override; @@ -97,7 +98,8 @@ public: void EmitSLEB128Value(const MCExpr *Value) override; void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; - void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo& STI) override; + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + bool = false) override; /// \brief Emit an instruction to a special fragment, because this instruction /// can change its size during relaxation. @@ -152,6 +154,7 @@ public: SMLoc Loc = SMLoc()) override; void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc = SMLoc()) override; + void EmitFileDirective(StringRef Filename) override; void FinishImpl() override; diff --git a/include/llvm/MC/MCObjectWriter.h b/include/llvm/MC/MCObjectWriter.h index 0ecebe42a0b9..86bcbb6861d7 100644 --- a/include/llvm/MC/MCObjectWriter.h +++ b/include/llvm/MC/MCObjectWriter.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCObjectWriter.h - Object File Writer Interface -*- C++ -*-===// +//===- llvm/MC/MCObjectWriter.h - Object File Writer Interface --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,13 +11,15 @@ #define LLVM_MC_MCOBJECTWRITER_H #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" #include <cassert> +#include <cstdint> namespace llvm { + class MCAsmLayout; class MCAssembler; class MCFixup; @@ -38,15 +40,12 @@ class MCValue; /// The object writer also contains a number of helper methods for writing /// binary data to the output stream. class MCObjectWriter { - MCObjectWriter(const MCObjectWriter &) = delete; - void operator=(const MCObjectWriter &) = delete; - raw_pwrite_stream *OS; protected: unsigned IsLittleEndian : 1; -protected: // Can only create subclasses. + // Can only create subclasses. MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian) : OS(&OS), IsLittleEndian(IsLittleEndian) {} @@ -55,6 +54,8 @@ protected: // Can only create subclasses. } public: + MCObjectWriter(const MCObjectWriter &) = delete; + MCObjectWriter &operator=(const MCObjectWriter &) = delete; virtual ~MCObjectWriter(); /// lifetime management @@ -108,11 +109,6 @@ public: bool InSet, bool IsPCRel) const; - /// True if this symbol (which is a variable) is weak. This is not - /// just STB_WEAK, but more generally whether or not we can evaluate - /// past it. - virtual bool isWeak(const MCSymbol &Sym) const; - /// Write the object file. /// /// This routine is called by the assembler after layout and relaxation is @@ -199,6 +195,6 @@ public: /// @} }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCOBJECTWRITER_H diff --git a/include/llvm/MC/MCParser/AsmCond.h b/include/llvm/MC/MCParser/AsmCond.h index a918b5600ed5..8e7bfc521556 100644 --- a/include/llvm/MC/MCParser/AsmCond.h +++ b/include/llvm/MC/MCParser/AsmCond.h @@ -28,13 +28,13 @@ public: ElseCond // inside else conditional }; - ConditionalAssemblyType TheCond; - bool CondMet; - bool Ignore; + ConditionalAssemblyType TheCond = NoCond; + bool CondMet = false; + bool Ignore = false; - AsmCond() : TheCond(NoCond), CondMet(false), Ignore(false) {} + AsmCond() = default; }; } // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_ASMCOND_H diff --git a/include/llvm/MC/MCParser/AsmLexer.h b/include/llvm/MC/MCParser/AsmLexer.h index 029598c013d3..207183a69b0e 100644 --- a/include/llvm/MC/MCParser/AsmLexer.h +++ b/include/llvm/MC/MCParser/AsmLexer.h @@ -16,25 +16,22 @@ #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/Support/DataTypes.h" #include <string> namespace llvm { -class MemoryBuffer; + class MCAsmInfo; /// AsmLexer - Lexer class for assembly files. class AsmLexer : public MCAsmLexer { const MCAsmInfo &MAI; - const char *CurPtr; + const char *CurPtr = nullptr; StringRef CurBuf; - bool IsAtStartOfLine; - bool IsAtStartOfStatement; - bool IsParsingMSInlineAsm; - bool IsPeeking; - void operator=(const AsmLexer&) = delete; - AsmLexer(const AsmLexer&) = delete; + bool IsAtStartOfLine = true; + bool IsAtStartOfStatement = true; + bool IsParsingMSInlineAsm = false; + bool IsPeeking = false; protected: /// LexToken - Read the next token and return its code. @@ -42,6 +39,8 @@ protected: public: AsmLexer(const MCAsmInfo &MAI); + AsmLexer(const AsmLexer &) = delete; + AsmLexer &operator=(const AsmLexer &) = delete; ~AsmLexer() override; void setBuffer(StringRef Buf, const char *ptr = nullptr); @@ -74,4 +73,4 @@ private: } // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_ASMLEXER_H diff --git a/include/llvm/MC/MCParser/MCAsmLexer.h b/include/llvm/MC/MCParser/MCAsmLexer.h index 56da6f85c199..7ddc7722e512 100644 --- a/include/llvm/MC/MCParser/MCAsmLexer.h +++ b/include/llvm/MC/MCParser/MCAsmLexer.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCAsmLexer.h - Abstract Asm Lexer Interface -----*- C++ -*-===// +//===- llvm/MC/MCAsmLexer.h - Abstract Asm Lexer Interface ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,10 +14,12 @@ #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> +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <string> namespace llvm { @@ -76,7 +78,7 @@ private: APInt IntVal; public: - AsmToken() {} + AsmToken() = default; AsmToken(TokenKind Kind, StringRef Str, APInt IntVal) : Kind(Kind), Str(Str), IntVal(std::move(IntVal)) {} AsmToken(TokenKind Kind, StringRef Str, int64_t IntVal = 0) @@ -132,7 +134,7 @@ public: /// it is lexed. class AsmCommentConsumer { public: - virtual ~AsmCommentConsumer() {}; + virtual ~AsmCommentConsumer() = default; /// Callback function for when a comment is lexed. Loc is the start of the /// comment text (excluding the comment-start marker). CommentText is the text @@ -152,14 +154,12 @@ class MCAsmLexer { SMLoc ErrLoc; std::string Err; - MCAsmLexer(const MCAsmLexer &) = delete; - void operator=(const MCAsmLexer &) = delete; protected: // Can only create subclasses. - const char *TokStart; - bool SkipSpace; + const char *TokStart = nullptr; + bool SkipSpace = true; bool AllowAtInIdentifier; - bool IsAtStartOfStatement; - AsmCommentConsumer *CommentConsumer; + bool IsAtStartOfStatement = true; + AsmCommentConsumer *CommentConsumer = nullptr; MCAsmLexer(); @@ -171,6 +171,8 @@ protected: // Can only create subclasses. } public: + MCAsmLexer(const MCAsmLexer &) = delete; + MCAsmLexer &operator=(const MCAsmLexer &) = delete; virtual ~MCAsmLexer(); /// Consume the next token from the input stream and return it. @@ -255,6 +257,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCASMLEXER_H diff --git a/include/llvm/MC/MCParser/MCAsmParser.h b/include/llvm/MC/MCParser/MCAsmParser.h index eb85a3a30963..6763374185ec 100644 --- a/include/llvm/MC/MCParser/MCAsmParser.h +++ b/include/llvm/MC/MCParser/MCAsmParser.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCAsmParser.h - Abstract Asm Parser Interface ---*- C++ -*-===// +//===- llvm/MC/MCAsmParser.h - Abstract Asm Parser Interface ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,16 +10,21 @@ #ifndef LLVM_MC_MCPARSER_MCASMPARSER_H #define LLVM_MC_MCPARSER_MCASMPARSER_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/MC/MCParser/AsmLexer.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/Support/SMLoc.h" +#include <cstdint> +#include <string> +#include <utility> namespace llvm { + class MCAsmInfo; -class MCAsmLexer; class MCAsmParserExtension; class MCContext; class MCExpr; @@ -27,10 +32,7 @@ class MCInstPrinter; class MCInstrInfo; class MCStreamer; class MCTargetAsmParser; -class SMLoc; -class SMRange; class SourceMgr; -class Twine; class InlineAsmIdentifierInfo { public: @@ -51,12 +53,12 @@ public: class MCAsmParserSemaCallback { public: virtual ~MCAsmParserSemaCallback(); + virtual void *LookupInlineAsmIdentifier(StringRef &LineBuf, InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) = 0; virtual StringRef LookupInlineAsmLabel(StringRef Identifier, SourceMgr &SM, SMLoc Location, bool Create) = 0; - virtual bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset) = 0; }; @@ -76,22 +78,21 @@ public: }; private: - MCAsmParser(const MCAsmParser &) = delete; - void operator=(const MCAsmParser &) = delete; - - MCTargetAsmParser *TargetParser; + MCTargetAsmParser *TargetParser = nullptr; unsigned ShowParsedOperands : 1; protected: // Can only create subclasses. MCAsmParser(); - bool HadError; + bool HadError = false; SmallVector<MCPendingError, 1> PendingErrors; /// Flag tracking whether any errors have been encountered. public: + MCAsmParser(const MCAsmParser &) = delete; + MCAsmParser &operator=(const MCAsmParser &) = delete; virtual ~MCAsmParser(); virtual void addDirectiveHandler(StringRef Directive, @@ -186,12 +187,12 @@ public: bool parseEOL(const Twine &ErrMsg); - bool parseMany(std::function<bool()> parseOne, bool hasComma = true); + bool parseMany(function_ref<bool()> parseOne, bool hasComma = true); bool parseIntToken(int64_t &V, const Twine &ErrMsg); - bool check(bool P, const llvm::Twine &Msg); - bool check(bool P, SMLoc Loc, const llvm::Twine &Msg); + bool check(bool P, const Twine &Msg); + bool check(bool P, SMLoc Loc, const Twine &Msg); /// \brief Parse an identifier or string (as a quoted identifier) and set \p /// Res to the identifier contents. @@ -258,8 +259,8 @@ public: /// \brief Create an MCAsmParser instance. MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer &, - const MCAsmInfo &); + const MCAsmInfo &, unsigned CB = 0); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCASMPARSER_H diff --git a/include/llvm/MC/MCParser/MCAsmParserExtension.h b/include/llvm/MC/MCParser/MCAsmParserExtension.h index dabda0ab9485..ffb8d7a4a26a 100644 --- a/include/llvm/MC/MCParser/MCAsmParserExtension.h +++ b/include/llvm/MC/MCParser/MCAsmParserExtension.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCAsmParserExtension.h - Asm Parser Hooks -------*- C++ -*-===// +//===- llvm/MC/MCAsmParserExtension.h - Asm Parser Hooks --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,20 +10,20 @@ #ifndef LLVM_MC_MCPARSER_MCASMPARSEREXTENSION_H #define LLVM_MC_MCPARSER_MCASMPARSEREXTENSION_H +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/Support/SMLoc.h" namespace llvm { + class Twine; /// \brief Generic interface for extending the MCAsmParser, /// which is implemented by target and object file assembly parser /// implementations. class MCAsmParserExtension { - MCAsmParserExtension(const MCAsmParserExtension &) = delete; - void operator=(const MCAsmParserExtension &) = delete; - MCAsmParser *Parser; protected: @@ -38,9 +38,11 @@ protected: return (Obj->*Handler)(Directive, DirectiveLoc); } - bool BracketExpressionsSupported; + bool BracketExpressionsSupported = false; public: + MCAsmParserExtension(const MCAsmParserExtension &) = delete; + MCAsmParserExtension &operator=(const MCAsmParserExtension &) = delete; virtual ~MCAsmParserExtension(); /// \brief Initialize the extension for parsing using the given \p Parser. @@ -65,15 +67,19 @@ public: SourceMgr &getSourceManager() { return getParser().getSourceManager(); } MCStreamer &getStreamer() { return getParser().getStreamer(); } + bool Warning(SMLoc L, const Twine &Msg) { return getParser().Warning(L, Msg); } + bool Error(SMLoc L, const Twine &Msg, SMRange Range = SMRange()) { return getParser().Error(L, Msg, Range); } + void Note(SMLoc L, const Twine &Msg) { getParser().Note(L, Msg); } + bool TokError(const Twine &Msg) { return getParser().TokError(Msg); } @@ -85,7 +91,7 @@ public: return getParser().parseToken(T, Msg); } - bool parseMany(std::function<bool()> parseOne, bool hasComma = true) { + bool parseMany(function_ref<bool()> parseOne, bool hasComma = true) { return getParser().parseMany(parseOne, hasComma); } @@ -93,11 +99,11 @@ public: return getParser().parseOptionalToken(T); } - bool check(bool P, const llvm::Twine &Msg) { + bool check(bool P, const Twine &Msg) { return getParser().check(P, Msg); } - bool check(bool P, SMLoc Loc, const llvm::Twine &Msg) { + bool check(bool P, SMLoc Loc, const Twine &Msg) { return getParser().check(P, Loc, Msg); } @@ -110,6 +116,6 @@ public: /// @} }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCASMPARSEREXTENSION_H diff --git a/include/llvm/MC/MCParser/MCAsmParserUtils.h b/include/llvm/MC/MCParser/MCAsmParserUtils.h index 9834fe96307b..84173bb9cb8e 100644 --- a/include/llvm/MC/MCParser/MCAsmParserUtils.h +++ b/include/llvm/MC/MCParser/MCAsmParserUtils.h @@ -1,4 +1,4 @@ -//===------ llvm/MC/MCAsmParserUtils.h - Asm Parser Utilities ---*- C++ -*-===// +//===- llvm/MC/MCAsmParserUtils.h - Asm Parser Utilities --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -28,6 +28,7 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, const MCExpr *&Value); } // namespace MCParserUtils + } // namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCASMPARSERUTILS_H diff --git a/include/llvm/MC/MCParser/MCParsedAsmOperand.h b/include/llvm/MC/MCParser/MCParsedAsmOperand.h index a90d280c240c..4af76ac2a858 100644 --- a/include/llvm/MC/MCParser/MCParsedAsmOperand.h +++ b/include/llvm/MC/MCParser/MCParsedAsmOperand.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCParsedAsmOperand.h - Asm Parser Operand -------*- C++ -*-===// +//===- llvm/MC/MCParsedAsmOperand.h - Asm Parser Operand --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,11 +10,12 @@ #ifndef LLVM_MC_MCPARSER_MCPARSEDASMOPERAND_H #define LLVM_MC_MCPARSER_MCPARSEDASMOPERAND_H -#include <string> #include "llvm/ADT/StringRef.h" #include "llvm/Support/SMLoc.h" +#include <string> namespace llvm { + class raw_ostream; /// MCParsedAsmOperand - This abstract class represents a source-level assembly @@ -35,12 +36,12 @@ protected: // lots of members and MSVC doesn't support defaulted move ops, so to avoid // that verbosity, just rely on defaulted copy ops. It's only the Constraint // string member that would benefit from movement anyway. + MCParsedAsmOperand() = default; MCParsedAsmOperand(const MCParsedAsmOperand &RHS) = default; MCParsedAsmOperand &operator=(const MCParsedAsmOperand &) = default; - MCParsedAsmOperand() = default; public: - virtual ~MCParsedAsmOperand() {} + virtual ~MCParsedAsmOperand() = default; void setConstraint(StringRef C) { Constraint = C.str(); } StringRef getConstraint() { return Constraint; } @@ -81,6 +82,7 @@ public: /// print - Print a debug representation of the operand to the given stream. virtual void print(raw_ostream &OS) const = 0; + /// dump - Print to the debug stream. virtual void dump() const; }; @@ -93,6 +95,6 @@ inline raw_ostream& operator<<(raw_ostream &OS, const MCParsedAsmOperand &MO) { return OS; } -} // end namespace llvm. +} // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCPARSEDASMOPERAND_H diff --git a/include/llvm/MC/MCParser/MCTargetAsmParser.h b/include/llvm/MC/MCParser/MCTargetAsmParser.h index 70cd60c9a112..c81a7624011f 100644 --- a/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCTargetAsmParser.h - Target Assembly Parser ----*- C++ -*-===// +//===- llvm/MC/MCTargetAsmParser.h - Target Assembly Parser -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,19 +10,21 @@ #ifndef LLVM_MC_MCPARSER_MCTARGETASMPARSER_H #define LLVM_MC_MCPARSER_MCTARGETASMPARSER_H +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCTargetOptions.h" +#include "llvm/Support/SMLoc.h" +#include <cstdint> #include <memory> namespace llvm { -class AsmToken; + class MCInst; class MCParsedAsmOperand; class MCStreamer; class MCSubtargetInfo; -class SMLoc; -class StringRef; template <typename T> class SmallVectorImpl; typedef SmallVectorImpl<std::unique_ptr<MCParsedAsmOperand>> OperandVector; @@ -66,6 +68,7 @@ struct AsmRewrite { unsigned Len; unsigned Val; StringRef Label; + public: AsmRewrite(AsmRewriteKind kind, SMLoc loc, unsigned len = 0, unsigned val = 0) : Kind(kind), Loc(loc), Len(len), Val(val) {} @@ -74,10 +77,9 @@ public: }; struct ParseInstructionInfo { + SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr; - SmallVectorImpl<AsmRewrite> *AsmRewrites; - - ParseInstructionInfo() : AsmRewrites(nullptr) {} + ParseInstructionInfo() = default; ParseInstructionInfo(SmallVectorImpl<AsmRewrite> *rewrites) : AsmRewrites(rewrites) {} }; @@ -99,9 +101,6 @@ public: FIRST_TARGET_MATCH_RESULT_TY }; -private: - MCTargetAsmParser(const MCTargetAsmParser &) = delete; - void operator=(const MCTargetAsmParser &) = delete; protected: // Can only create subclasses. MCTargetAsmParser(MCTargetOptions const &, const MCSubtargetInfo &STI); @@ -109,10 +108,10 @@ protected: // Can only create subclasses. MCSubtargetInfo ©STI(); /// AvailableFeatures - The current set of available features. - uint64_t AvailableFeatures; + uint64_t AvailableFeatures = 0; /// ParsingInlineAsm - Are we parsing ms-style inline assembly? - bool ParsingInlineAsm; + bool ParsingInlineAsm = false; /// SemaCallback - The Sema callback implementation. Must be set when parsing /// ms-style inline assembly. @@ -125,6 +124,9 @@ protected: // Can only create subclasses. const MCSubtargetInfo *STI; public: + MCTargetAsmParser(const MCTargetAsmParser &) = delete; + MCTargetAsmParser &operator=(const MCTargetAsmParser &) = delete; + ~MCTargetAsmParser() override; const MCSubtargetInfo &getSTI() const; @@ -229,11 +231,11 @@ public: return nullptr; } - virtual void onLabelParsed(MCSymbol *Symbol) { } + virtual void onLabelParsed(MCSymbol *Symbol) {} /// Ensure that all previously parsed instructions have been emitted to the /// output streamer, if the target does not emit them immediately. - virtual void flushPendingInstructions(MCStreamer &Out) { } + virtual void flushPendingInstructions(MCStreamer &Out) {} virtual const MCExpr *createTargetUnaryExpr(const MCExpr *E, AsmToken::TokenKind OperatorToken, @@ -242,6 +244,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCPARSER_MCTARGETASMPARSER_H diff --git a/include/llvm/MC/MCRegisterInfo.h b/include/llvm/MC/MCRegisterInfo.h index 3dc88a298ff8..015d0b96d9f2 100644 --- a/include/llvm/MC/MCRegisterInfo.h +++ b/include/llvm/MC/MCRegisterInfo.h @@ -1,4 +1,4 @@ -//=== MC/MCRegisterInfo.h - Target Register Description ---------*- C++ -*-===// +//===- MC/MCRegisterInfo.h - Target Register Description --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,9 +17,11 @@ #define LLVM_MC_MCREGISTERINFO_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/MC/LaneBitmask.h" -#include "llvm/Support/ErrorHandling.h" #include <cassert> +#include <cstdint> +#include <utility> namespace llvm { @@ -39,7 +41,7 @@ public: const uint16_t RegsSize; const uint16_t RegSetSize; const uint16_t ID; - const uint16_t RegSize, Alignment; // Size & Alignment of register in bytes + const uint16_t PhysRegSize; const int8_t CopyCost; const bool Allocatable; @@ -78,13 +80,10 @@ public: return contains(Reg1) && contains(Reg2); } - /// getSize - Return the size of the register in bytes, which is also the size - /// of a stack slot allocated to hold a spilled copy of this register. - unsigned getSize() const { return RegSize; } - - /// getAlignment - Return the minimum required alignment for a register of - /// this class. - unsigned getAlignment() const { return Alignment; } + /// Return the size of the physical register in bytes. + unsigned getPhysRegSize() const { return PhysRegSize; } + /// Temporary function to allow out-of-tree targets to switch. + unsigned getSize() const { return getPhysRegSize(); } /// getCopyCost - Return the cost of copying a value between two registers in /// this class. A negative number means the register class is very expensive @@ -152,6 +151,7 @@ public: uint16_t Offset; uint16_t Size; }; + private: const MCRegisterDesc *Desc; // Pointer to the descriptor array unsigned NumRegs; // Number of entries in the array @@ -191,12 +191,12 @@ public: /// Don't use this class directly, use one of the specialized sub-classes /// defined below. class DiffListIterator { - uint16_t Val; - const MCPhysReg *List; + uint16_t Val = 0; + const MCPhysReg *List = nullptr; protected: /// Create an invalid iterator. Call init() to point to something useful. - DiffListIterator() : Val(0), List(nullptr) {} + DiffListIterator() = default; /// init - Point the iterator to InitVal, decoding subsequent values from /// DiffList. The iterator will initially point to InitVal, sub-classes are @@ -217,7 +217,6 @@ public: } public: - /// isValid - returns true if this iterator is not yet at the end. bool isValid() const { return List; } @@ -418,6 +417,9 @@ public: regclass_iterator regclass_begin() const { return Classes; } regclass_iterator regclass_end() const { return Classes+NumClasses; } + iterator_range<regclass_iterator> regclasses() const { + return make_range(regclass_begin(), regclass_end()); + } unsigned getNumRegClasses() const { return (unsigned)(regclass_end()-regclass_begin()); @@ -492,6 +494,7 @@ public: class MCSubRegIndexIterator { MCSubRegIterator SRIter; const uint16_t *SRIndex; + public: /// Constructs an iterator that traverses subregisters and their /// associated subregister indices. @@ -504,6 +507,7 @@ public: unsigned getSubReg() const { return *SRIter; } + /// Returns sub-register index of the current sub-register. unsigned getSubRegIndex() const { return *SRIndex; @@ -523,7 +527,8 @@ public: /// If IncludeSelf is set, Reg itself is included in the list. class MCSuperRegIterator : public MCRegisterInfo::DiffListIterator { public: - MCSuperRegIterator() {} + MCSuperRegIterator() = default; + MCSuperRegIterator(unsigned Reg, const MCRegisterInfo *MCRI, bool IncludeSelf = false) { init(Reg, MCRI->DiffLists + MCRI->get(Reg).SuperRegs); @@ -560,7 +565,8 @@ class MCRegUnitIterator : public MCRegisterInfo::DiffListIterator { public: /// MCRegUnitIterator - Create an iterator that traverses the register units /// in Reg. - MCRegUnitIterator() {} + MCRegUnitIterator() = default; + MCRegUnitIterator(unsigned Reg, const MCRegisterInfo *MCRI) { assert(Reg && "Null register has no regunits"); // Decode the RegUnits MCRegisterDesc field. @@ -586,8 +592,10 @@ public: class MCRegUnitMaskIterator { MCRegUnitIterator RUIter; const LaneBitmask *MaskListIter; + public: - MCRegUnitMaskIterator() {} + MCRegUnitMaskIterator() = default; + /// Constructs an iterator that traverses the register units and their /// associated LaneMasks in Reg. MCRegUnitMaskIterator(unsigned Reg, const MCRegisterInfo *MCRI) @@ -622,10 +630,12 @@ public: /// MCRegUnitRootIterator enumerates the root registers of a register unit. class MCRegUnitRootIterator { - uint16_t Reg0; - uint16_t Reg1; + uint16_t Reg0 = 0; + uint16_t Reg1 = 0; + public: - MCRegUnitRootIterator() : Reg0(0), Reg1(0) {} + MCRegUnitRootIterator() = default; + MCRegUnitRootIterator(unsigned RegUnit, const MCRegisterInfo *MCRI) { assert(RegUnit < MCRI->getNumRegUnits() && "Invalid register unit"); Reg0 = MCRI->RegUnitRoots[RegUnit][0]; @@ -662,11 +672,11 @@ private: MCRegUnitIterator RI; MCRegUnitRootIterator RRI; MCSuperRegIterator SI; + public: MCRegAliasIterator(unsigned Reg, const MCRegisterInfo *MCRI, bool IncludeSelf) : Reg(Reg), MCRI(MCRI), IncludeSelf(IncludeSelf) { - // Initialize the iterators. for (RI = MCRegUnitIterator(Reg, MCRI); RI.isValid(); ++RI) { for (RRI = MCRegUnitRootIterator(*RI, MCRI); RRI.isValid(); ++RRI) { @@ -681,7 +691,7 @@ public: bool isValid() const { return RI.isValid(); } unsigned operator*() const { - assert (SI.isValid() && "Cannot dereference an invalid iterator."); + assert(SI.isValid() && "Cannot dereference an invalid iterator."); return *SI; } @@ -710,6 +720,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCREGISTERINFO_H diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index d4c31696b40f..2974d8f1b80b 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -14,22 +14,21 @@ #ifndef LLVM_MC_MCSECTION_H #define LLVM_MC_MCSECTION_H -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/SectionKind.h" -#include "llvm/Support/Compiler.h" +#include <cassert> +#include <utility> namespace llvm { + class MCAsmInfo; -class MCAssembler; class MCContext; class MCExpr; -class MCFragment; -class MCSection; class MCSymbol; class raw_ostream; +class Triple; template <> struct ilist_alloc_traits<MCFragment> { static void deleteNode(MCFragment *V); @@ -39,7 +38,7 @@ template <> struct ilist_alloc_traits<MCFragment> { /// current translation unit. The MCContext class uniques and creates these. class MCSection { public: - enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO }; + enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm }; /// \brief Express the state of bundle locked groups while emitting code. enum BundleLockStateType { @@ -57,9 +56,6 @@ public: typedef FragmentListType::reverse_iterator reverse_iterator; private: - MCSection(const MCSection &) = delete; - void operator=(const MCSection &) = delete; - MCSymbol *Begin; MCSymbol *End = nullptr; /// The alignment requirement of this section. @@ -77,12 +73,12 @@ private: /// \brief We've seen a bundle_lock directive but not its first instruction /// yet. - unsigned BundleGroupBeforeFirstInst : 1; + bool BundleGroupBeforeFirstInst : 1; /// Whether this section has had instructions emitted into it. - unsigned HasInstructions : 1; + bool HasInstructions : 1; - unsigned IsRegistered : 1; + bool IsRegistered : 1; MCDummyFragment DummyFragment; @@ -93,12 +89,16 @@ private: SmallVector<std::pair<unsigned, MCFragment *>, 1> SubsectionFragmentMap; protected: - MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin); SectionVariant Variant; SectionKind Kind; + + MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin); ~MCSection(); public: + MCSection(const MCSection &) = delete; + MCSection &operator=(const MCSection &) = delete; + SectionKind getKind() const { return Kind; } SectionVariant getVariant() const { return Variant; } @@ -169,7 +169,8 @@ public: void dump(); - virtual void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, const MCExpr *Subsection) const = 0; /// Return true if a .align directive should use "optimized nops" to fill @@ -183,4 +184,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_MC_MCSECTION_H diff --git a/include/llvm/MC/MCSectionCOFF.h b/include/llvm/MC/MCSectionCOFF.h index 7d5f9f7f3cde..24b9f8898ebb 100644 --- a/include/llvm/MC/MCSectionCOFF.h +++ b/include/llvm/MC/MCSectionCOFF.h @@ -16,8 +16,11 @@ #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" +#include "llvm/MC/SectionKind.h" +#include <cassert> namespace llvm { + class MCSymbol; /// This represents a section on Windows @@ -73,7 +76,8 @@ public: void setSelection(int Selection) const; - void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, const MCExpr *Subsection) const override; bool UseCodeAlign() const override; bool isVirtualSection() const override; @@ -93,4 +97,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_MC_MCSECTIONCOFF_H diff --git a/include/llvm/MC/MCSectionELF.h b/include/llvm/MC/MCSectionELF.h index dabd787b0d45..00c289c6bd6e 100644 --- a/include/llvm/MC/MCSectionELF.h +++ b/include/llvm/MC/MCSectionELF.h @@ -14,12 +14,10 @@ #ifndef LLVM_MC_MCSECTIONELF_H #define LLVM_MC_MCSECTIONELF_H -#include "llvm/ADT/Twine.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbolELF.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/MC/SectionKind.h" namespace llvm { @@ -47,17 +45,18 @@ class MCSectionELF final : public MCSection { const MCSymbolELF *Group; - /// Depending on the type of the section this is sh_link or sh_info. - const MCSectionELF *Associated; + /// sh_info for SHF_LINK_ORDER (can be null). + const MCSymbol *AssociatedSymbol; private: friend class MCContext; + MCSectionELF(StringRef Section, unsigned type, unsigned flags, SectionKind K, unsigned entrySize, const MCSymbolELF *group, unsigned UniqueID, - MCSymbol *Begin, const MCSectionELF *Associated) + MCSymbol *Begin, const MCSymbolELF *AssociatedSymbol) : MCSection(SV_ELF, K, Begin), SectionName(Section), Type(type), Flags(flags), UniqueID(UniqueID), EntrySize(entrySize), Group(group), - Associated(Associated) { + AssociatedSymbol(AssociatedSymbol) { if (Group) Group->setIsSignature(); } @@ -78,7 +77,8 @@ public: void setFlags(unsigned F) { Flags = F; } const MCSymbolELF *getGroup() const { return Group; } - void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, const MCExpr *Subsection) const override; bool UseCodeAlign() const override; bool isVirtualSection() const override; @@ -86,7 +86,8 @@ public: bool isUnique() const { return UniqueID != ~0U; } unsigned getUniqueID() const { return UniqueID; } - const MCSectionELF *getAssociatedSection() const { return Associated; } + const MCSection *getAssociatedSection() const { return &AssociatedSymbol->getSection(); } + const MCSymbol *getAssociatedSymbol() const { return AssociatedSymbol; } static bool classof(const MCSection *S) { return S->getVariant() == SV_ELF; @@ -95,4 +96,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_MC_MCSECTIONELF_H diff --git a/include/llvm/MC/MCSectionMachO.h b/include/llvm/MC/MCSectionMachO.h index 658dfcda7268..3bc5408a4f75 100644 --- a/include/llvm/MC/MCSectionMachO.h +++ b/include/llvm/MC/MCSectionMachO.h @@ -76,7 +76,8 @@ public: bool &TAAParsed, // Out. unsigned &StubSize); // Out. - void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, + void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, const MCExpr *Subsection) const override; bool UseCodeAlign() const override; bool isVirtualSection() const override; diff --git a/include/llvm/MC/MCSectionWasm.h b/include/llvm/MC/MCSectionWasm.h new file mode 100644 index 000000000000..4e19196175c0 --- /dev/null +++ b/include/llvm/MC/MCSectionWasm.h @@ -0,0 +1,86 @@ +//===- MCSectionWasm.h - Wasm Machine Code Sections -------------*- 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 MCSectionWasm class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCSECTIONWASM_H +#define LLVM_MC_MCSECTIONWASM_H + +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class MCSymbol; + +/// This represents a section on wasm. +class MCSectionWasm final : public MCSection { + /// This is the name of the section. The referenced memory is owned by + /// TargetLoweringObjectFileWasm's WasmUniqueMap. + StringRef SectionName; + + /// This is the sh_type field of a section, drawn from the enums below. + unsigned Type; + + /// This is the sh_flags field of a section, drawn from the enums below. + unsigned Flags; + + unsigned UniqueID; + + const MCSymbolWasm *Group; + + // The offset of the MC function section in the wasm code section. + uint64_t SectionOffset; + +private: + friend class MCContext; + MCSectionWasm(StringRef Section, unsigned type, unsigned flags, SectionKind K, + const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin) + : MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type), + Flags(flags), UniqueID(UniqueID), Group(group), SectionOffset(0) { + } + + void setSectionName(StringRef Name) { SectionName = Name; } + +public: + ~MCSectionWasm(); + + /// Decides whether a '.section' directive should be printed before the + /// section name + bool ShouldOmitSectionDirective(StringRef Name, const MCAsmInfo &MAI) const; + + StringRef getSectionName() const { return SectionName; } + unsigned getType() const { return Type; } + unsigned getFlags() const { return Flags; } + void setFlags(unsigned F) { Flags = F; } + const MCSymbolWasm *getGroup() const { return Group; } + + void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, + const MCExpr *Subsection) const override; + bool UseCodeAlign() const override; + bool isVirtualSection() const override; + + bool isUnique() const { return UniqueID != ~0U; } + unsigned getUniqueID() const { return UniqueID; } + + uint64_t getSectionOffset() const { return SectionOffset; } + void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; } + + static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; } +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 41f00a24dfbf..e466b368ed34 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -15,17 +15,26 @@ #define LLVM_MC_MCSTREAMER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCWinEH.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" +#include <cassert> +#include <cstdint> +#include <memory> #include <string> +#include <utility> +#include <vector> namespace llvm { + +class AssemblerConstantPools; +class formatted_raw_ostream; class MCAsmBackend; class MCCodeEmitter; class MCContext; @@ -34,14 +43,11 @@ class MCInst; class MCInstPrinter; class MCSection; class MCStreamer; -class MCSymbolELF; class MCSymbolRefExpr; +class MCSymbolWasm; class MCSubtargetInfo; -class StringRef; -class Twine; class raw_ostream; -class formatted_raw_ostream; -class AssemblerConstantPools; +class Twine; typedef std::pair<MCSection *, const MCExpr *> MCSectionSubPair; @@ -162,9 +168,6 @@ class MCStreamer { MCContext &Context; std::unique_ptr<MCTargetStreamer> TargetStreamer; - MCStreamer(const MCStreamer &) = delete; - MCStreamer &operator=(const MCStreamer &) = delete; - std::vector<MCDwarfFrameInfo> DwarfFrameInfos; MCDwarfFrameInfo *getCurrentDwarfFrameInfo(); void EnsureValidDwarfFrame(); @@ -205,6 +208,8 @@ protected: virtual void EmitRawTextImpl(StringRef String); public: + MCStreamer(const MCStreamer &) = delete; + MCStreamer &operator=(const MCStreamer &) = delete; virtual ~MCStreamer(); void visitUsedExpr(const MCExpr &Expr); @@ -282,6 +287,7 @@ public: /// \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(); @@ -393,7 +399,7 @@ public: /// used in an assignment. // FIXME: These emission are non-const because we mutate the symbol to // add the section we're emitting it to later. - virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()); virtual void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol); @@ -483,6 +489,14 @@ public: /// .size symbol, expression virtual void emitELFSize(MCSymbol *Symbol, const MCExpr *Value); + /// \brief Emit an ELF .symver directive. + /// + /// This corresponds to an assembler statement such as: + /// .symver _start, foo@@SOME_VERSION + /// \param Alias - The versioned alias (i.e. "foo@@SOME_VERSION") + /// \param Aliasee - The aliased symbol (i.e. "_start") + virtual void emitELFSymverDirective(MCSymbol *Alias, const MCSymbol *Aliasee); + /// \brief Emit a Linker Optimization Hint (LOH) directive. /// \param Args - Arguments of the LOH. virtual void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {} @@ -822,7 +836,9 @@ public: } /// \brief Emit the given \p Instruction into the current section. - virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); + /// PrintSchedInfo == true then schedul comment should be added to output + virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + bool PrintSchedInfo = false); /// \brief Set the bundle alignment mode from now on in the section. /// The argument is the power of 2 to which the alignment is set. The @@ -876,6 +892,7 @@ MCStreamer *createAsmStreamer(MCContext &Ctx, bool isVerboseAsm, bool useDwarfDirectory, MCInstPrinter *InstPrint, MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst); + } // end namespace llvm -#endif +#endif // LLVM_MC_MCSTREAMER_H diff --git a/include/llvm/MC/MCSubtargetInfo.h b/include/llvm/MC/MCSubtargetInfo.h index 5ede043fa2ee..6229db3bbcb2 100644 --- a/include/llvm/MC/MCSubtargetInfo.h +++ b/include/llvm/MC/MCSubtargetInfo.h @@ -1,4 +1,4 @@ -//==-- llvm/MC/MCSubtargetInfo.h - Subtarget Information ---------*- C++ -*-==// +//===- llvm/MC/MCSubtargetInfo.h - Subtarget Information --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,13 +15,19 @@ #define LLVM_MC_MCSUBTARGETINFO_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" #include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/MCSchedule.h" #include "llvm/MC/SubtargetFeature.h" +#include <algorithm> +#include <cassert> +#include <cstdint> #include <string> namespace llvm { - -class StringRef; +class MachineInstr; +class MCInst; //===----------------------------------------------------------------------===// /// @@ -45,10 +51,6 @@ class MCSubtargetInfo { const unsigned *ForwardingPaths; // Forwarding paths FeatureBitset FeatureBits; // Feature bits for current CPU + FS - MCSubtargetInfo() = delete; - MCSubtargetInfo &operator=(MCSubtargetInfo &&) = delete; - MCSubtargetInfo &operator=(const MCSubtargetInfo &) = delete; - public: MCSubtargetInfo(const MCSubtargetInfo &) = default; MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS, @@ -58,6 +60,11 @@ public: const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA, const InstrStage *IS, const unsigned *OC, const unsigned *FP); + MCSubtargetInfo() = delete; + MCSubtargetInfo &operator=(const MCSubtargetInfo &) = delete; + MCSubtargetInfo &operator=(MCSubtargetInfo &&) = delete; + + virtual ~MCSubtargetInfo() {} /// getTargetTriple - Return the target triple string. const Triple &getTargetTriple() const { return TargetTriple; } @@ -164,8 +171,17 @@ public: auto Found = std::lower_bound(ProcDesc.begin(), ProcDesc.end(), CPU); return Found != ProcDesc.end() && StringRef(Found->Key) == CPU; } + + /// Returns string representation of scheduler comment + virtual std::string getSchedInfoStr(const MachineInstr &MI) const { + return std::string(); + } + + virtual std::string getSchedInfoStr(MCInst const &MCI) const { + return std::string(); + } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCSUBTARGETINFO_H diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index 23e34b7869a5..e8432afd8627 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -15,18 +15,21 @@ #define LLVM_MC_MCSYMBOL_H #include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCFragment.h" -#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include <cassert> +#include <cstddef> +#include <cstdint> namespace llvm { + class MCAsmInfo; +class MCContext; class MCExpr; -class MCSymbol; -class MCFragment; class MCSection; -class MCContext; class raw_ostream; /// MCSymbol - Instances of this class represent a symbol name in the MC file, @@ -45,6 +48,7 @@ protected: SymbolKindCOFF, SymbolKindELF, SymbolKindMachO, + SymbolKindWasm, }; /// A symbol can contain an Offset, or Value, or be Common, but never more @@ -97,7 +101,7 @@ protected: /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is /// unsigned to avoid sign extension and achieve better bitpacking with MSVC. - unsigned Kind : 2; + unsigned Kind : 3; /// True if we have created a relocation that uses this symbol. mutable unsigned IsUsedInReloc : 1; @@ -133,7 +137,7 @@ protected: const MCExpr *Value; }; -protected: // MCContext creates and uniques these. + // MCContext creates and uniques these. friend class MCExpr; friend class MCContext; @@ -163,7 +167,6 @@ protected: // MCContext creates and uniques these. MCContext &Ctx); private: - void operator delete(void *); /// \brief Placement delete - required by std, but never called. void operator delete(void*, unsigned) { @@ -174,8 +177,6 @@ private: llvm_unreachable("Constructor throws?"); } - MCSymbol(const MCSymbol &) = delete; - void operator=(const MCSymbol &) = delete; MCSection *getSectionPtr(bool SetUsed = true) const { if (MCFragment *F = getFragment(SetUsed)) { assert(F != AbsolutePseudoFragment); @@ -195,6 +196,9 @@ private: } public: + MCSymbol(const MCSymbol &) = delete; + MCSymbol &operator=(const MCSymbol &) = delete; + /// getName - Get the symbol name. StringRef getName() const { if (!FragmentAndHasName.getInt()) @@ -281,6 +285,8 @@ public: bool isMachO() const { return Kind == SymbolKindMachO; } + bool isWasm() const { return Kind == SymbolKindWasm; } + /// @} /// \name Variable Symbols /// @{ @@ -416,6 +422,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MCSymbol &Sym) { Sym.print(OS, nullptr); return OS; } + } // end namespace llvm -#endif +#endif // LLVM_MC_MCSYMBOL_H diff --git a/include/llvm/MC/MCSymbolCOFF.h b/include/llvm/MC/MCSymbolCOFF.h index 2172c67981c0..7918c353dc15 100644 --- a/include/llvm/MC/MCSymbolCOFF.h +++ b/include/llvm/MC/MCSymbolCOFF.h @@ -6,16 +6,18 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// + #ifndef LLVM_MC_MCSYMBOLCOFF_H #define LLVM_MC_MCSYMBOLCOFF_H #include "llvm/MC/MCSymbol.h" +#include <cstdint> namespace llvm { -class MCSymbolCOFF : public MCSymbol { +class MCSymbolCOFF : public MCSymbol { /// This corresponds to the e_type field of the COFF symbol. - mutable uint16_t Type; + mutable uint16_t Type = 0; enum SymbolFlags : uint16_t { SF_ClassMask = 0x00FF, @@ -27,7 +29,7 @@ class MCSymbolCOFF : public MCSymbol { public: MCSymbolCOFF(const StringMapEntry<bool> *Name, bool isTemporary) - : MCSymbol(SymbolKindCOFF, Name, isTemporary), Type(0) {} + : MCSymbol(SymbolKindCOFF, Name, isTemporary) {} uint16_t getType() const { return Type; @@ -59,6 +61,7 @@ public: static bool classof(const MCSymbol *S) { return S->isCOFF(); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_MC_MCSYMBOLCOFF_H diff --git a/include/llvm/MC/MCSymbolWasm.h b/include/llvm/MC/MCSymbolWasm.h new file mode 100644 index 000000000000..4445be006eb0 --- /dev/null +++ b/include/llvm/MC/MCSymbolWasm.h @@ -0,0 +1,57 @@ +//===- MCSymbolWasm.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_MC_MCSYMBOLWASM_H +#define LLVM_MC_MCSYMBOLWASM_H + +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Wasm.h" + +namespace llvm { +class MCSymbolWasm : public MCSymbol { +private: + bool IsFunction = false; + std::string ModuleName; + SmallVector<wasm::ValType, 1> Returns; + SmallVector<wasm::ValType, 4> Params; + + /// An expression describing how to calculate the size of a symbol. If a + /// symbol has no size this field will be NULL. + const MCExpr *SymbolSize = nullptr; + +public: + // Use a module name of "env" for now, for compatibility with existing tools. + // This is temporary, and may change, as the ABI is not yet stable. + MCSymbolWasm(const StringMapEntry<bool> *Name, bool isTemporary) + : MCSymbol(SymbolKindWasm, Name, isTemporary), + ModuleName("env") {} + static bool classof(const MCSymbol *S) { return S->isWasm(); } + + const MCExpr *getSize() const { return SymbolSize; } + void setSize(const MCExpr *SS) { SymbolSize = SS; } + + bool isFunction() const { return IsFunction; } + void setIsFunction(bool isFunc) { IsFunction = isFunc; } + + const StringRef getModuleName() const { return ModuleName; } + + const SmallVector<wasm::ValType, 1> &getReturns() const { return Returns; } + + void setReturns(SmallVectorImpl<wasm::ValType> &&Rets) { + Returns = std::move(Rets); + } + + const SmallVector<wasm::ValType, 4> &getParams() const { return Params; } + + void setParams(SmallVectorImpl<wasm::ValType> &&Pars) { + Params = std::move(Pars); + } +}; +} + +#endif diff --git a/include/llvm/MC/MCTargetOptions.h b/include/llvm/MC/MCTargetOptions.h index 25642379ac9f..06f58d498030 100644 --- a/include/llvm/MC/MCTargetOptions.h +++ b/include/llvm/MC/MCTargetOptions.h @@ -1,4 +1,4 @@ -//===- MCTargetOptions.h - MC Target Options -------------------*- C++ -*-===// +//===- MCTargetOptions.h - MC Target Options --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -51,12 +51,8 @@ public: /// Preserve Comments in Assembly. bool PreserveAsmComments : 1; - int DwarfVersion; + int DwarfVersion = 0; - /// 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 - /// aapcs-linux. - StringRef getABIName() const; std::string ABIName; /// Additional paths to search for `.include` directives when using the @@ -64,33 +60,13 @@ public: std::vector<std::string> IASSearchPaths; MCTargetOptions(); -}; -inline bool operator==(const MCTargetOptions &LHS, const MCTargetOptions &RHS) { -#define ARE_EQUAL(X) LHS.X == RHS.X - return (ARE_EQUAL(SanitizeAddress) && - ARE_EQUAL(MCRelaxAll) && - ARE_EQUAL(MCNoExecStack) && - ARE_EQUAL(MCFatalWarnings) && - ARE_EQUAL(MCNoWarn) && - ARE_EQUAL(MCNoDeprecatedWarn) && - ARE_EQUAL(MCSaveTempLabels) && - ARE_EQUAL(MCUseDwarfDirectory) && - ARE_EQUAL(MCIncrementalLinkerCompatible) && - ARE_EQUAL(MCPIECopyRelocations) && - ARE_EQUAL(ShowMCEncoding) && - ARE_EQUAL(ShowMCInst) && - ARE_EQUAL(AsmVerbose) && - ARE_EQUAL(DwarfVersion) && - ARE_EQUAL(ABIName) && - ARE_EQUAL(IASSearchPaths)); -#undef ARE_EQUAL -} - -inline bool operator!=(const MCTargetOptions &LHS, const MCTargetOptions &RHS) { - return !(LHS == RHS); -} + /// 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 + /// aapcs-linux. + StringRef getABIName() const; +}; } // end namespace llvm -#endif +#endif // LLVM_MC_MCTARGETOPTIONS_H diff --git a/include/llvm/MC/MCWasmObjectWriter.h b/include/llvm/MC/MCWasmObjectWriter.h new file mode 100644 index 000000000000..6e458eaac9c8 --- /dev/null +++ b/include/llvm/MC/MCWasmObjectWriter.h @@ -0,0 +1,85 @@ +//===-- llvm/MC/MCWasmObjectWriter.h - Wasm Object Writer -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCWASMOBJECTWRITER_H +#define LLVM_MC_MCWASMOBJECTWRITER_H + +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +namespace llvm { +class MCAssembler; +class MCContext; +class MCFixup; +class MCFragment; +class MCObjectWriter; +class MCSectionWasm; +class MCSymbol; +class MCSymbolWasm; +class MCValue; +class raw_pwrite_stream; + +// Information about a single relocation. +struct WasmRelocationEntry { + uint64_t Offset; // Where is the relocation. + const MCSymbolWasm *Symbol; // The symbol to relocate with. + uint64_t Addend; // A value to add to the symbol. + unsigned Type; // The type of the relocation. + MCSectionWasm *FixupSection;// The section the relocation is targeting. + + WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, + uint64_t Addend, unsigned Type, + MCSectionWasm *FixupSection) + : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), + FixupSection(FixupSection) {} + + void print(raw_ostream &Out) const { + Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend + << ", Type=" << Type << ", FixupSection=" << FixupSection; + } + void dump() const { print(errs()); } +}; + +class MCWasmObjectTargetWriter { + const unsigned Is64Bit : 1; + +protected: + explicit MCWasmObjectTargetWriter(bool Is64Bit_); + +public: + virtual ~MCWasmObjectTargetWriter() {} + + virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const = 0; + + virtual bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const; + + virtual void sortRelocs(const MCAssembler &Asm, + std::vector<WasmRelocationEntry> &Relocs); + + /// \name Accessors + /// @{ + bool is64Bit() const { return Is64Bit; } + /// @} +}; + +/// \brief Construct a new Wasm writer instance. +/// +/// \param MOTW - The target specific Wasm writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +MCObjectWriter *createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, + raw_pwrite_stream &OS); +} // End llvm namespace + +#endif diff --git a/include/llvm/MC/MCWasmStreamer.h b/include/llvm/MC/MCWasmStreamer.h new file mode 100644 index 000000000000..bdd6f103cd44 --- /dev/null +++ b/include/llvm/MC/MCWasmStreamer.h @@ -0,0 +1,83 @@ +//===- MCWasmStreamer.h - MCStreamer Wasm Object File Interface -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCWASMSTREAMER_H +#define LLVM_MC_MCWASMSTREAMER_H + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCAssembler; +class MCCodeEmitter; +class MCExpr; +class MCInst; +class raw_ostream; + +class MCWasmStreamer : public MCObjectStreamer { +public: + MCWasmStreamer(MCContext &Context, MCAsmBackend &TAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter), SeenIdent(false) {} + + ~MCWasmStreamer() override; + + /// state management + void reset() override { + SeenIdent = false; + MCObjectStreamer::reset(); + } + + /// \name MCStreamer Interface + /// @{ + + void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; + void EmitAssemblerFlag(MCAssemblerFlag Flag) override; + void EmitThumbFunc(MCSymbol *Func) override; + void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; + void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; + void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override; + + void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; + + void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override; + + void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0) override; + void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment = 0) override; + void EmitValueImpl(const MCExpr *Value, unsigned Size, + SMLoc Loc = SMLoc()) override; + + void EmitIdent(StringRef IdentString) override; + + void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override; + + void FinishImpl() override; + +private: + void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override; + void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; + + /// \brief Merge the content of the fragment \p EF into the fragment \p DF. + void mergeFragment(MCDataFragment *, MCDataFragment *); + + bool SeenIdent; +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/MC/MCWinCOFFObjectWriter.h b/include/llvm/MC/MCWinCOFFObjectWriter.h index e2e95c7df710..57bed213aad4 100644 --- a/include/llvm/MC/MCWinCOFFObjectWriter.h +++ b/include/llvm/MC/MCWinCOFFObjectWriter.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MCWinCOFFObjectWriter.h - Win COFF Object Writer *- C++ -*-===// +//===- llvm/MC/MCWinCOFFObjectWriter.h - Win COFF Object Writer -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,22 +11,23 @@ #define LLVM_MC_MCWINCOFFOBJECTWRITER_H namespace llvm { + class MCAsmBackend; class MCFixup; class MCObjectWriter; class MCValue; -class raw_ostream; class raw_pwrite_stream; class MCWinCOFFObjectTargetWriter { virtual void anchor(); + const unsigned Machine; protected: MCWinCOFFObjectTargetWriter(unsigned Machine_); public: - virtual ~MCWinCOFFObjectTargetWriter() {} + virtual ~MCWinCOFFObjectTargetWriter() = default; unsigned getMachine() const { return Machine; } virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, @@ -42,6 +43,6 @@ class raw_pwrite_stream; /// \returns The constructed object writer. MCObjectWriter *createWinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, raw_pwrite_stream &OS); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MCWINCOFFOBJECTWRITER_H diff --git a/include/llvm/MC/MCWinCOFFStreamer.h b/include/llvm/MC/MCWinCOFFStreamer.h index 63e44f2e67d6..84e60b85be6a 100644 --- a/include/llvm/MC/MCWinCOFFStreamer.h +++ b/include/llvm/MC/MCWinCOFFStreamer.h @@ -14,16 +14,15 @@ #include "llvm/MC/MCObjectStreamer.h" namespace llvm { + class MCAsmBackend; class MCContext; class MCCodeEmitter; -class MCExpr; class MCInst; class MCSection; class MCSubtargetInfo; class MCSymbol; class StringRef; -class raw_ostream; class raw_pwrite_stream; class MCWinCOFFStreamer : public MCObjectStreamer { @@ -41,7 +40,7 @@ public: /// \{ void InitSections(bool NoExecStack) override; - void EmitLabel(MCSymbol *Symbol) override; + void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitThumbFunc(MCSymbol *Func) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; @@ -61,7 +60,6 @@ public: unsigned ByteAlignment) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; - void EmitFileDirective(StringRef Filename) override; void EmitIdent(StringRef IdentString) override; void EmitWinEHHandlerData() override; void FinishImpl() override; @@ -70,12 +68,13 @@ public: protected: const MCSymbol *CurSymbol; + void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override; private: void Error(const Twine &Msg) const; }; -} -#endif +} // end namespace llvm +#endif // LLVM_MC_MCWINCOFFSTREAMER_H diff --git a/include/llvm/MC/MachineLocation.h b/include/llvm/MC/MachineLocation.h index 4b5cf4357793..f4fc6ee2fd19 100644 --- a/include/llvm/MC/MachineLocation.h +++ b/include/llvm/MC/MachineLocation.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/MachineLocation.h -------------------------------*- C++ -*-===// +//===- llvm/MC/MachineLocation.h --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,35 +12,31 @@ // explicitly passing an offset to the constructor. //===----------------------------------------------------------------------===// - #ifndef LLVM_MC_MACHINELOCATION_H #define LLVM_MC_MACHINELOCATION_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" +#include <cstdint> namespace llvm { - class MCSymbol; class MachineLocation { private: - bool IsRegister; // True if location is a register. - unsigned Register; // gcc/gdb register number. - int Offset; // Displacement if not register. + bool IsRegister = false; // True if location is a register. + unsigned Register = 0; // gcc/gdb register number. + int Offset = 0; // Displacement if not register. + public: enum : uint32_t { // The target register number for an abstract frame pointer. The value is // an arbitrary value that doesn't collide with any real target register. VirtualFP = ~0U }; - MachineLocation() - : IsRegister(false), Register(0), Offset(0) {} + + MachineLocation() = default; /// Create a direct register location. - explicit MachineLocation(unsigned R) - : IsRegister(true), Register(R), Offset(0) {} + explicit MachineLocation(unsigned R) : IsRegister(true), Register(R) {} /// Create a register-indirect location with an offset. - MachineLocation(unsigned R, int O) - : IsRegister(false), Register(R), Offset(O) {} + MachineLocation(unsigned R, int O) : Register(R), Offset(O) {} bool operator==(const MachineLocation &Other) const { return IsRegister == Other.IsRegister && Register == Other.Register && @@ -56,12 +52,14 @@ public: void setIsRegister(bool Is) { IsRegister = Is; } void setRegister(unsigned R) { Register = R; } void setOffset(int O) { Offset = O; } + /// Make this location a direct register location. void set(unsigned R) { IsRegister = true; Register = R; Offset = 0; } + /// Make this location a register-indirect+offset location. void set(unsigned R, int O) { IsRegister = false; @@ -74,6 +72,6 @@ inline bool operator!=(const MachineLocation &LHS, const MachineLocation &RHS) { return !(LHS == RHS); } -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_MACHINELOCATION_H diff --git a/include/llvm/MC/StringTableBuilder.h b/include/llvm/MC/StringTableBuilder.h index 7da444f7bfb1..0df3fcd63723 100644 --- a/include/llvm/MC/StringTableBuilder.h +++ b/include/llvm/MC/StringTableBuilder.h @@ -1,4 +1,4 @@ -//===-- StringTableBuilder.h - String table building utility ------*- C++ -*-=// +//===- StringTableBuilder.h - String table building utility -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,9 +12,12 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" -#include <cassert> +#include "llvm/ADT/StringRef.h" +#include <cstddef> +#include <cstdint> namespace llvm { + class raw_ostream; /// \brief Utility for building string tables with deduplicated suffixes. @@ -67,6 +70,6 @@ private: bool isFinalized() const { return Finalized; } }; -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_MC_STRINGTABLEBUILDER_H diff --git a/include/llvm/MC/SubtargetFeature.h b/include/llvm/MC/SubtargetFeature.h index ed4abd772821..cb036671b752 100644 --- a/include/llvm/MC/SubtargetFeature.h +++ b/include/llvm/MC/SubtargetFeature.h @@ -1,4 +1,4 @@ -//===-- llvm/MC/SubtargetFeature.h - CPU characteristics --------*- C++ -*-===// +//===- llvm/MC/SubtargetFeature.h - CPU characteristics ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,126 +7,124 @@ // //===----------------------------------------------------------------------===// // -// This file defines and manages user or tool specified CPU characteristics. -// The intent is to be able to package specific features that should or should -// not be used on a specific target processor. A tool, such as llc, could, as -// as example, gather chip info from the command line, a long with features -// that should be used on that chip. +/// \file Defines and manages user or tool specified CPU characteristics. +/// The intent is to be able to package specific features that should or should +/// not be used on a specific target processor. A tool, such as llc, could, as +/// as example, gather chip info from the command line, a long with features +/// that should be used on that chip. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_SUBTARGETFEATURE_H #define LLVM_MC_SUBTARGETFEATURE_H -#include "llvm/ADT/Triple.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/StringRef.h" #include <bitset> +#include <initializer_list> +#include <string> #include <vector> namespace llvm { + template <typename T> class ArrayRef; - class raw_ostream; - class StringRef; +class raw_ostream; +class Triple; -// A container class for subtarget features. -// This is convenient because std::bitset does not have a constructor -// with an initializer list of set bits. -const unsigned MAX_SUBTARGET_FEATURES = 128; +const unsigned MAX_SUBTARGET_FEATURES = 192; +/// Container class for subtarget features. +/// This is convenient because std::bitset does not have a constructor +/// with an initializer list of set bits. class FeatureBitset : public std::bitset<MAX_SUBTARGET_FEATURES> { public: // Cannot inherit constructors because it's not supported by VC++.. - FeatureBitset() : bitset() {} + FeatureBitset() = default; FeatureBitset(const bitset<MAX_SUBTARGET_FEATURES>& B) : bitset(B) {} - FeatureBitset(std::initializer_list<unsigned> Init) : bitset() { + FeatureBitset(std::initializer_list<unsigned> Init) { for (auto I : Init) set(I); } }; //===----------------------------------------------------------------------===// -/// -/// SubtargetFeatureKV - Used to provide key value pairs for feature and -/// CPU bit flags. -// + +/// Used to provide key value pairs for feature and CPU bit flags. struct SubtargetFeatureKV { - const char *Key; // K-V key string - const char *Desc; // Help descriptor - FeatureBitset Value; // K-V integer value - FeatureBitset Implies; // K-V bit mask + const char *Key; ///< K-V key string + const char *Desc; ///< Help descriptor + FeatureBitset Value; ///< K-V integer value + FeatureBitset Implies; ///< K-V bit mask - // Compare routine for std::lower_bound + /// Compare routine for std::lower_bound bool operator<(StringRef S) const { return StringRef(Key) < S; } - // Compare routine for std::is_sorted. + /// Compare routine for std::is_sorted. bool operator<(const SubtargetFeatureKV &Other) const { return StringRef(Key) < StringRef(Other.Key); } }; //===----------------------------------------------------------------------===// -/// -/// SubtargetInfoKV - Used to provide key value pairs for CPU and arbitrary -/// pointers. -// + +/// Used to provide key value pairs for CPU and arbitrary pointers. struct SubtargetInfoKV { - const char *Key; // K-V key string - const void *Value; // K-V pointer value + const char *Key; ///< K-V key string + const void *Value; ///< K-V pointer value - // Compare routine for std::lower_bound + /// Compare routine for std::lower_bound bool operator<(StringRef S) const { return StringRef(Key) < S; } }; //===----------------------------------------------------------------------===// + +/// Manages the enabling and disabling of subtarget specific features. /// -/// SubtargetFeatures - Manages the enabling and disabling of subtarget -/// specific features. Features are encoded as a string of the form +/// Features are encoded as a string of the form /// "+attr1,+attr2,-attr3,...,+attrN" /// A comma separates each feature from the next (all lowercase.) /// Each of the remaining features is prefixed with + or - indicating whether /// that feature should be enabled or disabled contrary to the cpu /// specification. -/// - class SubtargetFeatures { - std::vector<std::string> Features; // Subtarget features as a vector + std::vector<std::string> Features; ///< Subtarget features as a vector + public: explicit SubtargetFeatures(StringRef Initial = ""); - /// Features string accessors. + /// Returns features as a string. std::string getString() const; - /// Adding Features. + /// Adds Features. void AddFeature(StringRef String, bool Enable = true); - /// ToggleFeature - Toggle a feature and update the feature bits. + /// Toggles a feature and update the feature bits. static void ToggleFeature(FeatureBitset &Bits, StringRef String, ArrayRef<SubtargetFeatureKV> FeatureTable); - /// Apply the feature flag and update the feature bits. + /// Applies the feature flag and update the feature bits. static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, ArrayRef<SubtargetFeatureKV> FeatureTable); - /// Get feature bits of a CPU. + /// Returns feature bits of a CPU. FeatureBitset getFeatureBits(StringRef CPU, - ArrayRef<SubtargetFeatureKV> CPUTable, - ArrayRef<SubtargetFeatureKV> FeatureTable); + ArrayRef<SubtargetFeatureKV> CPUTable, + ArrayRef<SubtargetFeatureKV> FeatureTable); - /// Print feature string. + /// Prints feature string. void print(raw_ostream &OS) const; - // Dump feature info. + // Dumps feature info. void dump() const; /// Adds the default features for the specified target triple. void getDefaultSubtargetFeatures(const Triple& Triple); }; -} // End namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_MC_SUBTARGETFEATURE_H diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 08128b0c2515..d423957d9b79 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -212,6 +212,7 @@ public: K_GNU, K_MIPS64, K_BSD, + K_DARWIN, K_DARWIN64, K_COFF }; diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index 00d06e3c7437..bdbe94301dc7 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -14,6 +14,7 @@ #ifndef LLVM_OBJECT_BINARY_H #define LLVM_OBJECT_BINARY_H +#include "llvm/ADT/Triple.h" #include "llvm/Object/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" @@ -133,6 +134,16 @@ public: return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || TypeID == ID_MachO32B || TypeID == ID_MachO64B); } + + Triple::ObjectFormatType getTripleObjectFormat() const { + if (isCOFF()) + return Triple::COFF; + if (isMachO()) + return Triple::MachO; + if (isELF()) + return Triple::ELF; + return Triple::UnknownObjectFormat; + } }; /// @brief Create a Binary from Source, autodetecting the file type. diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index aaa79ae70f01..7a3155b3953e 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -340,7 +340,7 @@ ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) { } template <class ELFT> -static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) { +bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) { return VAddr < Phdr->p_vaddr; } diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 69987d433e2d..9e95f2958aa4 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -26,6 +26,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" @@ -72,6 +73,12 @@ public: static inline bool classof(const Binary *v) { return v->isELF(); } SubtargetFeatures getFeatures() const override; + + SubtargetFeatures getMIPSFeatures() const; + + SubtargetFeatures getARMFeatures() const; + + void setARMSubArch(Triple &TheTriple) const override; }; class ELFSectionRef : public SectionRef { @@ -356,6 +363,28 @@ public: return std::error_code(); } + std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return errorToErrorCode(SectionsOrErr.takeError()); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return errorToErrorCode(ErrorOrContents.takeError()); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return std::error_code(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return std::error_code(); + } + const ELFFile<ELFT> *getELFFile() const { return &EF; } bool isDyldType() const { return isDyldELFObject; } @@ -866,6 +895,8 @@ elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_begin() const { template <class ELFT> elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_end() const { const Elf_Shdr *SymTab = DotDynSymSec; + if (!SymTab) + return dynamic_symbol_begin(); DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); return basic_symbol_iterator(SymbolRef(Sym, this)); } diff --git a/include/llvm/Object/IRSymtab.h b/include/llvm/Object/IRSymtab.h new file mode 100644 index 000000000000..cde6f3b0f651 --- /dev/null +++ b/include/llvm/Object/IRSymtab.h @@ -0,0 +1,302 @@ +//===- IRSymtab.h - data definitions for IR symbol tables -------*- 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 definitions and a reader and builder for a symbol +// table for LLVM IR. Its purpose is to allow linkers and other consumers of +// bitcode files to efficiently read the symbol table for symbol resolution +// purposes without needing to construct a module in memory. +// +// As with most object files the symbol table has two parts: the symbol table +// itself and a string table which is referenced by the symbol table. +// +// A symbol table corresponds to a single bitcode file, which may consist of +// multiple modules, so symbol tables may likewise contain symbols for multiple +// modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_IRSYMTAB_H +#define LLVM_OBJECT_IRSYMTAB_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace irsymtab { +namespace storage { + +// The data structures in this namespace define the low-level serialization +// format. Clients that just want to read a symbol table should use the +// irsymtab::Reader class. + +typedef support::ulittle32_t Word; + +/// A reference to a string in the string table. +struct Str { + Word Offset; + StringRef get(StringRef Strtab) const { + return Strtab.data() + Offset; + } +}; + +/// A reference to a range of objects in the symbol table. +template <typename T> struct Range { + Word Offset, Size; + ArrayRef<T> get(StringRef Symtab) const { + return {reinterpret_cast<const T *>(Symtab.data() + Offset), Size}; + } +}; + +/// Describes the range of a particular module's symbols within the symbol +/// table. +struct Module { + Word Begin, End; +}; + +/// This is equivalent to an IR comdat. +struct Comdat { + Str Name; +}; + +/// Contains the information needed by linkers for symbol resolution, as well as +/// by the LTO implementation itself. +struct Symbol { + /// The mangled symbol name. + Str Name; + + /// The unmangled symbol name, or the empty string if this is not an IR + /// symbol. + Str IRName; + + /// The index into Header::Comdats, or -1 if not a comdat member. + Word ComdatIndex; + + Word Flags; + enum FlagBits { + FB_visibility, // 2 bits + FB_undefined = FB_visibility + 2, + FB_weak, + FB_common, + FB_indirect, + FB_used, + FB_tls, + FB_may_omit, + FB_global, + FB_format_specific, + FB_unnamed_addr, + FB_executable, + }; + + /// The index into the Uncommon table, or -1 if this symbol does not have an + /// Uncommon. + Word UncommonIndex; +}; + +/// This data structure contains rarely used symbol fields and is optionally +/// referenced by a Symbol. +struct Uncommon { + Word CommonSize, CommonAlign; + + /// COFF-specific: the name of the symbol that a weak external resolves to + /// if not defined. + Str COFFWeakExternFallbackName; +}; + +struct Header { + Range<Module> Modules; + Range<Comdat> Comdats; + Range<Symbol> Symbols; + Range<Uncommon> Uncommons; + + Str TargetTriple, SourceFileName; + + /// COFF-specific: linker directives. + Str COFFLinkerOpts; +}; + +} + +/// Fills in Symtab and Strtab with a valid symbol and string table for Mods. +Error build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab, + SmallVector<char, 0> &Strtab); + +/// This represents a symbol that has been read from a storage::Symbol and +/// possibly a storage::Uncommon. +struct Symbol { + // Copied from storage::Symbol. + StringRef Name, IRName; + int ComdatIndex; + uint32_t Flags; + + // Copied from storage::Uncommon. + uint32_t CommonSize, CommonAlign; + StringRef COFFWeakExternFallbackName; + + /// Returns the mangled symbol name. + StringRef getName() const { return Name; } + + /// Returns the unmangled symbol name, or the empty string if this is not an + /// IR symbol. + StringRef getIRName() const { return IRName; } + + /// Returns the index into the comdat table (see Reader::getComdatTable()), or + /// -1 if not a comdat member. + int getComdatIndex() const { return ComdatIndex; } + + using S = storage::Symbol; + GlobalValue::VisibilityTypes getVisibility() const { + return GlobalValue::VisibilityTypes((Flags >> S::FB_visibility) & 3); + } + bool isUndefined() const { return (Flags >> S::FB_undefined) & 1; } + bool isWeak() const { return (Flags >> S::FB_weak) & 1; } + bool isCommon() const { return (Flags >> S::FB_common) & 1; } + bool isIndirect() const { return (Flags >> S::FB_indirect) & 1; } + bool isUsed() const { return (Flags >> S::FB_used) & 1; } + bool isTLS() const { return (Flags >> S::FB_tls) & 1; } + bool canBeOmittedFromSymbolTable() const { + return (Flags >> S::FB_may_omit) & 1; + } + bool isGlobal() const { return (Flags >> S::FB_global) & 1; } + bool isFormatSpecific() const { return (Flags >> S::FB_format_specific) & 1; } + bool isUnnamedAddr() const { return (Flags >> S::FB_unnamed_addr) & 1; } + bool isExecutable() const { return (Flags >> S::FB_executable) & 1; } + + uint64_t getCommonSize() const { + assert(isCommon()); + return CommonSize; + } + uint32_t getCommonAlignment() const { + assert(isCommon()); + return CommonAlign; + } + + /// COFF-specific: for weak externals, returns the name of the symbol that is + /// used as a fallback if the weak external remains undefined. + StringRef getCOFFWeakExternalFallback() const { + assert(isWeak() && isIndirect()); + return COFFWeakExternFallbackName; + } +}; + +/// This class can be used to read a Symtab and Strtab produced by +/// irsymtab::build. +class Reader { + StringRef Symtab, Strtab; + + ArrayRef<storage::Module> Modules; + ArrayRef<storage::Comdat> Comdats; + ArrayRef<storage::Symbol> Symbols; + ArrayRef<storage::Uncommon> Uncommons; + + StringRef str(storage::Str S) const { return S.get(Strtab); } + template <typename T> ArrayRef<T> range(storage::Range<T> R) const { + return R.get(Symtab); + } + const storage::Header &header() const { + return *reinterpret_cast<const storage::Header *>(Symtab.data()); + } + +public: + class SymbolRef; + + Reader() = default; + Reader(StringRef Symtab, StringRef Strtab) : Symtab(Symtab), Strtab(Strtab) { + Modules = range(header().Modules); + Comdats = range(header().Comdats); + Symbols = range(header().Symbols); + Uncommons = range(header().Uncommons); + } + + typedef iterator_range<object::content_iterator<SymbolRef>> symbol_range; + + /// Returns the symbol table for the entire bitcode file. + /// The symbols enumerated by this method are ephemeral, but they can be + /// copied into an irsymtab::Symbol object. + symbol_range symbols() const; + + /// Returns a slice of the symbol table for the I'th module in the file. + /// The symbols enumerated by this method are ephemeral, but they can be + /// copied into an irsymtab::Symbol object. + symbol_range module_symbols(unsigned I) const; + + StringRef getTargetTriple() const { return str(header().TargetTriple); } + + /// Returns the source file path specified at compile time. + StringRef getSourceFileName() const { return str(header().SourceFileName); } + + /// Returns a table with all the comdats used by this file. + std::vector<StringRef> getComdatTable() const { + std::vector<StringRef> ComdatTable; + ComdatTable.reserve(Comdats.size()); + for (auto C : Comdats) + ComdatTable.push_back(str(C.Name)); + return ComdatTable; + } + + /// COFF-specific: returns linker options specified in the input file. + StringRef getCOFFLinkerOpts() const { return str(header().COFFLinkerOpts); } +}; + +/// Ephemeral symbols produced by Reader::symbols() and +/// Reader::module_symbols(). +class Reader::SymbolRef : public Symbol { + const storage::Symbol *SymI, *SymE; + const Reader *R; + +public: + SymbolRef(const storage::Symbol *SymI, const storage::Symbol *SymE, + const Reader *R) + : SymI(SymI), SymE(SymE), R(R) { + read(); + } + + void read() { + if (SymI == SymE) + return; + + Name = R->str(SymI->Name); + IRName = R->str(SymI->IRName); + ComdatIndex = SymI->ComdatIndex; + Flags = SymI->Flags; + + uint32_t UncI = SymI->UncommonIndex; + if (UncI != -1u) { + const storage::Uncommon &Unc = R->Uncommons[UncI]; + CommonSize = Unc.CommonSize; + CommonAlign = Unc.CommonAlign; + COFFWeakExternFallbackName = R->str(Unc.COFFWeakExternFallbackName); + } + } + void moveNext() { + ++SymI; + read(); + } + + bool operator==(const SymbolRef &Other) const { return SymI == Other.SymI; } +}; + +inline Reader::symbol_range Reader::symbols() const { + return {SymbolRef(Symbols.begin(), Symbols.end(), this), + SymbolRef(Symbols.end(), Symbols.end(), this)}; +} + +inline Reader::symbol_range Reader::module_symbols(unsigned I) const { + const storage::Module &M = Modules[I]; + const storage::Symbol *MBegin = Symbols.begin() + M.Begin, + *MEnd = Symbols.begin() + M.End; + return {SymbolRef(MBegin, MEnd, this), SymbolRef(MEnd, MEnd, this)}; +} + +} + +} + +#endif diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 8c33ec8fd603..1ee571cce738 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -100,18 +100,58 @@ private: }; typedef content_iterator<ExportEntry> export_iterator; +// Segment info so SegIndex/SegOffset pairs in a Mach-O Bind or Rebase entry +// can be checked and translated. Only the SegIndex/SegOffset pairs from +// checked entries are to be used with the segmentName(), sectionName() and +// address() methods below. +class BindRebaseSegInfo { +public: + BindRebaseSegInfo(const object::MachOObjectFile *Obj); + + // Used to check a Mach-O Bind or Rebase entry for errors when iterating. + const char *checkSegAndOffset(int32_t SegIndex, uint64_t SegOffset, + bool endInvalid); + const char *checkCountAndSkip(uint32_t Count, uint32_t Skip, + uint8_t PointerSize, int32_t SegIndex, + uint64_t SegOffset); + // Used with valid SegIndex/SegOffset values from checked entries. + StringRef segmentName(int32_t SegIndex); + StringRef sectionName(int32_t SegIndex, uint64_t SegOffset); + uint64_t address(uint32_t SegIndex, uint64_t SegOffset); + +private: + struct SectionInfo { + uint64_t Address; + uint64_t Size; + StringRef SectionName; + StringRef SegmentName; + uint64_t OffsetInSegment; + uint64_t SegmentStartAddress; + int32_t SegmentIndex; + }; + const SectionInfo &findSection(int32_t SegIndex, uint64_t SegOffset); + SmallVector<SectionInfo, 32> Sections; + int32_t MaxSegIndex; +}; + /// MachORebaseEntry encapsulates the current state in the decompression of /// rebasing opcodes. This allows you to iterate through the compressed table of /// rebasing using: -/// for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) { +/// Error Err; +/// for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(&Err)) { /// } +/// if (Err) { report error ... class MachORebaseEntry { public: - MachORebaseEntry(ArrayRef<uint8_t> opcodes, bool is64Bit); + MachORebaseEntry(Error *Err, const MachOObjectFile *O, + ArrayRef<uint8_t> opcodes, bool is64Bit); - uint32_t segmentIndex() const; + int32_t segmentIndex() const; uint64_t segmentOffset() const; StringRef typeName() const; + StringRef segmentName() const; + StringRef sectionName() const; + uint64_t address() const; bool operator==(const MachORebaseEntry &) const; @@ -121,17 +161,18 @@ private: friend class MachOObjectFile; void moveToFirst(); void moveToEnd(); - uint64_t readULEB128(); + uint64_t readULEB128(const char **error); + Error *E; + const MachOObjectFile *O; ArrayRef<uint8_t> Opcodes; const uint8_t *Ptr; uint64_t SegmentOffset; - uint32_t SegmentIndex; + int32_t SegmentIndex; uint64_t RemainingLoopCount; uint64_t AdvanceAmount; uint8_t RebaseType; uint8_t PointerSize; - bool Malformed; bool Done; }; typedef content_iterator<MachORebaseEntry> rebase_iterator; @@ -139,15 +180,18 @@ typedef content_iterator<MachORebaseEntry> rebase_iterator; /// MachOBindEntry encapsulates the current state in the decompression of /// binding opcodes. This allows you to iterate through the compressed table of /// bindings using: -/// for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) { +/// Error Err; +/// for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(&Err)) { /// } +/// if (Err) { report error ... class MachOBindEntry { public: enum class Kind { Regular, Lazy, Weak }; - MachOBindEntry(ArrayRef<uint8_t> Opcodes, bool is64Bit, MachOBindEntry::Kind); + MachOBindEntry(Error *Err, const MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, bool is64Bit, MachOBindEntry::Kind); - uint32_t segmentIndex() const; + int32_t segmentIndex() const; uint64_t segmentOffset() const; StringRef typeName() const; StringRef symbolName() const; @@ -155,6 +199,10 @@ public: int64_t addend() const; int ordinal() const; + StringRef segmentName() const; + StringRef sectionName() const; + uint64_t address() const; + bool operator==(const MachOBindEntry &) const; void moveNext(); @@ -163,14 +211,17 @@ private: friend class MachOObjectFile; void moveToFirst(); void moveToEnd(); - uint64_t readULEB128(); - int64_t readSLEB128(); + uint64_t readULEB128(const char **error); + int64_t readSLEB128(const char **error); + Error *E; + const MachOObjectFile *O; ArrayRef<uint8_t> Opcodes; const uint8_t *Ptr; uint64_t SegmentOffset; - uint32_t SegmentIndex; + int32_t SegmentIndex; StringRef SymbolName; + bool LibraryOrdinalSet; int Ordinal; uint32_t Flags; int64_t Addend; @@ -179,7 +230,6 @@ private: uint8_t BindType; uint8_t PointerSize; Kind TableKind; - bool Malformed; bool Done; }; typedef content_iterator<MachOBindEntry> bind_iterator; @@ -245,6 +295,7 @@ public: // MachO specific. std::error_code getLibraryShortNameByIndex(unsigned Index, StringRef &) const; + uint32_t getLibraryCount() const; section_iterator getRelocationRelocatedSection(relocation_iterator Rel) const; @@ -285,26 +336,79 @@ public: static iterator_range<export_iterator> exports(ArrayRef<uint8_t> Trie); /// For use iterating over all rebase table entries. - iterator_range<rebase_iterator> rebaseTable() const; + iterator_range<rebase_iterator> rebaseTable(Error &Err); - /// For use examining rebase opcodes not in a MachOObjectFile. - static iterator_range<rebase_iterator> rebaseTable(ArrayRef<uint8_t> Opcodes, + /// For use examining rebase opcodes in a MachOObjectFile. + static iterator_range<rebase_iterator> rebaseTable(Error &Err, + MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, bool is64); /// For use iterating over all bind table entries. - iterator_range<bind_iterator> bindTable() const; + iterator_range<bind_iterator> bindTable(Error &Err); /// For use iterating over all lazy bind table entries. - iterator_range<bind_iterator> lazyBindTable() const; + iterator_range<bind_iterator> lazyBindTable(Error &Err); - /// For use iterating over all lazy bind table entries. - iterator_range<bind_iterator> weakBindTable() const; + /// For use iterating over all weak bind table entries. + iterator_range<bind_iterator> weakBindTable(Error &Err); - /// For use examining bind opcodes not in a MachOObjectFile. - static iterator_range<bind_iterator> bindTable(ArrayRef<uint8_t> Opcodes, + /// For use examining bind opcodes in a MachOObjectFile. + static iterator_range<bind_iterator> bindTable(Error &Err, + MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, bool is64, MachOBindEntry::Kind); + /// For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to + /// validate a MachOBindEntry. + const char *BindEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset, + bool endInvalid) const { + return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset, + endInvalid); + } + /// For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for + /// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode. + const char *BindEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip, + uint8_t PointerSize, int32_t SegIndex, + uint64_t SegOffset) const { + return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize, + SegIndex, SegOffset); + } + + /// For use with a SegIndex,SegOffset pair in MachORebaseEntry::moveNext() to + /// validate a MachORebaseEntry. + const char *RebaseEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset, + bool endInvalid) const { + return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset, + endInvalid); + } + /// For use in MachORebaseEntry::moveNext() to validate a MachORebaseEntry for + /// the REBASE_OPCODE_DO_*_TIMES* opcodes. + const char *RebaseEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip, + uint8_t PointerSize, int32_t SegIndex, + uint64_t SegOffset) const { + return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize, + SegIndex, SegOffset); + } + + /// For use with the SegIndex of a checked Mach-O Bind or Rebase entry to + /// get the segment name. + StringRef BindRebaseSegmentName(int32_t SegIndex) const { + return BindRebaseSectionTable->segmentName(SegIndex); + } + + /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or + /// Rebase entry to get the section name. + StringRef BindRebaseSectionName(uint32_t SegIndex, uint64_t SegOffset) const { + return BindRebaseSectionTable->sectionName(SegIndex, SegOffset); + } + + /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or + /// Rebase entry to get the address. + uint64_t BindRebaseAddress(uint32_t SegIndex, uint64_t SegOffset) const { + return BindRebaseSectionTable->address(SegIndex, SegOffset); + } // In a MachO file, sections have a segment name. This is used in the .o // files. They have a single segment, but this field specifies which segment @@ -351,6 +455,12 @@ public: getLinkerOptionLoadCommand(const LoadCommandInfo &L) const; MachO::version_min_command getVersionMinLoadCommand(const LoadCommandInfo &L) const; + MachO::note_command + getNoteLoadCommand(const LoadCommandInfo &L) const; + MachO::build_version_command + getBuildVersionLoadCommand(const LoadCommandInfo &L) const; + MachO::build_tool_version + getBuildToolVersion(unsigned index) const; MachO::dylib_command getDylibIDLoadCommand(const LoadCommandInfo &L) const; MachO::dyld_info_command @@ -444,6 +554,46 @@ public: return VersionOrSDK & 0xff; } + static std::string getBuildPlatform(uint32_t platform) { + switch (platform) { + case MachO::PLATFORM_MACOS: return "macos"; + case MachO::PLATFORM_IOS: return "ios"; + case MachO::PLATFORM_TVOS: return "tvos"; + case MachO::PLATFORM_WATCHOS: return "watchos"; + case MachO::PLATFORM_BRIDGEOS: return "bridgeos"; + default: + std::string ret; + llvm::raw_string_ostream ss(ret); + ss << format_hex(platform, 8, true); + return ss.str(); + } + } + + static std::string getBuildTool(uint32_t tools) { + switch (tools) { + case MachO::TOOL_CLANG: return "clang"; + case MachO::TOOL_SWIFT: return "swift"; + case MachO::TOOL_LD: return "ld"; + default: + std::string ret; + llvm::raw_string_ostream ss(ret); + ss << format_hex(tools, 8, true); + return ss.str(); + } + } + + static std::string getVersionString(uint32_t version) { + uint32_t major = (version >> 16) & 0xffff; + uint32_t minor = (version >> 8) & 0xff; + uint32_t update = version & 0xff; + + SmallString<32> Version; + Version = utostr(major) + "." + utostr(minor); + if (update != 0) + Version += "." + utostr(update); + return Version.str(); + } + private: MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, @@ -462,7 +612,10 @@ private: LibraryList Libraries; LoadCommandList LoadCommands; typedef SmallVector<StringRef, 1> LibraryShortName; + using BuildToolList = SmallVector<const char*, 1>; + BuildToolList BuildTools; mutable LibraryShortName LibrariesShortNames; + std::unique_ptr<BindRebaseSegInfo> BindRebaseSectionTable; const char *SymtabLoadCmd; const char *DysymtabLoadCmd; const char *DataInCodeLoadCmd; diff --git a/include/llvm/Object/ModuleSummaryIndexObjectFile.h b/include/llvm/Object/ModuleSummaryIndexObjectFile.h index 6205927039dc..713022264ea7 100644 --- a/include/llvm/Object/ModuleSummaryIndexObjectFile.h +++ b/include/llvm/Object/ModuleSummaryIndexObjectFile.h @@ -88,9 +88,12 @@ public: } /// Parse the module summary index out of an IR file and return the module -/// summary index object if found, or nullptr if not. +/// summary index object if found, or nullptr if not. If Identifier is +/// non-empty, it is used as the module ID (module path) in the resulting +/// index. This can be used when the index is being read from a file +/// containing minimized bitcode just for the thin link. Expected<std::unique_ptr<ModuleSummaryIndex>> -getModuleSummaryIndexForFile(StringRef Path); +getModuleSummaryIndexForFile(StringRef Path, StringRef Identifier = ""); } #endif diff --git a/include/llvm/Object/ModuleSymbolTable.h b/include/llvm/Object/ModuleSymbolTable.h index 70775352d977..333301d5b456 100644 --- a/include/llvm/Object/ModuleSymbolTable.h +++ b/include/llvm/Object/ModuleSymbolTable.h @@ -26,6 +26,7 @@ namespace llvm { class GlobalValue; +class RecordStreamer; class ModuleSymbolTable { public: @@ -52,7 +53,7 @@ public: /// For each found symbol, call \p AsmSymbol with the name of the symbol found /// and the associated flags. static void CollectAsmSymbols( - const Triple &TheTriple, StringRef InlineAsm, + const Module &M, function_ref<void(StringRef, object::BasicSymbolRef::Flags)> AsmSymbol); }; diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 13d5845c3a71..b689dc2ac03a 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -24,6 +24,8 @@ #include <cstring> namespace llvm { +class ARMAttributeParser; + namespace object { class ObjectFile; @@ -265,6 +267,7 @@ public: virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; + virtual void setARMSubArch(Triple &TheTriple) const { } /// Returns platform-specific object flags, if any. virtual std::error_code getPlatformFlags(unsigned &Result) const { @@ -272,6 +275,11 @@ public: return object_error::invalid_file_type; } + virtual std::error_code + getBuildAttributes(ARMAttributeParser &Attributes) const { + return std::error_code(); + } + /// True if this is a relocatable object (.o/.obj). virtual bool isRelocatableObject() const = 0; diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index 3510d293d73d..3a0a62d9283b 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -155,6 +155,8 @@ private: switch (RelocType) { case llvm::ELF::R_AMDGPU_ABS32: return visitELF_AMDGPU_ABS32(R, Value); + case llvm::ELF::R_AMDGPU_ABS64: + return visitELF_AMDGPU_ABS64(R, Value); default: HasError = true; return RelocToApply(); @@ -450,6 +452,11 @@ private: return RelocToApply(Value + Addend, 4); } + RelocToApply visitELF_AMDGPU_ABS64(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend(R); + return RelocToApply(Value + Addend, 8); + } + /// I386 COFF RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) { return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4); diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index af62e62c51d8..ef0f96f7834a 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 <cinttypes> #include <utility> namespace llvm { @@ -33,7 +34,8 @@ union DataRefImpl { template <typename OStream> OStream& operator<<(OStream &OS, const DataRefImpl &D) { - OS << "(" << format("0x%x8", D.p) << " (" << format("0x%x8", D.d.a) << ", " << format("0x%x8", D.d.b) << "))"; + OS << "(" << format("0x%08" PRIxPTR, D.p) << " (" << format("0x%08x", D.d.a) + << ", " << format("0x%08x", D.d.b) << "))"; return OS; } diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index 2ece6a6c3770..43ad62be68b6 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -17,24 +17,74 @@ #ifndef LLVM_OBJECT_WASM_H #define LLVM_OBJECT_WASM_H +#include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Wasm.h" +#include <cstddef> +#include <cstdint> +#include <vector> namespace llvm { namespace object { +class WasmSymbol { +public: + enum class SymbolType { + FUNCTION_IMPORT, + FUNCTION_EXPORT, + GLOBAL_IMPORT, + GLOBAL_EXPORT, + DEBUG_FUNCTION_NAME, + }; + + WasmSymbol(StringRef Name, SymbolType Type) : Name(Name), Type(Type) {} + + StringRef Name; + SymbolType Type; +}; + +class WasmSection { +public: + WasmSection() : Type(0), Offset(0) {} + + uint32_t Type; // Section type (See below) + uint32_t Offset; // Offset with in the file + StringRef Name; // Section name (User-defined sections only) + ArrayRef<uint8_t> Content; // Section content + std::vector<wasm::WasmRelocation> Relocations; // Relocations for this section +}; + class WasmObjectFile : public ObjectFile { public: WasmObjectFile(MemoryBufferRef Object, Error &Err); + const wasm::WasmObjectHeader &getHeader() const; - const wasm::WasmSection *getWasmSection(const SectionRef &Section) const; + const WasmSymbol &getWasmSymbol(DataRefImpl Symb) const; + const WasmSection &getWasmSection(const SectionRef &Section) const; + const wasm::WasmRelocation &getWasmRelocation(const RelocationRef& Ref) const; + static bool classof(const Binary *v) { return v->isWasm(); } -protected: - void moveSymbolNext(DataRefImpl &Symb) const override; + const std::vector<wasm::WasmSignature>& types() const { return Signatures; } + const std::vector<uint32_t>& functionTypes() const { return FunctionTypes; } + const std::vector<wasm::WasmImport>& imports() const { return Imports; } + const std::vector<wasm::WasmTable>& tables() const { return Tables; } + const std::vector<wasm::WasmLimits>& memories() const { return Memories; } + const std::vector<wasm::WasmGlobal>& globals() const { return Globals; } + const std::vector<wasm::WasmExport>& exports() const { return Exports; } + const std::vector<wasm::WasmElemSegment>& elements() const { + return ElemSegments; + } + const std::vector<wasm::WasmDataSegment>& dataSegments() const { + return DataSegments; + } + const std::vector<wasm::WasmFunction>& functions() const { return Functions; } + const ArrayRef<uint8_t>& code() const { return CodeSection; } + uint32_t startFunction() const { return StartFunction; } - std::error_code printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const override; + void moveSymbolNext(DataRefImpl &Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; @@ -67,7 +117,6 @@ protected: bool isSectionBitcode(DataRefImpl Sec) const override; relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; - section_iterator getRelocatedSection(DataRefImpl Sec) const override; // Overrides from RelocationRef. void moveRelocationNext(DataRefImpl &Rel) const override; @@ -86,14 +135,53 @@ protected: bool isRelocatableObject() const override; private: + const WasmSection &getWasmSection(DataRefImpl Ref) const; + const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; + + WasmSection* findCustomSectionByName(StringRef Name); + WasmSection* findSectionByType(uint32_t Type); + const uint8_t *getPtr(size_t Offset) const; - Error parseUserSection(wasm::WasmSection &Sec, const uint8_t *Ptr, - size_t Length); + Error parseSection(WasmSection &Sec); + Error parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, + const uint8_t *End); + + // Standard section types + Error parseTypeSection(const uint8_t *Ptr, const uint8_t *End); + Error parseImportSection(const uint8_t *Ptr, const uint8_t *End); + Error parseFunctionSection(const uint8_t *Ptr, const uint8_t *End); + Error parseTableSection(const uint8_t *Ptr, const uint8_t *End); + Error parseMemorySection(const uint8_t *Ptr, const uint8_t *End); + Error parseGlobalSection(const uint8_t *Ptr, const uint8_t *End); + Error parseExportSection(const uint8_t *Ptr, const uint8_t *End); + Error parseStartSection(const uint8_t *Ptr, const uint8_t *End); + Error parseElemSection(const uint8_t *Ptr, const uint8_t *End); + Error parseCodeSection(const uint8_t *Ptr, const uint8_t *End); + Error parseDataSection(const uint8_t *Ptr, const uint8_t *End); + + // Custom section types + Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); + Error parseRelocSection(StringRef Name, const uint8_t *Ptr, + const uint8_t *End); wasm::WasmObjectHeader Header; - std::vector<wasm::WasmSection> Sections; + std::vector<WasmSection> Sections; + std::vector<wasm::WasmSignature> Signatures; + std::vector<uint32_t> FunctionTypes; + std::vector<wasm::WasmTable> Tables; + std::vector<wasm::WasmLimits> Memories; + std::vector<wasm::WasmGlobal> Globals; + std::vector<wasm::WasmImport> Imports; + std::vector<wasm::WasmExport> Exports; + std::vector<wasm::WasmElemSegment> ElemSegments; + std::vector<wasm::WasmDataSegment> DataSegments; + std::vector<WasmSymbol> Symbols; + std::vector<wasm::WasmFunction> Functions; + ArrayRef<uint8_t> CodeSection; + uint32_t StartFunction; }; -} -} -#endif +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_WASM_H diff --git a/include/llvm/ObjectYAML/DWARFEmitter.h b/include/llvm/ObjectYAML/DWARFEmitter.h new file mode 100644 index 000000000000..ce231cc0ce68 --- /dev/null +++ b/include/llvm/ObjectYAML/DWARFEmitter.h @@ -0,0 +1,48 @@ +//===--- DWARFEmitter.h - -------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief Common declarations for yaml2obj +//===----------------------------------------------------------------------===// +#ifndef LLVM_OBJECTYAML_DWARFEMITTER_H +#define LLVM_OBJECTYAML_DWARFEMITTER_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include <memory> +#include <vector> + +namespace llvm { +class raw_ostream; + +namespace DWARFYAML { +struct Data; +struct PubSection; + +void EmitDebugAbbrev(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); +void EmitDebugStr(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); + +void EmitDebugAranges(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); +void EmitPubSection(llvm::raw_ostream &OS, + const llvm::DWARFYAML::PubSection &Sect, + bool IsLittleEndian); +void EmitDebugInfo(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); +void EmitDebugLine(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI); + +Expected<StringMap<std::unique_ptr<MemoryBuffer>>> +EmitDebugSections(StringRef YAMLString, + bool IsLittleEndian = sys::IsLittleEndianHost); + +} // namespace DWARFYAML +} // namespace llvm + +#endif diff --git a/include/llvm/ObjectYAML/DWARFYAML.h b/include/llvm/ObjectYAML/DWARFYAML.h index d031b5ac404c..ec34de1f0881 100644 --- a/include/llvm/ObjectYAML/DWARFYAML.h +++ b/include/llvm/ObjectYAML/DWARFYAML.h @@ -13,7 +13,6 @@ /// //===----------------------------------------------------------------------===// - #ifndef LLVM_OBJECTYAML_DWARFYAML_H #define LLVM_OBJECTYAML_DWARFYAML_H @@ -23,9 +22,30 @@ namespace llvm { namespace DWARFYAML { +struct InitialLength { + uint32_t TotalLength; + uint64_t TotalLength64; + + bool isDWARF64() const { return TotalLength == UINT32_MAX; } + + uint64_t getLength() const { + return isDWARF64() ? TotalLength64 : TotalLength; + } + + void setLength(uint64_t Len) { + if (Len >= (uint64_t)UINT32_MAX) { + TotalLength64 = Len; + TotalLength = UINT32_MAX; + } else { + TotalLength = Len; + } + } +}; + struct AttributeAbbrev { llvm::dwarf::Attribute Attribute; llvm::dwarf::Form Form; + llvm::yaml::Hex64 Value; // Some DWARF5 attributes have values }; struct Abbrev { @@ -41,7 +61,7 @@ struct ARangeDescriptor { }; struct ARange { - uint32_t Length; + InitialLength Length; uint16_t Version; uint32_t CuOffset; uint8_t AddrSize; @@ -58,7 +78,7 @@ struct PubEntry { struct PubSection { PubSection() : IsGNUStyle(false) {} - uint32_t Length; + InitialLength Length; uint16_t Version; uint32_t UnitOffset; uint32_t UnitSize; @@ -78,8 +98,9 @@ struct Entry { }; struct Unit { - uint32_t Length; + InitialLength Length; uint16_t Version; + llvm::dwarf::UnitType Type; // Added in DWARF 5 uint32_t AbbrOffset; uint8_t AddrSize; std::vector<Entry> Entries; @@ -104,8 +125,7 @@ struct LineTableOpcode { }; struct LineTable { - uint32_t TotalLength; - uint64_t TotalLength64; + InitialLength Length; uint16_t Version; uint64_t PrologueLength; uint8_t MinInstLength; @@ -130,7 +150,7 @@ struct Data { PubSection GNUPubNames; PubSection GNUPubTypes; - + std::vector<Unit> CompileUnits; std::vector<LineTable> DebugLines; @@ -141,7 +161,7 @@ struct Data { } // namespace llvm::DWARFYAML } // namespace llvm -LLVM_YAML_IS_SEQUENCE_VECTOR(uint8_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint8_t) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8) @@ -203,7 +223,7 @@ template <> struct MappingTraits<DWARFYAML::FormValue> { template <> struct MappingTraits<DWARFYAML::File> { static void mapping(IO &IO, DWARFYAML::File &File); }; - + template <> struct MappingTraits<DWARFYAML::LineTableOpcode> { static void mapping(IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode); }; @@ -212,6 +232,10 @@ template <> struct MappingTraits<DWARFYAML::LineTable> { static void mapping(IO &IO, DWARFYAML::LineTable &LineTable); }; +template <> struct MappingTraits<DWARFYAML::InitialLength> { + static void mapping(IO &IO, DWARFYAML::InitialLength &DWARF); +}; + #define HANDLE_DW_TAG(unused, name) \ io.enumCase(value, "DW_TAG_" #name, dwarf::DW_TAG_##name); @@ -262,6 +286,16 @@ template <> struct ScalarEnumerationTraits<dwarf::Form> { } }; +#define HANDLE_DW_UT(unused, name) \ + io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name); + +template <> struct ScalarEnumerationTraits<dwarf::UnitType> { + static void enumeration(IO &io, dwarf::UnitType &value) { +#include "llvm/Support/Dwarf.def" + io.enumFallback<Hex8>(value); + } +}; + template <> struct ScalarEnumerationTraits<dwarf::Constants> { static void enumeration(IO &io, dwarf::Constants &value) { io.enumCase(value, "DW_CHILDREN_no", dwarf::DW_CHILDREN_no); diff --git a/include/llvm/ObjectYAML/MachOYAML.h b/include/llvm/ObjectYAML/MachOYAML.h index 9ec32d265bca..ae858c8f4aaf 100644 --- a/include/llvm/ObjectYAML/MachOYAML.h +++ b/include/llvm/ObjectYAML/MachOYAML.h @@ -53,6 +53,7 @@ struct LoadCommand { virtual ~LoadCommand(); llvm::MachO::macho_load_command Data; std::vector<Section> Sections; + std::vector<MachO::build_tool_version> Tools; std::vector<llvm::yaml::Hex8> PayloadBytes; std::string PayloadString; uint64_t ZeroPadBytes; @@ -139,13 +140,14 @@ struct UniversalBinary { LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section) -LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t) +LLVM_YAML_IS_FLOW_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::MachOYAML::Object) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachO::build_tool_version) namespace llvm { namespace yaml { @@ -198,6 +200,10 @@ template <> struct MappingTraits<MachOYAML::NListEntry> { static void mapping(IO &IO, MachOYAML::NListEntry &NListEntry); }; +template <> struct MappingTraits<MachO::build_tool_version> { + static void mapping(IO &IO, MachO::build_tool_version &tool); +}; + #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ io.enumCase(value, #LCName, MachO::LCName); diff --git a/include/llvm/ObjectYAML/ObjectYAML.h b/include/llvm/ObjectYAML/ObjectYAML.h index 1d6462347770..36d6ed5417cf 100644 --- a/include/llvm/ObjectYAML/ObjectYAML.h +++ b/include/llvm/ObjectYAML/ObjectYAML.h @@ -10,10 +10,11 @@ #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/ELFYAML.h" #include "llvm/ObjectYAML/MachOYAML.h" +#include "llvm/ObjectYAML/WasmYAML.h" +#include "llvm/Support/YAMLTraits.h" namespace llvm { namespace yaml { @@ -23,6 +24,7 @@ struct YamlObjectFile { std::unique_ptr<COFFYAML::Object> Coff; std::unique_ptr<MachOYAML::Object> MachO; std::unique_ptr<MachOYAML::UniversalBinary> FatMachO; + std::unique_ptr<WasmYAML::Object> Wasm; }; template <> struct MappingTraits<YamlObjectFile> { diff --git a/include/llvm/ObjectYAML/WasmYAML.h b/include/llvm/ObjectYAML/WasmYAML.h new file mode 100644 index 000000000000..b1af8bbdfa6e --- /dev/null +++ b/include/llvm/ObjectYAML/WasmYAML.h @@ -0,0 +1,339 @@ +//===- WasmYAML.h - Wasm 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 wasm binaries. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_WASMYAML_H +#define LLVM_OBJECTYAML_WASMYAML_H + +#include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/Wasm.h" + +namespace llvm { +namespace WasmYAML { + +LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, ValueType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, TableType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, SignatureForm) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportKind) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, Opcode) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, RelocType) + +struct FileHeader { + yaml::Hex32 Version; +}; + +struct Import { + StringRef Module; + StringRef Field; + ExportKind Kind; + union { + uint32_t SigIndex; + ValueType GlobalType; + }; + bool GlobalMutable; +}; + +struct Limits { + yaml::Hex32 Flags; + yaml::Hex32 Initial; + yaml::Hex32 Maximum; +}; + +struct Table { + TableType ElemType; + Limits TableLimits; +}; + +struct Export { + StringRef Name; + ExportKind Kind; + uint32_t Index; +}; + +struct ElemSegment { + uint32_t TableIndex; + wasm::WasmInitExpr Offset; + std::vector<uint32_t> Functions; +}; + +struct Global { + ValueType Type; + bool Mutable; + wasm::WasmInitExpr InitExpr; +}; + +struct LocalDecl { + ValueType Type; + uint32_t Count; +}; + +struct Function { + std::vector<LocalDecl> Locals; + yaml::BinaryRef Body; +}; + +struct Relocation { + RelocType Type; + uint32_t Index; + yaml::Hex32 Offset; + yaml::Hex32 Addend; +}; + +struct DataSegment { + uint32_t Index; + wasm::WasmInitExpr Offset; + yaml::BinaryRef Content; +}; + +struct Signature { + Signature() : Form(wasm::WASM_TYPE_FUNC) {} + + uint32_t Index; + SignatureForm Form; + std::vector<ValueType> ParamTypes; + ValueType ReturnType; +}; + +struct Section { + Section(SectionType SecType) : Type(SecType) {} + virtual ~Section(); + + SectionType Type; + std::vector<Relocation> Relocations; +}; + +struct CustomSection : Section { + CustomSection() : Section(wasm::WASM_SEC_CUSTOM) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_CUSTOM; + } + + StringRef Name; + yaml::BinaryRef Payload; +}; + +struct TypeSection : Section { + TypeSection() : Section(wasm::WASM_SEC_TYPE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_TYPE; + } + + std::vector<Signature> Signatures; +}; + +struct ImportSection : Section { + ImportSection() : Section(wasm::WASM_SEC_IMPORT) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_IMPORT; + } + + std::vector<Import> Imports; +}; + +struct FunctionSection : Section { + FunctionSection() : Section(wasm::WASM_SEC_FUNCTION) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_FUNCTION; + } + + std::vector<uint32_t> FunctionTypes; +}; + +struct TableSection : Section { + TableSection() : Section(wasm::WASM_SEC_TABLE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_TABLE; + } + + std::vector<Table> Tables; +}; + +struct MemorySection : Section { + MemorySection() : Section(wasm::WASM_SEC_MEMORY) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_MEMORY; + } + + std::vector<Limits> Memories; +}; + +struct GlobalSection : Section { + GlobalSection() : Section(wasm::WASM_SEC_GLOBAL) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_GLOBAL; + } + + std::vector<Global> Globals; +}; + +struct ExportSection : Section { + ExportSection() : Section(wasm::WASM_SEC_EXPORT) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_EXPORT; + } + + std::vector<Export> Exports; +}; + +struct StartSection : Section { + StartSection() : Section(wasm::WASM_SEC_START) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_START; + } + + uint32_t StartFunction; +}; + +struct ElemSection : Section { + ElemSection() : Section(wasm::WASM_SEC_ELEM) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_ELEM; + } + + std::vector<ElemSegment> Segments; +}; + +struct CodeSection : Section { + CodeSection() : Section(wasm::WASM_SEC_CODE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_CODE; + } + + std::vector<Function> Functions; +}; + +struct DataSection : Section { + DataSection() : Section(wasm::WASM_SEC_DATA) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_DATA; + } + + std::vector<DataSegment> Segments; +}; + +struct Object { + FileHeader Header; + std::vector<std::unique_ptr<Section>> Sections; +}; + +} // end namespace WasmYAML +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::WasmYAML::Section>) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Signature) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ValueType) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Table) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Import) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Export) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ElemSegment) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Limits) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::DataSegment) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Global) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Function) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::LocalDecl) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<WasmYAML::FileHeader> { + static void mapping(IO &IO, WasmYAML::FileHeader &FileHdr); +}; + +template <> struct MappingTraits<std::unique_ptr<WasmYAML::Section>> { + static void mapping(IO &IO, std::unique_ptr<WasmYAML::Section> &Section); +}; + +template <> struct MappingTraits<WasmYAML::Object> { + static void mapping(IO &IO, WasmYAML::Object &Object); +}; + +template <> struct MappingTraits<WasmYAML::Import> { + static void mapping(IO &IO, WasmYAML::Import &Import); +}; + +template <> struct MappingTraits<WasmYAML::Export> { + static void mapping(IO &IO, WasmYAML::Export &Export); +}; + +template <> struct MappingTraits<WasmYAML::Global> { + static void mapping(IO &IO, WasmYAML::Global &Global); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::SectionType> { + static void enumeration(IO &IO, WasmYAML::SectionType &Type); +}; + +template <> struct MappingTraits<WasmYAML::Signature> { + static void mapping(IO &IO, WasmYAML::Signature &Signature); +}; + +template <> struct MappingTraits<WasmYAML::Table> { + static void mapping(IO &IO, WasmYAML::Table &Table); +}; + +template <> struct MappingTraits<WasmYAML::Limits> { + static void mapping(IO &IO, WasmYAML::Limits &Limits); +}; + +template <> struct MappingTraits<WasmYAML::Function> { + static void mapping(IO &IO, WasmYAML::Function &Function); +}; + +template <> struct MappingTraits<WasmYAML::Relocation> { + static void mapping(IO &IO, WasmYAML::Relocation &Relocation); +}; + +template <> struct MappingTraits<WasmYAML::LocalDecl> { + static void mapping(IO &IO, WasmYAML::LocalDecl &LocalDecl); +}; + +template <> struct MappingTraits<wasm::WasmInitExpr> { + static void mapping(IO &IO, wasm::WasmInitExpr &Expr); +}; + +template <> struct MappingTraits<WasmYAML::DataSegment> { + static void mapping(IO &IO, WasmYAML::DataSegment &Segment); +}; + +template <> struct MappingTraits<WasmYAML::ElemSegment> { + static void mapping(IO &IO, WasmYAML::ElemSegment &Segment); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::ValueType> { + static void enumeration(IO &IO, WasmYAML::ValueType &Type); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::ExportKind> { + static void enumeration(IO &IO, WasmYAML::ExportKind &Kind); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::TableType> { + static void enumeration(IO &IO, WasmYAML::TableType &Type); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::Opcode> { + static void enumeration(IO &IO, WasmYAML::Opcode &Opcode); +}; + +template <> struct ScalarEnumerationTraits<WasmYAML::RelocType> { + static void enumeration(IO &IO, WasmYAML::RelocType &Kind); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif diff --git a/include/llvm/Option/ArgList.h b/include/llvm/Option/ArgList.h index 53cb0d8dec4d..4ed28d7a852b 100644 --- a/include/llvm/Option/ArgList.h +++ b/include/llvm/Option/ArgList.h @@ -10,6 +10,7 @@ #ifndef LLVM_OPTION_ARGLIST_H #define LLVM_OPTION_ARGLIST_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -28,40 +29,57 @@ class ArgList; class Option; /// arg_iterator - Iterates through arguments stored inside an ArgList. +template<typename BaseIter, unsigned NumOptSpecifiers = 0> class arg_iterator { - /// The current argument. - SmallVectorImpl<Arg*>::const_iterator Current; - - /// The argument list we are iterating over. - const ArgList &Args; - - /// Optional filters on the arguments which will be match. Most clients - /// should never want to iterate over arguments without filters, so we won't - /// bother to factor this into two separate iterator implementations. - // - // FIXME: Make efficient; the idea is to provide efficient iteration over - // all arguments which match a particular id and then just provide an - // iterator combinator which takes multiple iterators which can be - // efficiently compared and returns them in order. - OptSpecifier Id0, Id1, Id2; + /// The current argument and the end of the sequence we're iterating. + BaseIter Current, End; + + /// Optional filters on the arguments which will be match. To avoid a + /// zero-sized array, we store one specifier even if we're asked for none. + OptSpecifier Ids[NumOptSpecifiers ? NumOptSpecifiers : 1]; + + void SkipToNextArg() { + for (; Current != End; ++Current) { + // Skip erased elements. + if (!*Current) + continue; + + // Done if there are no filters. + if (!NumOptSpecifiers) + return; + + // Otherwise require a match. + const Option &O = (*Current)->getOption(); + for (auto Id : Ids) { + if (!Id.isValid()) + break; + if (O.matches(Id)) + return; + } + } + } - void SkipToNextArg(); + typedef std::iterator_traits<BaseIter> Traits; public: - typedef Arg * const * value_type; - typedef Arg * const & reference; - typedef Arg * const * pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; - - arg_iterator(SmallVectorImpl<Arg *>::const_iterator it, const ArgList &Args, - OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U, - OptSpecifier Id2 = 0U) - : Current(it), Args(Args), Id0(Id0), Id1(Id1), Id2(Id2) { + typedef typename Traits::value_type value_type; + typedef typename Traits::reference reference; + typedef typename Traits::pointer pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + arg_iterator( + BaseIter Current, BaseIter End, + const OptSpecifier (&Ids)[NumOptSpecifiers ? NumOptSpecifiers : 1] = {}) + : Current(Current), End(End) { + for (unsigned I = 0; I != NumOptSpecifiers; ++I) + this->Ids[I] = Ids[I]; SkipToNextArg(); } + // FIXME: This conversion function makes no sense. operator const Arg*() { return *Current; } + reference operator*() const { return *Current; } pointer operator->() const { return Current; } @@ -94,15 +112,31 @@ public: class ArgList { public: typedef SmallVector<Arg*, 16> arglist_type; - typedef arglist_type::iterator iterator; - typedef arglist_type::const_iterator const_iterator; - typedef arglist_type::reverse_iterator reverse_iterator; - typedef arglist_type::const_reverse_iterator const_reverse_iterator; + typedef arg_iterator<arglist_type::iterator> iterator; + typedef arg_iterator<arglist_type::const_iterator> const_iterator; + typedef arg_iterator<arglist_type::reverse_iterator> reverse_iterator; + typedef arg_iterator<arglist_type::const_reverse_iterator> + const_reverse_iterator; + + template<unsigned N> using filtered_iterator = + arg_iterator<arglist_type::const_iterator, N>; + template<unsigned N> using filtered_reverse_iterator = + arg_iterator<arglist_type::const_reverse_iterator, N>; private: /// The internal list of arguments. arglist_type Args; + typedef std::pair<unsigned, unsigned> OptRange; + static OptRange emptyRange() { return {-1u, 0u}; } + + /// The first and last index of each different OptSpecifier ID. + DenseMap<unsigned, OptRange> OptRanges; + + /// Get the range of indexes in which options with the specified IDs might + /// reside, or (0, 0) if there are no such options. + OptRange getRange(std::initializer_list<OptSpecifier> Ids) const; + protected: // Make the default special members protected so they won't be used to slice // derived objects, but can still be used by derived objects to implement @@ -113,24 +147,32 @@ protected: // InputArgList which deletes the contents of the container. If we could fix // up the ownership here (delegate storage/ownership to the derived class so // it can be a container of unique_ptr) this would be simpler. - ArgList(ArgList &&RHS) : Args(std::move(RHS.Args)) { RHS.Args.clear(); } + ArgList(ArgList &&RHS) + : Args(std::move(RHS.Args)), OptRanges(std::move(RHS.OptRanges)) { + RHS.Args.clear(); + RHS.OptRanges.clear(); + } ArgList &operator=(ArgList &&RHS) { Args = std::move(RHS.Args); RHS.Args.clear(); + OptRanges = std::move(RHS.OptRanges); + RHS.OptRanges.clear(); return *this; } // Protect the dtor to ensure this type is never destroyed polymorphically. ~ArgList() = default; -public: + // Implicitly convert a value to an OptSpecifier. Used to work around a bug + // in MSVC's implementation of narrowing conversion checking. + static OptSpecifier toOptSpecifier(OptSpecifier S) { return S; } +public: /// @name Arg Access /// @{ /// append - Append \p A to the arg list. void append(Arg *A); - arglist_type &getArgs() { return Args; } const arglist_type &getArgs() const { return Args; } unsigned size() const { return Args.size(); } @@ -139,30 +181,38 @@ public: /// @name Arg Iteration /// @{ - iterator begin() { return Args.begin(); } - iterator end() { return Args.end(); } + iterator begin() { return {Args.begin(), Args.end()}; } + iterator end() { return {Args.end(), Args.end()}; } - reverse_iterator rbegin() { return Args.rbegin(); } - reverse_iterator rend() { return Args.rend(); } + reverse_iterator rbegin() { return {Args.rbegin(), Args.rend()}; } + reverse_iterator rend() { return {Args.rend(), Args.rend()}; } - const_iterator begin() const { return Args.begin(); } - const_iterator end() const { return Args.end(); } + const_iterator begin() const { return {Args.begin(), Args.end()}; } + const_iterator end() const { return {Args.end(), Args.end()}; } - const_reverse_iterator rbegin() const { return Args.rbegin(); } - const_reverse_iterator rend() const { return Args.rend(); } + const_reverse_iterator rbegin() const { return {Args.rbegin(), Args.rend()}; } + const_reverse_iterator rend() const { return {Args.rend(), Args.rend()}; } - arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U, - OptSpecifier Id2 = 0U) const { - return arg_iterator(Args.begin(), *this, Id0, Id1, Id2); - } - arg_iterator filtered_end() const { - return arg_iterator(Args.end(), *this); + template<typename ...OptSpecifiers> + iterator_range<filtered_iterator<sizeof...(OptSpecifiers)>> + filtered(OptSpecifiers ...Ids) const { + OptRange Range = getRange({toOptSpecifier(Ids)...}); + auto B = Args.begin() + Range.first; + auto E = Args.begin() + Range.second; + using Iterator = filtered_iterator<sizeof...(OptSpecifiers)>; + return make_range(Iterator(B, E, {toOptSpecifier(Ids)...}), + Iterator(E, E, {toOptSpecifier(Ids)...})); } - iterator_range<arg_iterator> filtered(OptSpecifier Id0 = 0U, - OptSpecifier Id1 = 0U, - OptSpecifier Id2 = 0U) const { - return make_range(filtered_begin(Id0, Id1, Id2), filtered_end()); + template<typename ...OptSpecifiers> + iterator_range<filtered_reverse_iterator<sizeof...(OptSpecifiers)>> + filtered_reverse(OptSpecifiers ...Ids) const { + OptRange Range = getRange({toOptSpecifier(Ids)...}); + auto B = Args.rend() - Range.second; + auto E = Args.rend() - Range.first; + using Iterator = filtered_reverse_iterator<sizeof...(OptSpecifiers)>; + return make_range(Iterator(B, E, {toOptSpecifier(Ids)...}), + Iterator(E, E, {toOptSpecifier(Ids)...})); } /// @} @@ -179,43 +229,34 @@ public: /// hasArg - Does the arg list contain any option matching \p Id. /// /// \p Claim Whether the argument should be claimed, if it exists. - bool hasArgNoClaim(OptSpecifier Id) const { - return getLastArgNoClaim(Id) != nullptr; - } - bool hasArg(OptSpecifier Id) const { - return getLastArg(Id) != nullptr; + template<typename ...OptSpecifiers> + bool hasArgNoClaim(OptSpecifiers ...Ids) const { + return getLastArgNoClaim(Ids...) != nullptr; } - bool hasArg(OptSpecifier Id0, OptSpecifier Id1) const { - return getLastArg(Id0, Id1) != nullptr; + template<typename ...OptSpecifiers> + bool hasArg(OptSpecifiers ...Ids) const { + return getLastArg(Ids...) != nullptr; } - bool hasArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { - return getLastArg(Id0, Id1, Id2) != nullptr; + + /// Return the last argument matching \p Id, or null. + template<typename ...OptSpecifiers> + Arg *getLastArg(OptSpecifiers ...Ids) const { + Arg *Res = nullptr; + for (Arg *A : filtered(Ids...)) { + Res = A; + Res->claim(); + } + return Res; } - /// getLastArg - Return the last argument matching \p Id, or null. - /// - /// \p Claim Whether the argument should be claimed, if it exists. - Arg *getLastArgNoClaim(OptSpecifier Id) const; - Arg *getLastArgNoClaim(OptSpecifier Id0, OptSpecifier Id1) const; - Arg *getLastArgNoClaim(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2) const; - Arg *getLastArgNoClaim(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3) const; - Arg *getLastArg(OptSpecifier Id) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3, OptSpecifier Id4) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5, - OptSpecifier Id6) const; - Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, - OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5, - OptSpecifier Id6, OptSpecifier Id7) const; + /// Return the last argument matching \p Id, or null. Do not "claim" the + /// option (don't mark it as having been used). + template<typename ...OptSpecifiers> + Arg *getLastArgNoClaim(OptSpecifiers ...Ids) const { + for (Arg *A : filtered_reverse(Ids...)) + return A; + return nullptr; + } /// getArgString - Return the input argument string at \p Index. virtual const char *getArgString(unsigned Index) const = 0; @@ -230,8 +271,7 @@ public: /// @{ /// getLastArgValue - Return the value of the last argument, or a default. - StringRef getLastArgValue(OptSpecifier Id, - StringRef Default = "") const; + StringRef getLastArgValue(OptSpecifier Id, StringRef Default = "") const; /// getAllArgValues - Get the values of all instances of the given argument /// as strings. @@ -273,7 +313,7 @@ public: /// AddAllArgValues - Render the argument values of all arguments /// matching the given ids. void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; /// AddAllArgsTranslated - Render all the arguments matching the /// given ids, but forced to separate args and using the provided diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index e77a0b9882b2..852d79fbd443 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -41,7 +41,7 @@ class TargetMachine; Registry.registerPass(*PI, true); \ return PI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + static llvm::once_flag Initialize##passName##PassFlag; \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ llvm::call_once(Initialize##passName##PassFlag, \ initialize##passName##PassOnce, std::ref(Registry)); \ @@ -61,7 +61,7 @@ class TargetMachine; Registry.registerPass(*PI, true); \ return PI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + static llvm::once_flag Initialize##passName##PassFlag; \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ llvm::call_once(Initialize##passName##PassFlag, \ initialize##passName##PassOnce, std::ref(Registry)); \ @@ -152,7 +152,7 @@ struct RegisterAnalysisGroup : public RegisterAGBase { Registry.registerAnalysisGroup(&agName::ID, 0, *AI, false, true); \ return AI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##agName##AnalysisGroupFlag); \ + static llvm::once_flag Initialize##agName##AnalysisGroupFlag; \ void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ llvm::call_once(Initialize##agName##AnalysisGroupFlag, \ initialize##agName##AnalysisGroupOnce, \ @@ -173,7 +173,7 @@ struct RegisterAnalysisGroup : public RegisterAGBase { true); \ return AI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + static llvm::once_flag Initialize##passName##PassFlag; \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ llvm::call_once(Initialize##passName##PassFlag, \ initialize##passName##PassOnce, std::ref(Registry)); \ @@ -194,7 +194,7 @@ struct RegisterAnalysisGroup : public RegisterAGBase { Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, true); \ return AI; \ } \ - LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + static llvm::once_flag Initialize##passName##PassFlag; \ void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ llvm::call_once(Initialize##passName##PassFlag, \ initialize##passName##PassOnce, std::ref(Registry)); \ diff --git a/include/llvm/Passes/PassBuilder.h b/include/llvm/Passes/PassBuilder.h index d76c13984d11..efa36d957fbd 100644 --- a/include/llvm/Passes/PassBuilder.h +++ b/include/llvm/Passes/PassBuilder.h @@ -27,6 +27,14 @@ class StringRef; class AAManager; class TargetMachine; +/// A struct capturing PGO tunables. +struct PGOOptions { + std::string ProfileGenFile = ""; + std::string ProfileUseFile = ""; + bool RunProfileGen = false; + bool SamplePGO = false; +}; + /// \brief This class provides access to building LLVM's passes. /// /// It's members provide the baseline state available to passes during their @@ -35,6 +43,7 @@ class TargetMachine; /// construction. class PassBuilder { TargetMachine *TM; + Optional<PGOOptions> PGOOpt; public: /// \brief LLVM-provided high-level optimization levels. @@ -123,7 +132,9 @@ public: Oz }; - explicit PassBuilder(TargetMachine *TM = nullptr) : TM(TM) {} + explicit PassBuilder(TargetMachine *TM = nullptr, + Optional<PGOOptions> PGOOpt = None) + : TM(TM), PGOOpt(PGOOpt) {} /// \brief Cross register the analysis managers through their proxies. /// diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index d6051ffb3f8d..b9a9f5377698 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -1,4 +1,4 @@ -//=-- CoverageMapping.h - Code coverage mapping support ---------*- C++ -*-=// +//===- CoverageMapping.h - Code coverage mapping support --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,25 +12,42 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_H_ -#define LLVM_PROFILEDATA_COVERAGEMAPPING_H_ +#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H +#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdint> +#include <iterator> +#include <memory> +#include <string> #include <system_error> #include <tuple> +#include <utility> +#include <vector> namespace llvm { + +class IndexedInstrProfReader; + namespace coverage { +class CoverageMappingReader; +struct CoverageMappingRecord; + enum class coveragemap_error { success = 0, eof, @@ -68,19 +85,6 @@ private: coveragemap_error Err; }; -} // end of coverage namespace. -} // end of llvm namespace - -namespace llvm { -class IndexedInstrProfReader; -namespace coverage { - -class CoverageMappingReader; -struct CoverageMappingRecord; - -class CoverageMapping; -struct CounterExpressions; - /// \brief A Counter is an abstract value that describes how to compute the /// execution count for a region of code using the collected profile count data. struct Counter { @@ -91,13 +95,13 @@ struct Counter { EncodingTagBits + 1; private: - CounterKind Kind; - unsigned ID; + CounterKind Kind = Zero; + unsigned ID = 0; Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {} public: - Counter() : Kind(Zero), ID(0) {} + Counter() = default; CounterKind getKind() const { return Kind; } @@ -153,8 +157,9 @@ struct CounterExpression { class CounterExpressionBuilder { /// \brief A list of all the counter expressions std::vector<CounterExpression> Expressions; + /// \brief A lookup table for the index of a given expression. - llvm::DenseMap<CounterExpression, unsigned> ExpressionIndices; + DenseMap<CounterExpression, unsigned> ExpressionIndices; /// \brief Return the counter which corresponds to the given expression. /// @@ -238,7 +243,6 @@ struct CounterMappingRegion { LineEnd, ColumnEnd, SkippedRegion); } - inline std::pair<unsigned, unsigned> startLoc() const { return std::pair<unsigned, unsigned>(LineStart, ColumnStart); } @@ -269,7 +273,7 @@ public: void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; } - void dump(const Counter &C, llvm::raw_ostream &OS) const; + void dump(const Counter &C, raw_ostream &OS) const; void dump(const Counter &C) const { dump(C, dbgs()); } /// \brief Return the number of times that a region of code associated with @@ -390,13 +394,14 @@ struct CoverageSegment { /// provides a sequence of CoverageSegments to iterate through, as well as the /// list of expansions that can be further processed. class CoverageData { + friend class CoverageMapping; + std::string Filename; std::vector<CoverageSegment> Segments; std::vector<ExpansionRecord> Expansions; - friend class CoverageMapping; public: - CoverageData() {} + CoverageData() = default; CoverageData(StringRef Filename) : Filename(Filename) {} @@ -422,18 +427,17 @@ public: class CoverageMapping { StringSet<> FunctionNames; std::vector<FunctionRecord> Functions; - unsigned MismatchedFunctionCount; - - CoverageMapping() : MismatchedFunctionCount(0) {} - - CoverageMapping(const CoverageMapping &) = delete; - const CoverageMapping &operator=(const CoverageMapping &) = delete; + unsigned MismatchedFunctionCount = 0; + CoverageMapping() = default; /// \brief Add a function record corresponding to \p Record. Error loadFunctionRecord(const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader); public: + CoverageMapping(const CoverageMapping &) = delete; + CoverageMapping &operator=(const CoverageMapping &) = delete; + /// \brief Load the coverage mapping using the given readers. static Expected<std::unique_ptr<CoverageMapping>> load(CoverageMappingReader &CoverageReader, @@ -517,14 +521,17 @@ template <class IntPtrT> struct CovMapFunctionRecordV1 { 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> IntPtrT getFuncNameRef() const { return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); } + // Return the PGO name of the function */ template <support::endianness Endian> Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { @@ -545,14 +552,17 @@ struct CovMapFunctionRecord { 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 { @@ -570,12 +580,15 @@ struct CovMapHeader { template <support::endianness Endian> uint32_t getNRecords() const { return support::endian::byte_swap<uint32_t, Endian>(NRecords); } + template <support::endianness Endian> uint32_t getFilenamesSize() const { return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); } + template <support::endianness Endian> uint32_t getCoverageSize() const { return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); } + template <support::endianness Endian> uint32_t getVersion() const { return support::endian::byte_swap<uint32_t, Endian>(Version); } @@ -635,4 +648,4 @@ template<> struct DenseMapInfo<coverage::CounterExpression> { } // end namespace llvm -#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_ +#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index db907f128d93..5b372252a9ac 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -1,4 +1,4 @@ -//=-- CoverageMappingReader.h - Code coverage mapping reader ------*- C++ -*-=// +//===- CoverageMappingReader.h - Code coverage mapping reader ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,18 +12,20 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H -#define LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H +#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H +#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/InstrProf.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" +#include <cstddef> +#include <cstdint> #include <iterator> +#include <memory> +#include <vector> namespace llvm { namespace coverage { @@ -42,13 +44,14 @@ struct CoverageMappingRecord { /// \brief A file format agnostic iterator over coverage mapping data. class CoverageMappingIterator : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> { - CoverageMappingReader *Reader; + CoverageMappingReader *Reader = nullptr; CoverageMappingRecord Record; void increment(); public: - CoverageMappingIterator() : Reader(nullptr) {} + CoverageMappingIterator() = default; + CoverageMappingIterator(CoverageMappingReader *Reader) : Reader(Reader) { increment(); } @@ -69,10 +72,11 @@ public: class CoverageMappingReader { public: + virtual ~CoverageMappingReader() = default; + virtual Error readNextRecord(CoverageMappingRecord &Record) = 0; CoverageMappingIterator begin() { return CoverageMappingIterator(this); } CoverageMappingIterator end() { return CoverageMappingIterator(); } - virtual ~CoverageMappingReader() {} }; /// \brief Base class for the raw coverage mapping and filenames data readers. @@ -92,13 +96,12 @@ protected: class RawCoverageFilenamesReader : public RawCoverageReader { std::vector<StringRef> &Filenames; - RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete; - RawCoverageFilenamesReader & - operator=(const RawCoverageFilenamesReader &) = delete; - public: RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames) : RawCoverageReader(Data), Filenames(Filenames) {} + RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete; + RawCoverageFilenamesReader & + operator=(const RawCoverageFilenamesReader &) = delete; Error read(); }; @@ -120,10 +123,6 @@ class RawCoverageMappingReader : public RawCoverageReader { std::vector<CounterExpression> &Expressions; std::vector<CounterMappingRegion> &MappingRegions; - RawCoverageMappingReader(const RawCoverageMappingReader &) = delete; - RawCoverageMappingReader & - operator=(const RawCoverageMappingReader &) = delete; - public: RawCoverageMappingReader(StringRef MappingData, ArrayRef<StringRef> TranslationUnitFilenames, @@ -134,6 +133,9 @@ public: TranslationUnitFilenames(TranslationUnitFilenames), Filenames(Filenames), Expressions(Expressions), MappingRegions(MappingRegions) {} + RawCoverageMappingReader(const RawCoverageMappingReader &) = delete; + RawCoverageMappingReader & + operator=(const RawCoverageMappingReader &) = delete; Error read(); @@ -169,17 +171,17 @@ private: std::vector<StringRef> Filenames; std::vector<ProfileMappingRecord> MappingRecords; InstrProfSymtab ProfileNames; - size_t CurrentRecord; + size_t CurrentRecord = 0; std::vector<StringRef> FunctionsFilenames; std::vector<CounterExpression> Expressions; std::vector<CounterMappingRegion> MappingRegions; + BinaryCoverageReader() = default; + +public: BinaryCoverageReader(const BinaryCoverageReader &) = delete; BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete; - BinaryCoverageReader() : CurrentRecord(0) {} - -public: static Expected<std::unique_ptr<BinaryCoverageReader>> create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, StringRef Arch); @@ -190,4 +192,4 @@ public: } // end namespace coverage } // end namespace llvm -#endif +#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h index 24fb94647247..b6f864ab3de3 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -1,4 +1,4 @@ -//=-- CoverageMappingWriter.h - Code coverage mapping writer ------*- C++ -*-=// +//===- CoverageMappingWriter.h - Code coverage mapping writer ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,15 +12,17 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H -#define LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H +#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H +#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" -#include "llvm/Support/raw_ostream.h" namespace llvm { + +class raw_ostream; + namespace coverage { /// \brief Writer of the filenames section for the instrumentation @@ -54,6 +56,7 @@ public: }; } // end namespace coverage + } // end namespace llvm -#endif +#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index c7e558efa3dc..c9828858cce3 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 // @@ -16,62 +16,57 @@ #ifndef LLVM_PROFILEDATA_INSTRPROF_H #define LLVM_PROFILEDATA_INSTRPROF_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" #include "llvm/IR/GlobalValue.h" -#include "llvm/IR/Metadata.h" +#include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/InstrProfData.inc" -#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> #include <cstdint> +#include <cstring> #include <list> +#include <memory> +#include <string> #include <system_error> +#include <utility> #include <vector> namespace llvm { class Function; class GlobalVariable; +struct InstrProfRecord; +class InstrProfSymtab; +class Instruction; +class MDNode; class Module; -/// Return the name of data section containing profile counter variables. -inline StringRef getInstrProfCountersSectionName(bool AddSegment) { - return AddSegment ? "__DATA," INSTR_PROF_CNTS_SECT_NAME_STR - : INSTR_PROF_CNTS_SECT_NAME_STR; -} - -/// Return the name of data section containing names of instrumented -/// functions. -inline StringRef getInstrProfNameSectionName(bool AddSegment) { - return AddSegment ? "__DATA," INSTR_PROF_NAME_SECT_NAME_STR - : INSTR_PROF_NAME_SECT_NAME_STR; -} - -/// Return the name of the data section containing per-function control -/// data. -inline StringRef getInstrProfDataSectionName(bool AddSegment) { - return AddSegment ? "__DATA," INSTR_PROF_DATA_SECT_NAME_STR - ",regular,live_support" - : 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; -} +enum InstrProfSectKind { +#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Kind, +#include "llvm/ProfileData/InstrProfData.inc" +}; -/// 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 of the profile section corresponding to \p IPSK. +/// +/// The name of the section depends on the object format type \p OF. If +/// \p AddSegmentInfo is true, a segment prefix and additional linker hints may +/// be added to the section name (this is the default). +std::string getInstrProfSectionName(InstrProfSectKind IPSK, + Triple::ObjectFormatType OF, + bool AddSegmentInfo = true); /// Return the name profile runtime entry point to do value profiling /// for a given site. @@ -79,12 +74,18 @@ inline StringRef getInstrProfValueProfFuncName() { return INSTR_PROF_VALUE_PROF_FUNC_STR; } +/// Return the name profile runtime entry point to do value range profiling. +inline StringRef getInstrProfValueRangeProfFuncName() { + return INSTR_PROF_VALUE_RANGE_PROF_FUNC_STR; +} + /// Return the name of the section containing function coverage mapping /// data. -inline StringRef getInstrProfCoverageSectionName(bool AddSegment) { - return AddSegment ? "__LLVM_COV," INSTR_PROF_COVMAP_SECT_NAME_STR - : INSTR_PROF_COVMAP_SECT_NAME_STR; -} +std::string getInstrProfCoverageSectionName(const Module *M = nullptr); +/// Similar to the above, but used by host tool (e.g, coverage) which has +/// object format information. The section name returned is not prefixed +/// with segment name. +std::string getInstrProfCoverageSectionNameInObject(bool isCoff); /// Return the name prefix of variables containing instrumented function names. inline StringRef getInstrProfNameVarPrefix() { return "__profn_"; } @@ -201,6 +202,7 @@ GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName); GlobalVariable *createPGOFuncNameVar(Module &M, GlobalValue::LinkageTypes Linkage, StringRef PGOFuncName); + /// Return the initializer in string of the PGO name var \c NameVar. StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar); @@ -220,11 +222,12 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, /// second field will have value zero. 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. 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 separated by 0 or more zero /// bytes. This method decodes the string and populates the \c Symtab. @@ -244,8 +247,6 @@ enum InstrProfValueKind : uint32_t { #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. @@ -253,6 +254,7 @@ 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, @@ -347,25 +349,22 @@ class SoftInstrProfErrors { /// the first such error for reporting purposes. /// The first soft error encountered. - instrprof_error FirstError; + instrprof_error FirstError = instrprof_error::success; /// The number of hash mismatches. - unsigned NumHashMismatches; + unsigned NumHashMismatches = 0; /// The number of count mismatches. - unsigned NumCountMismatches; + unsigned NumCountMismatches = 0; /// The number of counter overflows. - unsigned NumCounterOverflows; + unsigned NumCounterOverflows = 0; /// The number of value site count mismatches. - unsigned NumValueSiteCountMismatches; + unsigned NumValueSiteCountMismatches = 0; public: - SoftInstrProfErrors() - : FirstError(instrprof_error::success), NumHashMismatches(0), - NumCountMismatches(0), NumCounterOverflows(0), - NumValueSiteCountMismatches(0) {} + SoftInstrProfErrors() = default; ~SoftInstrProfErrors() { assert(FirstError == instrprof_error::success && @@ -401,12 +400,16 @@ public: }; namespace object { + class SectionRef; -} + +} // end namespace object namespace IndexedInstrProf { + uint64_t ComputeHash(StringRef K); -} + +} // end namespace IndexedInstrProf /// A symbol table used for function PGO name look-up with keys /// (such as pointers, md5hash values) to the function. A function's @@ -419,7 +422,7 @@ public: private: StringRef Data; - uint64_t Address; + uint64_t Address = 0; // Unique name strings. StringSet<> NameTab; // A map from MD5 keys to function name strings. @@ -432,9 +435,7 @@ private: AddrHashMap AddrToMD5Map; public: - InstrProfSymtab() - : Data(), Address(0), NameTab(), MD5NameMap(), MD5FuncMap(), - AddrToMD5Map() {} + InstrProfSymtab() = default; /// Create InstrProfSymtab from an object file section which /// contains function PGO names. When section may contain raw @@ -443,26 +444,32 @@ public: /// 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 Error create(StringRef D, uint64_t BaseAddr); + /// \c NameStrings is a string composed of one of more sub-strings /// 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); + // If the symtab is created by a series of calls to \c addFuncName, \c // finalizeSymtab needs to be called before looking up function names. // This is required because the underlying map is a vector (for space // efficiency) which needs to be sorted. inline void finalizeSymtab(); + /// 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) { @@ -471,25 +478,32 @@ public: 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. void mapAddress(uint64_t Addr, uint64_t MD5Val) { AddrToMD5Map.push_back(std::make_pair(Addr, MD5Val)); } + AddrHashMap &getAddrHashMap() { return AddrToMD5Map; } + /// Return function's PGO name from the function name's symbol /// address in the object file. If an error occurs, return /// an empty string. StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize); + /// 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; } }; @@ -579,40 +593,48 @@ struct InstrProfValueSiteRecord { /// Profiling information for a single function. struct InstrProfRecord { - InstrProfRecord() : SIPE() {} - InstrProfRecord(StringRef Name, uint64_t Hash, std::vector<uint64_t> Counts) - : Name(Name), Hash(Hash), Counts(std::move(Counts)), SIPE() {} StringRef Name; uint64_t Hash; std::vector<uint64_t> Counts; SoftInstrProfErrors SIPE; + InstrProfRecord() = default; + InstrProfRecord(StringRef Name, uint64_t Hash, std::vector<uint64_t> Counts) + : Name(Name), Hash(Hash), Counts(std::move(Counts)) {} + typedef std::vector<std::pair<uint64_t, uint64_t>> ValueMapType; /// Return the number of value profile kinds with non-zero number /// of profile sites. inline uint32_t getNumValueKinds() const; + /// Return the number of instrumented sites for ValueKind. inline uint32_t getNumValueSites(uint32_t ValueKind) const; + /// Return the total number of ValueData for ValueKind. inline uint32_t getNumValueData(uint32_t ValueKind) const; + /// Return the number of value data collected for ValueKind at profiling /// site: Site. inline uint32_t getNumValueDataForSite(uint32_t ValueKind, uint32_t Site) const; + /// 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 *TotalC = 0) const; + uint64_t *TotalC = nullptr) 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. void addValueData(uint32_t ValueKind, uint32_t Site, InstrProfValueData *VData, uint32_t N, @@ -635,6 +657,13 @@ struct InstrProfRecord { SR.sortByCount(); } } + + /// Clear value data entries and edge counters. + void Clear() { + Counts.clear(); + clearValueData(); + } + /// Clear value data entries void clearValueData() { for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) @@ -646,11 +675,15 @@ struct InstrProfRecord { private: std::vector<InstrProfValueSiteRecord> IndirectCallSites; + std::vector<InstrProfValueSiteRecord> MemOPSizes; const std::vector<InstrProfValueSiteRecord> & + getValueSitesForKind(uint32_t ValueKind) const { switch (ValueKind) { case IPVK_IndirectCallTarget: return IndirectCallSites; + case IPVK_MemOPSize: + return MemOPSizes; default: llvm_unreachable("Unknown value kind!"); } @@ -672,6 +705,7 @@ private: // Scale merged value counts by \p Weight. void mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src, uint64_t Weight); + // Scale up value profile data count. void scaleValueProfData(uint32_t ValueKind, uint64_t Weight); }; @@ -706,7 +740,7 @@ 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); + uint64_t &TotalCount = (TotalC == nullptr ? Dummy : *TotalC); uint32_t N = getNumValueDataForSite(ValueKind, Site); if (N == 0) { TotalCount = 0; @@ -762,7 +796,6 @@ namespace IndexedInstrProf { enum class HashT : uint32_t { MD5, - Last = MD5 }; @@ -816,7 +849,6 @@ struct Header { // 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 @@ -857,13 +889,16 @@ struct Summary { 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]); } @@ -877,6 +912,7 @@ struct Summary { } 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; @@ -894,6 +930,7 @@ 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 { @@ -937,6 +974,10 @@ struct Header { } // end namespace RawInstrProf +// Parse MemOP Size range option. +void getMemOPSizeRangeFromOption(std::string Str, int64_t &RangeStart, + int64_t &RangeLast); + } // end namespace llvm #endif // LLVM_PROFILEDATA_INSTRPROF_H diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc index f7c22d10763c..be0dd4ad04bf 100644 --- a/include/llvm/ProfileData/InstrProfData.inc +++ b/include/llvm/ProfileData/InstrProfData.inc @@ -153,7 +153,17 @@ INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \ INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA +#ifndef VALUE_RANGE_PROF VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) +#else /* VALUE_RANGE_PROF */ +VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeStart, Type::getInt64Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeLast, Type::getInt64Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, LargeValue, Type::getInt64Ty(Ctx)) +#endif /*VALUE_RANGE_PROF */ #undef VALUE_PROF_FUNC_PARAM #undef INSTR_PROF_COMMA /* VALUE_PROF_FUNC_PARAM end */ @@ -174,13 +184,15 @@ VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) * name hash and the function address. */ VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) +/* For memory intrinsic functions size profiling. */ +VALUE_PROF_KIND(IPVK_MemOPSize, 1) /* These two kinds must be the last to be * declared. This is to make sure the string * array created with the template can be * indexed with the kind value. */ VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget) -VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) +VALUE_PROF_KIND(IPVK_Last, IPVK_MemOPSize) #undef VALUE_PROF_KIND /* VALUE_PROF_KIND end */ @@ -234,6 +246,31 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \ /* COVMAP_HEADER end. */ +#ifdef INSTR_PROF_SECT_ENTRY +#define INSTR_PROF_DATA_DEFINED +INSTR_PROF_SECT_ENTRY(IPSK_data, \ + INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_cnts, \ + INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_name, \ + INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_vals, \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_covmap, \ + INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,") + +#undef INSTR_PROF_SECT_ENTRY +#endif + + #ifdef INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_DATA_DEFINED @@ -610,17 +647,47 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * specified via command line. */ #define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename +/* section name strings common to all targets other + than WIN32 */ +#define INSTR_PROF_DATA_COMMON __llvm_prf_data +#define INSTR_PROF_NAME_COMMON __llvm_prf_names +#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts +#define INSTR_PROF_VALS_COMMON __llvm_prf_vals +#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds +#define INSTR_PROF_COVMAP_COMMON __llvm_covmap +/* Win32 */ +#define INSTR_PROF_DATA_COFF .lprfd +#define INSTR_PROF_NAME_COFF .lprfn +#define INSTR_PROF_CNTS_COFF .lprfc +#define INSTR_PROF_VALS_COFF .lprfv +#define INSTR_PROF_VNODES_COFF .lprfnd +#define INSTR_PROF_COVMAP_COFF .lcovmap + +#ifdef _WIN32 /* 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 +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF /* 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 +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COFF /* Value profile nodes section. */ -#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds -#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF +#else +/* Runtime section names and name strings. */ +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COMMON +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COMMON +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COMMON +/* Array of pointers. Each pointer points to a list + * of value nodes associated with one value site. + */ +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COMMON +/* Value profile nodes section. */ +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COMMON +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COMMON +#endif #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) @@ -649,6 +716,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, #define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target #define INSTR_PROF_VALUE_PROF_FUNC_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC) +#define INSTR_PROF_VALUE_RANGE_PROF_FUNC __llvm_profile_instrument_range +#define INSTR_PROF_VALUE_RANGE_PROF_FUNC_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VALUE_RANGE_PROF_FUNC) /* InstrProfile per-function control data alignment. */ #define INSTR_PROF_DATA_ALIGNMENT 8 diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index 65b11f61d10b..1d85a7149afc 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -1,4 +1,4 @@ -//=-- InstrProfReader.h - Instrumented profiling readers ----------*- C++ -*-=// +//===- InstrProfReader.h - Instrumented profiling readers -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,14 +16,23 @@ #define LLVM_PROFILEDATA_INSTRPROFREADER_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/InstrProf.h" -#include "llvm/Support/EndianStream.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SwapByteOrder.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> #include <iterator> +#include <memory> +#include <utility> +#include <vector> namespace llvm { @@ -32,12 +41,13 @@ class InstrProfReader; /// A file format agnostic iterator over profiling data. class InstrProfIterator : public std::iterator<std::input_iterator_tag, InstrProfRecord> { - InstrProfReader *Reader; + InstrProfReader *Reader = nullptr; InstrProfRecord Record; void Increment(); + public: - InstrProfIterator() : Reader(nullptr) {} + InstrProfIterator() = default; InstrProfIterator(InstrProfReader *Reader) : Reader(Reader) { Increment(); } InstrProfIterator &operator++() { Increment(); return *this; } @@ -50,19 +60,22 @@ public: /// Base class and interface for reading profiling data of any known instrprof /// format. Provides an iterator over InstrProfRecords. class InstrProfReader { - instrprof_error LastError; + instrprof_error LastError = instrprof_error::success; public: - InstrProfReader() : LastError(instrprof_error::success), Symtab() {} - virtual ~InstrProfReader() {} + InstrProfReader() = default; + virtual ~InstrProfReader() = default; /// Read the header. Required before reading first record. virtual Error readHeader() = 0; + /// Read a single record. 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: @@ -86,6 +99,7 @@ protected: return Error::success(); return make_error<InstrProfError>(Err); } + Error error(Error E) { return error(InstrProfError::take(std::move(E))); } /// Clear the current error and return a successful one. @@ -94,8 +108,10 @@ protected: 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 != instrprof_error::success && !isEOF(); } + /// Get the current error. Error getError() { if (hasError()) @@ -125,16 +141,15 @@ private: std::unique_ptr<MemoryBuffer> DataBuffer; /// Iterator over the profile data. line_iterator Line; - bool IsIRLevelProfile; + bool IsIRLevelProfile = false; - TextInstrProfReader(const TextInstrProfReader &) = delete; - TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; Error readValueProfileData(InstrProfRecord &Record); public: TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_) - : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#'), - IsIRLevelProfile(false) {} + : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {} + TextInstrProfReader(const TextInstrProfReader &) = delete; + TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; /// Return true if the given buffer is in text instrprof format. static bool hasFormat(const MemoryBuffer &Buffer); @@ -143,6 +158,7 @@ public: /// Read the header. Error readHeader() override; + /// Read a single record. Error readNextRecord(InstrProfRecord &Record) override; @@ -184,15 +200,16 @@ private: InstrProfRecord::ValueMapType FunctionPtrToNameMap; - RawInstrProfReader(const RawInstrProfReader &) = delete; - RawInstrProfReader &operator=(const RawInstrProfReader &) = delete; public: RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer) : DataBuffer(std::move(DataBuffer)) { } + RawInstrProfReader(const RawInstrProfReader &) = delete; + RawInstrProfReader &operator=(const RawInstrProfReader &) = delete; static bool hasFormat(const MemoryBuffer &DataBuffer); Error readHeader() override; Error readNextRecord(InstrProfRecord &Record) override; + bool isIRLevelProfile() const override { return (Version & VARIANT_MASK_IR_PROF) != 0; } @@ -206,9 +223,11 @@ private: 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; } + support::endianness getDataEndianness() const { support::endianness HostEndian = getHostEndianness(); if (!ShouldSwapBytes) @@ -222,15 +241,18 @@ private: inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } + 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; @@ -240,6 +262,7 @@ private: ptrdiff_t Offset = (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t); return CountersStart + Offset; } + StringRef getName(uint64_t NameRef) const { return Symtab->getFuncName(swap(NameRef)); } @@ -249,8 +272,10 @@ typedef RawInstrProfReader<uint32_t> RawInstrProfReader32; typedef RawInstrProfReader<uint64_t> RawInstrProfReader64; namespace IndexedInstrProf { + enum class HashT : uint32_t; -} + +} // end namespace IndexedInstrProf /// Trait for lookups into the on-disk hash table for the binary instrprof /// format. @@ -261,12 +286,11 @@ class InstrProfLookupTrait { // Endianness of the input value profile data. // It should be LE by default, but can be changed // for testing purpose. - support::endianness ValueProfDataEndianness; + support::endianness ValueProfDataEndianness = support::little; public: InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion) - : HashType(HashType), FormatVersion(FormatVersion), - ValueProfDataEndianness(support::little) {} + : HashType(HashType), FormatVersion(FormatVersion) {} typedef ArrayRef<InstrProfRecord> data_type; @@ -284,6 +308,7 @@ public: static std::pair<offset_type, offset_type> ReadKeyDataLength(const unsigned char *&D) { using namespace support; + offset_type KeyLen = endian::readNext<offset_type, little, unaligned>(D); offset_type DataLen = endian::readNext<offset_type, little, unaligned>(D); return std::make_pair(KeyLen, DataLen); @@ -304,16 +329,18 @@ public: }; struct InstrProfReaderIndexBase { + virtual ~InstrProfReaderIndexBase() = default; + // Read all the profile records with the same key pointed to the current // iterator. virtual Error getRecords(ArrayRef<InstrProfRecord> &Data) = 0; + // Read all the profile records with the key equal to 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; @@ -335,22 +362,27 @@ public: const unsigned char *const Payload, const unsigned char *const Base, IndexedInstrProf::HashT HashType, uint64_t Version); + ~InstrProfReaderIndex() override = default; 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(); } + void setValueProfDataEndianness(support::endianness Endianness) override { HashTable->getInfoObj().setValueProfDataEndianness(Endianness); } - ~InstrProfReaderIndex() override {} + 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()); } @@ -366,20 +398,20 @@ private: /// 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: + IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer) + : DataBuffer(std::move(DataBuffer)) {} + IndexedInstrProfReader(const IndexedInstrProfReader &) = delete; + IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete; + /// 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) {} /// Return true if the given buffer is in an indexed instrprof format. static bool hasFormat(const MemoryBuffer &DataBuffer); @@ -422,4 +454,4 @@ public: } // end namespace llvm -#endif +#endif // LLVM_PROFILEDATA_INSTRPROFREADER_H diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index f7780fb45004..10742c0228eb 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -1,4 +1,4 @@ -//=-- InstrProfWriter.h - Instrumented profiling writer -----------*- C++ -*-=// +//===- InstrProfWriter.h - Instrumented profiling writer --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,16 +16,19 @@ #define LLVM_PROFILEDATA_INSTRPROFWRITER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ProfileData/InstrProf.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <memory> namespace llvm { /// Writer for instrumentation based profile data. -class ProfOStream; class InstrProfRecordWriterTrait; +class ProfOStream; class InstrProfWriter { public: @@ -35,7 +38,7 @@ public: private: bool Sparse; StringMap<ProfilingData> FunctionData; - ProfKind ProfileKind; + ProfKind ProfileKind = PF_Unknown; // Use raw pointer here for the incomplete type object. InstrProfRecordWriterTrait *InfoObj; @@ -47,15 +50,20 @@ public: /// for this function and the hash and number of counts match, each counter is /// summed. Optionally scale counts by \p Weight. Error addRecord(InstrProfRecord &&I, uint64_t Weight = 1); + /// Merge existing function counts from the given writer. Error mergeRecordsFromWriter(InstrProfWriter &&IPW); + /// Write the profile to \c OS void write(raw_fd_ostream &OS); + /// Write the profile in text format to \c OS void writeText(raw_fd_ostream &OS); + /// Write \c Record in text format to \c OS static void writeRecordInText(const InstrProfRecord &Record, InstrProfSymtab &Symtab, raw_fd_ostream &OS); + /// Write the profile, returning the raw data. For testing. std::unique_ptr<MemoryBuffer> writeBuffer(); @@ -82,4 +90,4 @@ private: } // end namespace llvm -#endif +#endif // LLVM_PROFILEDATA_INSTRPROFWRITER_H diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h index e955755e5c9a..987e3160ccae 100644 --- a/include/llvm/ProfileData/ProfileCommon.h +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -1,4 +1,4 @@ -//===-- ProfileCommon.h - Common profiling APIs. ----------------*- C++ -*-===// +//===- ProfileCommon.h - Common profiling APIs. -----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,38 +12,33 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_PROFILE_COMMON_H -#define LLVM_PROFILEDATA_PROFILE_COMMON_H +#ifndef LLVM_PROFILEDATA_PROFILECOMMON_H +#define LLVM_PROFILEDATA_PROFILECOMMON_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/Support/Error.h" +#include <algorithm> #include <cstdint> #include <functional> #include <map> -#include <utility> +#include <memory> #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; -} + +struct InstrProfRecord; + namespace sampleprof { + class FunctionSamples; -} -struct InstrProfRecord; -class LLVMContext; -class Metadata; -class MDTuple; -class MDNode; + +} // end namespace sampleprof 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 @@ -53,13 +48,18 @@ private: protected: SummaryEntryVector DetailedSummary; + uint64_t TotalCount = 0; + uint64_t MaxCount = 0; + uint64_t MaxFunctionCount = 0; + uint32_t NumCounts = 0; + uint32_t NumFunctions = 0; + ProfileSummaryBuilder(std::vector<uint32_t> Cutoffs) : DetailedSummaryCutoffs(std::move(Cutoffs)) {} - inline void addCount(uint64_t Count); ~ProfileSummaryBuilder() = default; + + inline void addCount(uint64_t Count); void computeDetailedSummary(); - uint64_t TotalCount = 0, MaxCount = 0, MaxFunctionCount = 0; - uint32_t NumCounts = 0, NumFunctions = 0; public: /// \brief A vector of useful cutoff values for detailed summary. @@ -68,22 +68,24 @@ public: class InstrProfSummaryBuilder final : public ProfileSummaryBuilder { uint64_t MaxInternalBlockCount = 0; + inline void addEntryCount(uint64_t Count); inline void addInternalCount(uint64_t Count); public: InstrProfSummaryBuilder(std::vector<uint32_t> Cutoffs) : ProfileSummaryBuilder(std::move(Cutoffs)) {} + 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)) {} + + void addRecord(const sampleprof::FunctionSamples &FS); std::unique_ptr<ProfileSummary> getSummary(); }; @@ -96,6 +98,6 @@ void ProfileSummaryBuilder::addCount(uint64_t Count) { CountFrequencies[Count]++; } - } // end namespace llvm -#endif + +#endif // LLVM_PROFILEDATA_PROFILECOMMON_H diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h index a96f83620f8b..7a705ca5416d 100644 --- a/include/llvm/ProfileData/SampleProf.h +++ b/include/llvm/ProfileData/SampleProf.h @@ -1,4 +1,4 @@ -//=-- SampleProf.h - Sampling profiling format support --------------------===// +//===- SampleProf.h - Sampling profiling format support ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,20 +12,30 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_ -#define LLVM_PROFILEDATA_SAMPLEPROF_H_ +#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H +#define LLVM_PROFILEDATA_SAMPLEPROF_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/raw_ostream.h" - +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cstdint> #include <map> +#include <string> #include <system_error> +#include <utility> namespace llvm { +class raw_ostream; + const std::error_category &sampleprof_category(); enum class sampleprof_error { @@ -59,12 +69,13 @@ inline sampleprof_error MergeResult(sampleprof_error &Accumulator, } // end namespace llvm namespace std { + template <> struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {}; -} -namespace llvm { +} // end namespace std +namespace llvm { namespace sampleprof { static inline uint64_t SPMagic() { @@ -87,8 +98,10 @@ static inline uint64_t SPVersion() { return 103; } /// (e.g., the two post-increment instructions in "if (p) x++; else y++;"). struct LineLocation { LineLocation(uint32_t L, uint32_t D) : LineOffset(L), Discriminator(D) {} + void print(raw_ostream &OS) const; void dump() const; + bool operator<(const LineLocation &O) const { return LineOffset < O.LineOffset || (LineOffset == O.LineOffset && Discriminator < O.Discriminator); @@ -114,7 +127,7 @@ class SampleRecord { public: typedef StringMap<uint64_t> CallTargetMap; - SampleRecord() : NumSamples(0), CallTargets() {} + SampleRecord() = default; /// Increment the number of samples for this record by \p S. /// Optionally scale sample count \p S by \p Weight. @@ -144,7 +157,7 @@ public: } /// Return true if this sample record contains function calls. - bool hasCalls() const { return CallTargets.size() > 0; } + bool hasCalls() const { return !CallTargets.empty(); } uint64_t getSamples() const { return NumSamples; } const CallTargetMap &getCallTargets() const { return CallTargets; } @@ -163,7 +176,7 @@ public: void dump() const; private: - uint64_t NumSamples; + uint64_t NumSamples = 0; CallTargetMap CallTargets; }; @@ -171,7 +184,8 @@ raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample); typedef std::map<LineLocation, SampleRecord> BodySampleMap; class FunctionSamples; -typedef std::map<LineLocation, FunctionSamples> CallsiteSampleMap; +typedef StringMap<FunctionSamples> FunctionSamplesMap; +typedef std::map<LineLocation, FunctionSamplesMap> CallsiteSampleMap; /// Representation of the samples collected for a function. /// @@ -180,9 +194,11 @@ typedef std::map<LineLocation, FunctionSamples> CallsiteSampleMap; /// within the body of the function. class FunctionSamples { public: - FunctionSamples() : Name(), TotalSamples(0), TotalHeadSamples(0) {} + FunctionSamples() = default; + void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const; void dump() const; + sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) { bool Overflowed; TotalSamples = @@ -190,6 +206,7 @@ public: return Overflowed ? sampleprof_error::counter_overflow : sampleprof_error::success; } + sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) { bool Overflowed; TotalHeadSamples = @@ -197,11 +214,13 @@ public: return Overflowed ? sampleprof_error::counter_overflow : sampleprof_error::success; } + sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num, uint64_t Weight = 1) { return BodySamples[LineLocation(LineOffset, Discriminator)].addSamples( Num, Weight); } + sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, const std::string &FName, @@ -222,34 +241,53 @@ public: return ret->second.getSamples(); } - /// Return the total number of call target samples collected at a given - /// location. Each location is specified by \p LineOffset and - /// \p Discriminator. If the location is not found in profile, return error. - ErrorOr<uint64_t> findCallSamplesAt(uint32_t LineOffset, - uint32_t Discriminator) const { + /// Returns the call target map collected at a given location. + /// Each location is specified by \p LineOffset and \p Discriminator. + /// If the location is not found in profile, return error. + ErrorOr<SampleRecord::CallTargetMap> + findCallTargetMapAt(uint32_t LineOffset, uint32_t Discriminator) const { const auto &ret = BodySamples.find(LineLocation(LineOffset, Discriminator)); if (ret == BodySamples.end()) return std::error_code(); - uint64_t T = 0; - for (const auto &t_c : ret->second.getCallTargets()) { - T += t_c.second; - } - return T; + return ret->second.getCallTargets(); } /// Return the function samples at the given callsite location. - FunctionSamples &functionSamplesAt(const LineLocation &Loc) { + FunctionSamplesMap &functionSamplesAt(const LineLocation &Loc) { return CallsiteSamples[Loc]; } - /// Return a pointer to function samples at the given callsite location. - const FunctionSamples *findFunctionSamplesAt(const LineLocation &Loc) const { + /// Returns the FunctionSamplesMap at the given \p Loc. + const FunctionSamplesMap * + findFunctionSamplesMapAt(const LineLocation &Loc) const { auto iter = CallsiteSamples.find(Loc); - if (iter == CallsiteSamples.end()) { + if (iter == CallsiteSamples.end()) return nullptr; - } else { - return &iter->second; - } + return &iter->second; + } + + /// Returns a pointer to FunctionSamples at the given callsite location \p Loc + /// with callee \p CalleeName. If no callsite can be found, relax the + /// restriction to return the FunctionSamples at callsite location \p Loc + /// with the maximum total sample count. + const FunctionSamples *findFunctionSamplesAt(const LineLocation &Loc, + StringRef CalleeName) const { + auto iter = CallsiteSamples.find(Loc); + if (iter == CallsiteSamples.end()) + return nullptr; + auto FS = iter->second.find(CalleeName); + if (FS != iter->second.end()) + return &FS->getValue(); + // If we cannot find exact match of the callee name, return the FS with + // the max total count. + uint64_t MaxTotalSamples = 0; + const FunctionSamples *R = nullptr; + for (const auto &NameFS : iter->second) + if (NameFS.second.getTotalSamples() >= MaxTotalSamples) { + MaxTotalSamples = NameFS.second.getTotalSamples(); + R = &NameFS.second; + } + return R; } bool empty() const { return TotalSamples == 0; } @@ -283,12 +321,28 @@ public: } for (const auto &I : Other.getCallsiteSamples()) { const LineLocation &Loc = I.first; - const FunctionSamples &Rec = I.second; - MergeResult(Result, functionSamplesAt(Loc).merge(Rec, Weight)); + FunctionSamplesMap &FSMap = functionSamplesAt(Loc); + for (const auto &Rec : I.second) + MergeResult(Result, FSMap[Rec.first()].merge(Rec.second, Weight)); } return Result; } + /// Recursively traverses all children, if the corresponding function is + /// not defined in module \p M, and its total sample is no less than + /// \p Threshold, add its corresponding GUID to \p S. + void findImportedFunctions(DenseSet<GlobalValue::GUID> &S, const Module *M, + uint64_t Threshold) const { + if (TotalSamples <= Threshold) + return; + Function *F = M->getFunction(Name); + if (!F || !F->getSubprogram()) + S.insert(Function::getGUID(Name)); + for (auto CS : CallsiteSamples) + for (const auto &NameFS : CS.second) + NameFS.second.findImportedFunctions(S, M, Threshold); + } + /// Set the name of the function. void setName(StringRef FunctionName) { Name = FunctionName; } @@ -303,12 +357,12 @@ private: /// /// Samples are cumulative, they include all the samples collected /// inside this function and all its inlined callees. - uint64_t TotalSamples; + uint64_t TotalSamples = 0; /// Total number of samples collected at the head of the function. /// This is an approximation of the number of calls made to this function /// at runtime. - uint64_t TotalHeadSamples; + uint64_t TotalHeadSamples = 0; /// Map instruction locations to collected samples. /// @@ -355,6 +409,7 @@ public: return A->first < B->first; }); } + const SamplesWithLocList &get() const { return V; } private: @@ -362,7 +417,6 @@ private: }; } // end namespace sampleprof - } // end namespace llvm -#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_ +#endif // LLVM_PROFILEDATA_SAMPLEPROF_H diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h index bf86721709c7..29e3aba3e0e7 100644 --- a/include/llvm/ProfileData/SampleProfReader.h +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -1,4 +1,4 @@ -//===- SampleProfReader.h - Read LLVM sample profile data -----------------===// +//===- SampleProfReader.h - Read LLVM sample profile data -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -205,26 +205,34 @@ // FUNCTION BODY // A FUNCTION BODY entry describing the inlined function. //===----------------------------------------------------------------------===// + #ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H #define LLVM_PROFILEDATA_SAMPLEPROFREADER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/GCOV.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <memory> +#include <string> +#include <system_error> +#include <vector> namespace llvm { +class raw_ostream; + namespace sampleprof { /// \brief Sample-based profile reader. @@ -259,7 +267,7 @@ public: SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) : Profiles(0), Ctx(C), Buffer(std::move(B)) {} - virtual ~SampleProfileReader() {} + virtual ~SampleProfileReader() = default; /// \brief Read and validate the file header. virtual std::error_code readHeader() = 0; @@ -275,7 +283,12 @@ public: /// \brief Return the samples collected for function \p F. FunctionSamples *getSamplesFor(const Function &F) { - return &Profiles[F.getName()]; + // The function name may have been updated by adding suffix. In sample + // profile, the function names are all stripped, so we need to strip + // the function name suffix before matching with profile. + if (Profiles.count(F.getName().split('.').first)) + return &Profiles[(F.getName().split('.').first)]; + return nullptr; } /// \brief Return all the profiles. @@ -442,8 +455,8 @@ protected: static const uint32_t GCOVTagAFDOFunction = 0xac000000; }; -} // End namespace sampleprof +} // end namespace sampleprof -} // End namespace llvm +} // end namespace llvm #endif // LLVM_PROFILEDATA_SAMPLEPROFREADER_H diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h index f6f2e2702e31..9d69af32dd46 100644 --- a/include/llvm/ProfileData/SampleProfWriter.h +++ b/include/llvm/ProfileData/SampleProfWriter.h @@ -1,4 +1,4 @@ -//===- SampleProfWriter.h - Write LLVM sample profile data ----------------===// +//===- SampleProfWriter.h - Write LLVM sample profile data ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,15 +14,18 @@ #define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <memory> +#include <system_error> namespace llvm { - namespace sampleprof { enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC }; @@ -30,7 +33,7 @@ enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC }; /// \brief Sample-based profile writer. Base class. class SampleProfileWriter { public: - virtual ~SampleProfileWriter() {} + virtual ~SampleProfileWriter() = default; /// Write sample profiles in \p S. /// @@ -114,7 +117,7 @@ public: protected: SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS) - : SampleProfileWriter(OS), NameTable() {} + : SampleProfileWriter(OS) {} std::error_code writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; @@ -133,8 +136,7 @@ private: SampleProfileFormat Format); }; -} // End namespace sampleprof - -} // End namespace llvm +} // end namespace sampleprof +} // end namespace llvm #endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def index c4416f099de1..46d253bf0ec7 100644 --- a/include/llvm/Support/AArch64TargetParser.def +++ b/include/llvm/Support/AArch64TargetParser.def @@ -73,8 +73,17 @@ AARCH64_CPU_NAME("falkor", 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)) +AARCH64_CPU_NAME("thunderx2t99", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_LSE | AArch64::AEK_CRC | + AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("thunderx", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt88", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt81", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE)) +AARCH64_CPU_NAME("thunderxt83", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_PROFILE)) // Invalid CPU AARCH64_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AArch64::AEK_INVALID) #undef AARCH64_CPU_NAME diff --git a/include/llvm/Support/ARMAttributeParser.h b/include/llvm/Support/ARMAttributeParser.h new file mode 100644 index 000000000000..919f39721f86 --- /dev/null +++ b/include/llvm/Support/ARMAttributeParser.h @@ -0,0 +1,140 @@ +//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ARMATTRIBUTEPARSER_H +#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H + +#include "ARMBuildAttributes.h" +#include "ScopedPrinter.h" + +#include <map> + +namespace llvm { +class StringRef; + +class ARMAttributeParser { + ScopedPrinter *SW; + + std::map<unsigned, unsigned> Attributes; + + struct DisplayHandler { + ARMBuildAttrs::AttrType Attribute; + void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType, + const uint8_t *, uint32_t &); + }; + static const DisplayHandler DisplayRoutines[]; + + uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); + StringRef ParseString(const uint8_t *Data, uint32_t &Offset); + + void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); + + void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag, + const uint8_t *Data, uint32_t &Offset); + void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, + uint32_t Length); + void ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl<uint8_t> &IndexList); + void ParseSubsection(const uint8_t *Data, uint32_t Length); +public: + ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} + + ARMAttributeParser() : SW(nullptr) { } + + void Parse(ArrayRef<uint8_t> Section, bool isLittle); + + bool hasAttribute(unsigned Tag) const { + return Attributes.count(Tag); + } + + unsigned getAttributeValue(unsigned Tag) const { + return Attributes.find(Tag)->second; + } +}; + +} + +#endif + diff --git a/include/llvm/Support/ARMBuildAttributes.h b/include/llvm/Support/ARMBuildAttributes.h index e25445790b0c..6c83e447cb24 100644 --- a/include/llvm/Support/ARMBuildAttributes.h +++ b/include/llvm/Support/ARMBuildAttributes.h @@ -176,14 +176,25 @@ enum { WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2 WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4 + // Tag_ABI_align_needed, (=24), uleb128 + Align8Byte = 1, + Align4Byte = 2, + AlignReserved = 3, + + // Tag_ABI_align_needed, (=25), uleb128 + AlignNotPreserved = 0, + AlignPreserve8Byte = 1, + AlignPreserveAll = 2, + // Tag_ABI_FP_denormal, (=20), uleb128 PositiveZero = 0, IEEEDenormals = 1, PreserveFPSign = 2, // sign when flushed-to-zero is preserved // Tag_ABI_FP_number_model, (=23), uleb128 + AllowIEEENormal = 1, AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) - AllowIEE754 = 3, // this code to use all the IEEE 754-defined FP encodings + AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings // Tag_ABI_enum_size, (=26), uleb128 EnumProhibited = 0, // The user prohibited the use of enums when building @@ -208,6 +219,7 @@ enum { // Tag_FP_16bit_format, (=38), uleb128 FP16FormatIEEE = 1, + FP16VFP3 = 2, // Tag_MPextension_use, (=42), uleb128 AllowMP = 1, // Allow use of MP extensions diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def index 58cb6381a9ab..18bf9af43226 100644 --- a/include/llvm/Support/ARMTargetParser.def +++ b/include/llvm/Support/ARMTargetParser.def @@ -76,6 +76,9 @@ ARM_ARCH("armv6-m", AK_ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M, FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv7-a", AK_ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7, FK_NEON, ARM::AEK_DSP) +ARM_ARCH("armv7ve", AK_ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7, + FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | + ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP)) ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7, FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP)) ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7, @@ -229,6 +232,8 @@ 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-m23", AK_ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m33", AK_ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP) 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) @@ -239,6 +244,7 @@ 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) ARM_CPU_NAME("exynos-m2", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) ARM_CPU_NAME("exynos-m3", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) // Non-standard Arch names. ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, ARM::AEK_NONE) ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, ARM::AEK_NONE) diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index c71759abd7d2..a5e662f4c588 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -1,4 +1,4 @@ -//===--- Allocator.h - Simple memory allocation abstraction -----*- C++ -*-===// +//===- Allocator.h - Simple memory allocation abstraction -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -144,19 +144,18 @@ public: "that objects larger than a slab go into their own memory " "allocation."); - BumpPtrAllocatorImpl() - : CurPtr(nullptr), End(nullptr), BytesAllocated(0), Allocator() {} + BumpPtrAllocatorImpl() = default; + template <typename T> BumpPtrAllocatorImpl(T &&Allocator) - : CurPtr(nullptr), End(nullptr), BytesAllocated(0), - Allocator(std::forward<T &&>(Allocator)) {} + : Allocator(std::forward<T &&>(Allocator)) {} // Manually implement a move constructor as we must clear the old allocator's // slabs as a matter of correctness. BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old) : CurPtr(Old.CurPtr), End(Old.End), Slabs(std::move(Old.Slabs)), CustomSizedSlabs(std::move(Old.CustomSizedSlabs)), - BytesAllocated(Old.BytesAllocated), + BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize), Allocator(std::move(Old.Allocator)) { Old.CurPtr = Old.End = nullptr; Old.BytesAllocated = 0; @@ -176,6 +175,7 @@ public: CurPtr = RHS.CurPtr; End = RHS.End; BytesAllocated = RHS.BytesAllocated; + RedZoneSize = RHS.RedZoneSize; Slabs = std::move(RHS.Slabs); CustomSizedSlabs = std::move(RHS.CustomSizedSlabs); Allocator = std::move(RHS.Allocator); @@ -218,10 +218,16 @@ public: size_t Adjustment = alignmentAdjustment(CurPtr, Alignment); assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow"); + size_t SizeToAllocate = Size; +#if LLVM_ADDRESS_SANITIZER_BUILD + // Add trailing bytes as a "red zone" under ASan. + SizeToAllocate += RedZoneSize; +#endif + // Check if we have enough space. - if (Adjustment + Size <= size_t(End - CurPtr)) { + if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) { char *AlignedPtr = CurPtr + Adjustment; - CurPtr = AlignedPtr + Size; + CurPtr = AlignedPtr + SizeToAllocate; // Update the allocation point of this memory block in MemorySanitizer. // Without this, MemorySanitizer messages for values originated from here // will point to the allocation of the entire slab. @@ -232,7 +238,7 @@ public: } // If Size is really big, allocate a separate slab for it. - size_t PaddedSize = Size + Alignment - 1; + size_t PaddedSize = SizeToAllocate + Alignment - 1; if (PaddedSize > SizeThreshold) { void *NewSlab = Allocator.Allocate(PaddedSize, 0); // We own the new slab and don't want anyone reading anyting other than @@ -251,10 +257,10 @@ public: // Otherwise, start a new slab and try again. StartNewSlab(); uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment); - assert(AlignedAddr + Size <= (uintptr_t)End && + assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End && "Unable to allocate memory!"); char *AlignedPtr = (char*)AlignedAddr; - CurPtr = AlignedPtr + Size; + CurPtr = AlignedPtr + SizeToAllocate; __msan_allocated_memory(AlignedPtr, Size); __asan_unpoison_memory_region(AlignedPtr, Size); return AlignedPtr; @@ -283,6 +289,10 @@ public: size_t getBytesAllocated() const { return BytesAllocated; } + void setRedZoneSize(size_t NewSize) { + RedZoneSize = NewSize; + } + void PrintStats() const { detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated, getTotalMemory()); @@ -292,10 +302,10 @@ private: /// \brief The current pointer into the current slab. /// /// This points to the next free byte in the slab. - char *CurPtr; + char *CurPtr = nullptr; /// \brief The end of the current slab. - char *End; + char *End = nullptr; /// \brief The slabs allocated so far. SmallVector<void *, 4> Slabs; @@ -306,7 +316,11 @@ private: /// \brief How many bytes we've allocated. /// /// Used so that we can compute how much space was wasted. - size_t BytesAllocated; + size_t BytesAllocated = 0; + + /// \brief The number of bytes to put between allocations when running under + /// a sanitizer. + size_t RedZoneSize = 1; /// \brief The allocator instance we use to get slabs of memory. AllocatorT Allocator; @@ -357,7 +371,7 @@ private: }; /// \brief The standard BumpPtrAllocator which just uses the default template -/// paramaters. +/// parameters. typedef BumpPtrAllocatorImpl<> BumpPtrAllocator; /// \brief A BumpPtrAllocator that allows only elements of a specific type to be @@ -369,7 +383,11 @@ template <typename T> class SpecificBumpPtrAllocator { BumpPtrAllocator Allocator; public: - SpecificBumpPtrAllocator() = default; + SpecificBumpPtrAllocator() { + // Because SpecificBumpPtrAllocator walks the memory to call destructors, + // it can't have red zones between allocations. + Allocator.setRedZoneSize(0); + } SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old) : Allocator(std::move(Old.Allocator)) {} ~SpecificBumpPtrAllocator() { DestroyAll(); } diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h index d03714b009c5..552313f0c241 100644 --- a/include/llvm/Support/Atomic.h +++ b/include/llvm/Support/Atomic.h @@ -20,6 +20,11 @@ #include "llvm/Support/DataTypes.h" +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + namespace llvm { namespace sys { void MemoryFence(); diff --git a/include/llvm/Support/BinaryByteStream.h b/include/llvm/Support/BinaryByteStream.h new file mode 100644 index 000000000000..694be28e07e1 --- /dev/null +++ b/include/llvm/Support/BinaryByteStream.h @@ -0,0 +1,192 @@ +//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===// +// A BinaryStream which stores data in a single continguous memory buffer. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H +#define LLVM_SUPPORT_BINARYBYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <memory> + +namespace llvm { + +/// \brief An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. BinaryByteStream guarantees that no read +/// operation will ever incur a copy. Note that BinaryByteStream does not +/// own the underlying buffer. +class BinaryByteStream : public BinaryStream { +public: + BinaryByteStream() = default; + BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data) {} + BinaryByteStream(StringRef Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffset(Offset, Size)) + return EC; + Buffer = Data.slice(Offset, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffset(Offset, 1)) + return EC; + Buffer = Data.slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + ArrayRef<uint8_t> data() const { return Data; } + + StringRef str() const { + const char *CharData = reinterpret_cast<const char *>(Data.data()); + return StringRef(CharData, Data.size()); + } + +protected: + llvm::support::endianness Endian; + ArrayRef<uint8_t> Data; +}; + +/// \brief An implementation of BinaryStream whose data is backed by an llvm +/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in +/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream +/// will never cause a copy. +class MemoryBufferByteStream : public BinaryByteStream { +public: + MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer, + llvm::support::endianness Endian) + : BinaryByteStream(Buffer->getBuffer(), Endian), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr<MemoryBuffer> MemBuffer; +}; + +/// \brief An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. As with BinaryByteStream, the mutable +/// version also guarantees that no read operation will ever incur a copy, +/// and similarly it does not own the underlying buffer. +class MutableBinaryByteStream : public WritableBinaryStream { +public: + MutableBinaryByteStream() = default; + MutableBinaryByteStream(MutableArrayRef<uint8_t> Data, + llvm::support::endianness Endian) + : Data(Data), ImmutableStream(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return ImmutableStream.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return ImmutableStream.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { + if (Buffer.empty()) + return Error::success(); + + if (auto EC = checkOffset(Offset, Buffer.size())) + return EC; + + uint8_t *DataPtr = const_cast<uint8_t *>(Data.data()); + ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + MutableArrayRef<uint8_t> data() const { return Data; } + +private: + MutableArrayRef<uint8_t> Data; + BinaryByteStream ImmutableStream; +}; + +/// \brief An implementation of WritableBinaryStream backed by an llvm +/// FileOutputBuffer. +class FileBufferByteStream : public WritableBinaryStream { +private: + class StreamImpl : public MutableBinaryByteStream { + public: + StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : MutableBinaryByteStream( + MutableArrayRef<uint8_t>(Buffer->getBufferStart(), + Buffer->getBufferEnd()), + Endian), + FileBuffer(std::move(Buffer)) {} + + Error commit() override { + if (FileBuffer->commit()) + return make_error<BinaryStreamError>( + stream_error_code::filesystem_error); + return Error::success(); + } + + private: + std::unique_ptr<FileOutputBuffer> FileBuffer; + }; + +public: + FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : Impl(std::move(Buffer), Endian) {} + + llvm::support::endianness getEndian() const override { + return Impl.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return Impl.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { + return Impl.writeBytes(Offset, Data); + } + + Error commit() override { return Impl.commit(); } + +private: + StreamImpl Impl; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BYTESTREAM_H diff --git a/include/llvm/DebugInfo/MSF/SequencedItemStream.h b/include/llvm/Support/BinaryItemStream.h index 1949beef9fff..f4b319217819 100644 --- a/include/llvm/DebugInfo/MSF/SequencedItemStream.h +++ b/include/llvm/Support/BinaryItemStream.h @@ -1,4 +1,4 @@ -//===- SequencedItemStream.h ------------------------------------*- C++ -*-===// +//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,52 +7,54 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H -#define LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H +#ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H +#define LLVM_SUPPORT_BINARYITEMSTREAM_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/Error.h" #include <cstddef> #include <cstdint> namespace llvm { -namespace msf { -template <typename T> struct SequencedItemTraits { +template <typename T> struct BinaryItemTraits { static size_t length(const T &Item) = delete; static ArrayRef<uint8_t> bytes(const T &Item) = delete; }; -/// SequencedItemStream represents a sequence of objects stored in a -/// standard container but for which it is useful to view as a stream of -/// contiguous bytes. An example of this might be if you have a std::vector -/// of TPI records, where each record contains a byte sequence that -/// represents that one record serialized, but where each consecutive item -/// might not be allocated immediately after the previous item. Using a -/// SequencedItemStream, we can adapt the VarStreamArray class to trivially -/// extract one item at a time, allowing the data to be used anywhere a -/// VarStreamArray could be used. -template <typename T, typename Traits = SequencedItemTraits<T>> -class SequencedItemStream : public ReadableStream { +/// BinaryItemStream represents a sequence of objects stored in some kind of +/// external container but for which it is useful to view as a stream of +/// contiguous bytes. An example of this might be if you have a collection of +/// records and you serialize each one into a buffer, and store these serialized +/// records in a container. The pointers themselves are not laid out +/// contiguously in memory, but we may wish to read from or write to these +/// records as if they were. +template <typename T, typename Traits = BinaryItemTraits<T>> +class BinaryItemStream : public BinaryStream { public: - SequencedItemStream() = default; + explicit BinaryItemStream(llvm::support::endianness Endian) + : Endian(Endian) {} + + llvm::support::endianness getEndian() const override { return Endian; } Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const override { + ArrayRef<uint8_t> &Buffer) override { auto ExpectedIndex = translateOffsetIndex(Offset); if (!ExpectedIndex) return ExpectedIndex.takeError(); const auto &Item = Items[*ExpectedIndex]; + if (auto EC = checkOffset(Offset, Size)) + return EC; if (Size > Traits::length(Item)) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); Buffer = Traits::bytes(Item).take_front(Size); return Error::success(); } Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef<uint8_t> &Buffer) const override { + ArrayRef<uint8_t> &Buffer) override { auto ExpectedIndex = translateOffsetIndex(Offset); if (!ExpectedIndex) return ExpectedIndex.takeError(); @@ -62,7 +64,7 @@ public: void setItems(ArrayRef<T> ItemArray) { Items = ItemArray; } - uint32_t getLength() const override { + uint32_t getLength() override { uint32_t Size = 0; for (const auto &Item : Items) Size += Traits::length(Item); @@ -80,14 +82,14 @@ private: ++CurrentIndex; } if (CurrentOffset != Offset) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); return CurrentIndex; } + llvm::support::endianness Endian; ArrayRef<T> Items; }; -} // end namespace msf } // end namespace llvm -#endif // LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H +#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H diff --git a/include/llvm/Support/BinaryStream.h b/include/llvm/Support/BinaryStream.h new file mode 100644 index 000000000000..a227117e063e --- /dev/null +++ b/include/llvm/Support/BinaryStream.h @@ -0,0 +1,78 @@ +//===- BinaryStream.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_SUPPORT_BINARYSTREAM_H +#define LLVM_SUPPORT_BINARYSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { + +/// \brief An interface for accessing data in a stream-like format, but which +/// discourages copying. Instead of specifying a buffer in which to copy +/// data on a read, the API returns an ArrayRef to data owned by the stream's +/// implementation. Since implementations may not necessarily store data in a +/// single contiguous buffer (or even in memory at all), in such cases a it may +/// be necessary for an implementation to cache such a buffer so that it can +/// return it. +class BinaryStream { +public: + virtual ~BinaryStream() = default; + + virtual llvm::support::endianness getEndian() const = 0; + + /// \brief Given an offset into the stream and a number of bytes, attempt to + /// read the bytes and set the output ArrayRef to point to data owned by the + /// stream. + virtual Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) = 0; + + /// \brief 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) = 0; + + /// \brief Return the number of bytes of data in this stream. + virtual uint32_t getLength() = 0; + +protected: + Error checkOffset(uint32_t Offset, uint32_t DataSize) { + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + if (getLength() < DataSize + Offset) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + return Error::success(); + } +}; + +/// \brief A BinaryStream which can be read from as well as written to. Note +/// that writing to a BinaryStream always necessitates copying from the input +/// buffer to the stream's backing store. Streams are assumed to be buffered +/// so that to be portable it is necessary to call commit() on the stream when +/// all data has been written. +class WritableBinaryStream : public BinaryStream { +public: + ~WritableBinaryStream() override = default; + + /// \brief 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) = 0; + + /// \brief For buffered streams, commits changes to the backing store. + virtual Error commit() = 0; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAM_H diff --git a/include/llvm/DebugInfo/MSF/StreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 5dfeb8c524af..3b1301d3cc0b 100644 --- a/include/llvm/DebugInfo/MSF/StreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -1,4 +1,4 @@ -//===- StreamArray.h - Array backed by an arbitrary stream ------*- C++ -*-===// +//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,21 +7,30 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_MSF_STREAMARRAY_H -#define LLVM_DEBUGINFO_MSF_STREAMARRAY_H +#ifndef LLVM_SUPPORT_BINARYSTREAMARRAY_H +#define LLVM_SUPPORT_BINARYSTREAMARRAY_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include <cassert> #include <cstdint> +/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file +/// provides two different array implementations. +/// +/// VarStreamArray - Arrays of variable length records. The user specifies +/// an Extractor type that can extract a record from a given offset and +/// return the number of bytes consumed by the record. +/// +/// FixedStreamArray - Arrays of fixed length records. This is similar in +/// spirit to ArrayRef<T>, but since it is backed by a BinaryStream, the +/// elements of the array need not be laid out in contiguous memory. namespace llvm { -namespace msf { /// VarStreamArrayExtractor is intended to be specialized to provide customized -/// extraction logic. On input it receives a StreamRef pointing to the +/// extraction logic. On input it receives a BinaryStreamRef 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 @@ -35,7 +44,7 @@ namespace msf { template <typename T> struct VarStreamArrayExtractor { // Method intentionally deleted. You must provide an explicit specialization // with the following method implemented. - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, T &Item) const = delete; }; @@ -49,10 +58,10 @@ template <typename T> struct VarStreamArrayExtractor { /// 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. +/// or copying 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 +/// If you do not specify an Extractor type, you are expected to specialize /// VarStreamArrayExtractor<T> for your ValueType. /// /// By default an Extractor is default constructed in the class, but in some @@ -86,8 +95,8 @@ public: VarStreamArray() = default; explicit VarStreamArray(const Extractor &E) : E(E) {} - explicit VarStreamArray(ReadableStreamRef Stream) : Stream(Stream) {} - VarStreamArray(ReadableStreamRef Stream, const Extractor &E) + explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} + VarStreamArray(BinaryStreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {} VarStreamArray(const VarStreamArray<ValueType, Extractor> &Other) @@ -101,10 +110,10 @@ public: const Extractor &getExtractor() const { return E; } - ReadableStreamRef getUnderlyingStream() const { return Stream; } + BinaryStreamRef getUnderlyingStream() const { return Stream; } private: - ReadableStreamRef Stream; + BinaryStreamRef Stream; Extractor E; }; @@ -153,23 +162,25 @@ public: 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. + IterType &operator+=(unsigned N) { + for (unsigned I = 0; I < N; ++I) { + // 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; @@ -188,7 +199,7 @@ private: } ValueType ThisValue; - ReadableStreamRef IterRef; + BinaryStreamRef IterRef; const ArrayType *Array{nullptr}; uint32_t ThisLen{0}; bool HasError{false}; @@ -198,12 +209,17 @@ private: template <typename T> class FixedStreamArrayIterator; +/// FixedStreamArray is similar to VarStreamArray, except with each record +/// having a fixed-length. As with VarStreamArray, there is no upfront +/// cost associated with building or copying a FixedStreamArray, as the +/// memory for each element is not read from the backing stream until that +/// element is iterated. template <typename T> class FixedStreamArray { friend class FixedStreamArrayIterator<T>; public: FixedStreamArray() = default; - FixedStreamArray(ReadableStreamRef Stream) : Stream(Stream) { + explicit FixedStreamArray(BinaryStreamRef Stream) : Stream(Stream) { assert(Stream.getLength() % sizeof(T) == 0); } @@ -227,6 +243,7 @@ public: // an exact multiple of the element size. consumeError(std::move(EC)); } + assert(llvm::alignmentAdjustment(Data.data(), alignof(T)) == 0); return *reinterpret_cast<const T *>(Data.data()); } @@ -242,10 +259,10 @@ public: return FixedStreamArrayIterator<T>(*this, size()); } - ReadableStreamRef getUnderlyingStream() const { return Stream; } + BinaryStreamRef getUnderlyingStream() const { return Stream; } private: - ReadableStreamRef Stream; + BinaryStreamRef Stream; }; template <typename T> @@ -298,7 +315,6 @@ private: uint32_t Index; }; -} // namespace msf } // namespace llvm -#endif // LLVM_DEBUGINFO_MSF_STREAMARRAY_H +#endif // LLVM_SUPPORT_BINARYSTREAMARRAY_H diff --git a/include/llvm/Support/BinaryStreamError.h b/include/llvm/Support/BinaryStreamError.h new file mode 100644 index 000000000000..7d9699d53639 --- /dev/null +++ b/include/llvm/Support/BinaryStreamError.h @@ -0,0 +1,48 @@ +//===- BinaryStreamError.h - Error extensions for Binary Streams *- 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_BINARYSTREAMERROR_H +#define LLVM_SUPPORT_BINARYSTREAMERROR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#include <string> + +namespace llvm { +enum class stream_error_code { + unspecified, + stream_too_short, + invalid_array_size, + invalid_offset, + filesystem_error +}; + +/// Base class for errors originating when parsing raw PDB files +class BinaryStreamError : public ErrorInfo<BinaryStreamError> { +public: + static char ID; + explicit BinaryStreamError(stream_error_code C); + explicit BinaryStreamError(StringRef Context); + BinaryStreamError(stream_error_code C, StringRef Context); + + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + + StringRef getErrorMessage() const; + + stream_error_code getErrorCode() const { return Code; } + +private: + std::string ErrMsg; + stream_error_code Code; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h new file mode 100644 index 000000000000..d994fa0f49d0 --- /dev/null +++ b/include/llvm/Support/BinaryStreamReader.h @@ -0,0 +1,234 @@ +//===- BinaryStreamReader.h - Reads objects from a binary 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_SUPPORT_BINARYSTREAMREADER_H +#define LLVM_SUPPORT_BINARYSTREAMREADER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/type_traits.h" + +#include <string> +#include <type_traits> + +namespace llvm { + +/// \brief Provides read only access to a subclass of `BinaryStream`. Provides +/// bounds checking and helpers for writing certain common data types such as +/// null-terminated strings, integers in various flavors of endianness, etc. +/// Can be subclassed to provide reading of custom datatypes, although no +/// are overridable. +class BinaryStreamReader { +public: + explicit BinaryStreamReader(BinaryStreamRef Stream); + virtual ~BinaryStreamReader() {} + + /// Read as much as possible from the underlying string at the current offset + /// without invoking a copy, and set \p Buffer to the resulting data slice. + /// Updates the stream's offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer); + + /// Read \p Size bytes from the underlying stream at the current offset and + /// and set \p Buffer to the resulting data slice. Whether a copy occurs + /// depends on the implementation of the underlying stream. Updates the + /// stream's offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size); + + /// Read an integer of the specified endianness into \p Dest and update the + /// stream's offset. The data is always copied from the stream's underlying + /// buffer into \p Dest. Updates the stream's offset to point after the newly + /// read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + template <typename T> Error readInteger(T &Dest) { + static_assert(std::is_integral<T>::value, + "Cannot call readInteger with non-integral value!"); + + ArrayRef<uint8_t> Bytes; + if (auto EC = readBytes(Bytes, sizeof(T))) + return EC; + + Dest = llvm::support::endian::read<T, llvm::support::unaligned>( + Bytes.data(), Stream.getEndian()); + return Error::success(); + } + + /// Similar to readInteger. + template <typename T> Error readEnum(T &Dest) { + static_assert(std::is_enum<T>::value, + "Cannot call readEnum with non-enum value!"); + typename std::underlying_type<T>::type N; + if (auto EC = readInteger(N)) + return EC; + Dest = static_cast<T>(N); + return Error::success(); + } + + /// Read a null terminated string from \p Dest. Whether a copy occurs depends + /// on the implementation of the underlying stream. Updates the stream's + /// offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readCString(StringRef &Dest); + + /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends + /// on the implementation of the underlying stream. Updates the stream's + /// offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readFixedString(StringRef &Dest, uint32_t Length); + + /// Read the entire remainder of the underlying stream into \p Ref. This is + /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the + /// stream's offset to point to the end of the stream. Never causes a copy. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readStreamRef(BinaryStreamRef &Ref); + + /// Read \p Length bytes from the underlying stream into \p Ref. This is + /// equivalent to calling getUnderlyingStream().slice(Offset, Length). + /// Updates the stream's offset to point after the newly read object. Never + /// causes a copy. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length); + + /// Get a pointer to an object of type T from the underlying stream, as if by + /// memcpy, and store the result into \p Dest. It is up to the caller to + /// ensure that objects of type T can be safely treated in this manner. + /// Updates the stream's offset to point after the newly read object. Whether + /// a copy occurs depends upon the implementation of the underlying + /// stream. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + 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(); + } + + /// Get a reference to a \p NumElements element array of objects of type T + /// from the underlying stream as if by memcpy, and store the resulting array + /// slice into \p array. It is up to the caller to ensure that objects of + /// type T can be safely treated in this manner. Updates the stream's offset + /// to point after the newly read object. Whether a copy occurs depends upon + /// the implementation of the underlying stream. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + 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<BinaryStreamError>( + stream_error_code::invalid_array_size); + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + + assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && + "Reading at invalid alignment!"); + + Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); + return Error::success(); + } + + /// Read a VarStreamArray of size \p Size bytes and store the result into + /// \p Array. Updates the stream's offset to point after the newly read + /// array. Never causes a copy (although iterating the elements of the + /// VarStreamArray may, depending upon the implementation of the underlying + /// stream). + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + template <typename T, typename U> + Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { + BinaryStreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray<T, U>(S, Array.getExtractor()); + return Error::success(); + } + + /// Read a FixedStreamArray of \p NumItems elements and store the result into + /// \p Array. Updates the stream's offset to point after the newly read + /// array. Never causes a copy (although iterating the elements of the + /// FixedStreamArray may, depending upon the implementation of the underlying + /// stream). + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + template <typename T> + Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) { + if (NumItems == 0) { + Array = FixedStreamArray<T>(); + return Error::success(); + } + + if (NumItems > UINT32_MAX / sizeof(T)) + return make_error<BinaryStreamError>( + stream_error_code::invalid_array_size); + + BinaryStreamRef View; + if (auto EC = readStreamRef(View, NumItems * sizeof(T))) + return EC; + + Array = FixedStreamArray<T>(View); + return Error::success(); + } + + bool empty() const { return bytesRemaining() == 0; } + 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(); } + + /// Advance the stream's offset by \p Amount bytes. + /// + /// \returns a success error code if at least \p Amount bytes remain in the + /// stream, otherwise returns an appropriate error code. + Error skip(uint32_t Amount); + + /// Examine the next byte of the underlying stream without advancing the + /// stream's offset. If the stream is empty the behavior is undefined. + /// + /// \returns the next byte in the stream. + uint8_t peek() const; + +private: + BinaryStreamRef Stream; + uint32_t Offset; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H diff --git a/include/llvm/Support/BinaryStreamRef.h b/include/llvm/Support/BinaryStreamRef.h new file mode 100644 index 000000000000..23ce02fd7ca4 --- /dev/null +++ b/include/llvm/Support/BinaryStreamRef.h @@ -0,0 +1,174 @@ +//===- BinaryStreamRef.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_SUPPORT_BINARYSTREAMREF_H +#define LLVM_SUPPORT_BINARYSTREAMREF_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> + +namespace llvm { + +/// Common stuff for mutable and immutable StreamRefs. +template <class StreamType, class RefType> class BinaryStreamRefBase { +public: + BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} + BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) + : Stream(&Stream), ViewOffset(Offset), Length(Length) {} + + llvm::support::endianness getEndian() const { return Stream->getEndian(); } + + uint32_t getLength() const { return Length; } + const StreamType *getStream() const { return Stream; } + + /// Return a new BinaryStreamRef with the first \p N elements removed. + RefType drop_front(uint32_t N) const { + if (!Stream) + return RefType(); + + N = std::min(N, Length); + return RefType(*Stream, ViewOffset + N, Length - N); + } + + /// Return a new BinaryStreamRef with only the first \p N elements remaining. + RefType keep_front(uint32_t N) const { + if (!Stream) + return RefType(); + N = std::min(N, Length); + return RefType(*Stream, ViewOffset, N); + } + + /// Return a new BinaryStreamRef with the first \p Offset elements removed, + /// and retaining exactly \p Len elements. + RefType slice(uint32_t Offset, uint32_t Len) const { + return drop_front(Offset).keep_front(Len); + } + + bool operator==(const RefType &Other) const { + if (Stream != Other.Stream) + return false; + if (ViewOffset != Other.ViewOffset) + return false; + if (Length != Other.Length) + return false; + return true; + } + +protected: + Error checkOffset(uint32_t Offset, uint32_t DataSize) const { + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + if (getLength() < DataSize + Offset) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + return Error::success(); + } + + StreamType *Stream; + uint32_t ViewOffset; + uint32_t Length; +}; + +/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It +/// provides copy-semantics and read only access to a "window" of the underlying +/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to +/// say, it does not inherit and override the methods of BinaryStream. In +/// general, you should not pass around pointers or references to BinaryStreams +/// and use inheritance to achieve polymorphism. Instead, you should pass +/// around BinaryStreamRefs by value and achieve polymorphism that way. +class BinaryStreamRef + : public BinaryStreamRefBase<BinaryStream, BinaryStreamRef> { +public: + BinaryStreamRef() = default; + BinaryStreamRef(BinaryStream &Stream) + : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} + BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + + // Use BinaryStreamRef.slice() instead. + BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, + uint32_t Length) = delete; + + /// Given an Offset into this StreamRef and a Size, return a reference to a + /// buffer owned by the stream. + /// + /// \returns a success error code if the entire range of data is within the + /// bounds of this BinaryStreamRef's view and the implementation could read + /// the data, and an appropriate error code otherwise. + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const { + if (auto EC = checkOffset(Offset, Size)) + return EC; + + return Stream->readBytes(ViewOffset + Offset, Size, Buffer); + } + + /// Given an Offset into this BinaryStreamRef, return a reference to the + /// largest buffer the stream could support without necessitating a copy. + /// + /// \returns a success error code if implementation could read the data, + /// and an appropriate error code otherwise. + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) const { + if (auto EC = checkOffset(Offset, 1)) + return EC; + + if (auto EC = + Stream->readLongestContiguousChunk(ViewOffset + 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(); + } +}; + +class WritableBinaryStreamRef + : public BinaryStreamRefBase<WritableBinaryStream, + WritableBinaryStreamRef> { +public: + WritableBinaryStreamRef() = default; + WritableBinaryStreamRef(WritableBinaryStream &Stream) + : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} + WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + + // Use WritableBinaryStreamRef.slice() instead. + WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, + uint32_t Length) = delete; + + /// Given an Offset into this WritableBinaryStreamRef and some input data, + /// writes the data to the underlying stream. + /// + /// \returns a success error code if the data could fit within the underlying + /// stream at the specified location and the implementation could write the + /// data, and an appropriate error code otherwise. + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { + if (auto EC = checkOffset(Offset, Data.size())) + return EC; + + return Stream->writeBytes(ViewOffset + Offset, Data); + } + + operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } + + /// \brief For buffered streams, commits changes to the backing store. + Error commit() { return Stream->commit(); } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMREF_H diff --git a/include/llvm/Support/BinaryStreamWriter.h b/include/llvm/Support/BinaryStreamWriter.h new file mode 100644 index 000000000000..64f26b24543d --- /dev/null +++ b/include/llvm/Support/BinaryStreamWriter.h @@ -0,0 +1,166 @@ +//===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- 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_BINARYSTREAMWRITER_H +#define LLVM_SUPPORT_BINARYSTREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <type_traits> + +namespace llvm { + +/// \brief Provides write only access to a subclass of `WritableBinaryStream`. +/// Provides bounds checking and helpers for writing certain common data types +/// such as null-terminated strings, integers in various flavors of endianness, +/// etc. Can be subclassed to provide reading and writing of custom datatypes, +/// although no methods are overridable. +class BinaryStreamWriter { +public: + BinaryStreamWriter() = default; + explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); + virtual ~BinaryStreamWriter() {} + + /// Write the bytes specified in \p Buffer to the underlying stream. + /// On success, updates the offset so that subsequent writes will occur + /// at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeBytes(ArrayRef<uint8_t> Buffer); + + /// Write the the integer \p Value to the underlying stream in the + /// specified endianness. On success, updates the offset so that + /// subsequent writes occur at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template <typename T> Error writeInteger(T Value) { + static_assert(std::is_integral<T>::value, + "Cannot call writeInteger with non-integral value!"); + uint8_t Buffer[sizeof(T)]; + llvm::support::endian::write<T, llvm::support::unaligned>( + Buffer, Value, Stream.getEndian()); + return writeBytes(Buffer); + } + + /// Similar to writeInteger + template <typename T> Error writeEnum(T Num) { + static_assert(std::is_enum<T>::value, + "Cannot call writeEnum with non-Enum type"); + + using U = typename std::underlying_type<T>::type; + return writeInteger<U>(static_cast<U>(Num)); + } + + /// Write the the string \p Str to the underlying stream followed by a null + /// terminator. On success, updates the offset so that subsequent writes + /// occur at the next unwritten position. \p Str need not be null terminated + /// on input. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeCString(StringRef Str); + + /// Write the the string \p Str to the underlying stream without a null + /// terminator. On success, updates the offset so that subsequent writes + /// occur at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeFixedString(StringRef Str); + + /// Efficiently reads all data from \p Ref, and writes it to this stream. + /// This operation will not invoke any copies of the source data, regardless + /// of the source stream's implementation. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeStreamRef(BinaryStreamRef Ref); + + /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream. + /// This operation will not invoke any copies of the source data, regardless + /// of the source stream's implementation. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size); + + /// Writes the object \p Obj to the underlying stream, as if by using memcpy. + /// It is up to the caller to ensure that type of \p Obj can be safely copied + /// in this fashion, as no checks are made to ensure that this is safe. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + 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))); + } + + /// Writes an array of objects of type T to the underlying stream, as if by + /// using memcpy. It is up to the caller to ensure that type of \p Obj can + /// be safely copied in this fashion, as no checks are made to ensure that + /// this is safe. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template <typename T> Error writeArray(ArrayRef<T> Array) { + if (Array.empty()) + return Error::success(); + if (Array.size() > UINT32_MAX / sizeof(T)) + return make_error<BinaryStreamError>( + stream_error_code::invalid_array_size); + + return writeBytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()), + Array.size() * sizeof(T))); + } + + /// Writes all data from the array \p Array to the underlying stream. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template <typename T, typename U> + Error writeArray(VarStreamArray<T, U> Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + /// Writes all elements from the array \p Array to the underlying stream. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + 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(); } + Error padToAlignment(uint32_t Align); + +protected: + WritableBinaryStreamRef Stream; + uint32_t Offset = 0; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H diff --git a/include/llvm/Support/CMakeLists.txt b/include/llvm/Support/CMakeLists.txt new file mode 100644 index 000000000000..b4b993705745 --- /dev/null +++ b/include/llvm/Support/CMakeLists.txt @@ -0,0 +1,54 @@ +# Figure out if we can track VC revisions. +function(find_first_existing_file out_var) + foreach(file ${ARGN}) + if(EXISTS "${file}") + set(${out_var} "${file}" PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() + +macro(find_first_existing_vc_file out_var path) + find_program(git_executable NAMES git git.exe git.cmd) + # Run from a subdirectory to force git to print an absolute path. + execute_process(COMMAND ${git_executable} rev-parse --git-dir + WORKING_DIRECTORY ${path}/cmake + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_dir) + if(git_result EQUAL 0) + string(STRIP "${git_dir}" git_dir) + set(${out_var} "${git_dir}/logs/HEAD") + else() + find_first_existing_file(${out_var} + "${path}/.svn/wc.db" # SVN 1.7 + "${path}/.svn/entries" # SVN 1.6 + ) + endif() +endmacro() + +find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}") + +# The VC revision include that we want to generate. +set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSRevision.h") + +set(get_svn_script "${LLVM_CMAKE_PATH}/GenerateVersionFromCVS.cmake") + +if(DEFINED llvm_vc) + # Create custom target to generate the VC revision include. + add_custom_command(OUTPUT "${version_inc}" + DEPENDS "${llvm_vc}" "${get_svn_script}" + COMMAND + ${CMAKE_COMMAND} "-DSOURCE_DIR=${LLVM_MAIN_SRC_DIR}" + "-DNAME=LLVM_REVISION" + "-DHEADER_FILE=${version_inc}" + -P "${get_svn_script}") + + # Mark the generated header as being generated. + set_source_files_properties("${version_inc}" + PROPERTIES GENERATED TRUE + HEADER_FILE_ONLY TRUE) +else() + file(WRITE "${version_inc}" "") +endif() + +add_custom_target(llvm_vcsrevision_h DEPENDS "${version_inc}") diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h index 954fd8ae7ffb..e826938878e5 100644 --- a/include/llvm/Support/CachePruning.h +++ b/include/llvm/Support/CachePruning.h @@ -20,51 +20,44 @@ 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(std::chrono::seconds 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(std::chrono::seconds 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; - std::chrono::seconds Expiration = std::chrono::seconds::zero(); - std::chrono::seconds Interval = std::chrono::seconds::zero(); - unsigned PercentageOfAvailableSpace = 0; +template <typename T> class Expected; + +/// Policy for the pruneCache() function. A default constructed +/// CachePruningPolicy provides a reasonable default policy. +struct CachePruningPolicy { + /// 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 occur. + std::chrono::seconds Interval = std::chrono::seconds(1200); + + /// The expiration for a file. When a file hasn't been accessed for Expiration + /// seconds, it is removed from the cache. A value of 0 disables the + /// expiration-based pruning. + std::chrono::seconds Expiration = std::chrono::hours(7 * 24); // 1w + + /// 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 disables the + /// size-based pruning. + unsigned PercentageOfAvailableSpace = 75; }; +/// Parse the given string as a cache pruning policy. Defaults are taken from a +/// default constructed CachePruningPolicy object. +/// For example: "prune_interval=30s:prune_after=24h:cache_size=50%" +/// which means a pruning interval of 30 seconds, expiration time of 24 hours +/// and maximum cache size of 50% of available disk space. +Expected<CachePruningPolicy> parseCachePruningPolicy(StringRef PolicyStr); + +/// Peform pruning using the supplied policy, returns true if pruning +/// occured, i.e. if Policy.Interval was expired. +/// +/// As a safeguard against data loss if the user specifies the wrong directory +/// as their cache directory, this function will ignore files not matching the +/// pattern "llvmcache-*". +bool pruneCache(StringRef Path, CachePruningPolicy Policy); + } // namespace llvm #endif diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h index a73047b2b557..89d2af052dc1 100644 --- a/include/llvm/Support/Casting.h +++ b/include/llvm/Support/Casting.h @@ -18,6 +18,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/type_traits.h" #include <cassert> +#include <memory> namespace llvm { @@ -76,6 +77,14 @@ template <typename To, typename From> struct isa_impl_cl<To, const From> { } }; +template <typename To, typename From> +struct isa_impl_cl<To, const std::unique_ptr<From>> { + static inline bool doit(const std::unique_ptr<From> &Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl_cl<To, From>::doit(*Val); + } +}; + template <typename To, typename From> struct isa_impl_cl<To, From*> { static inline bool doit(const From *Val) { assert(Val && "isa<> used on a null pointer"); @@ -161,6 +170,15 @@ template<class To, class From> struct cast_retty_impl<To, const From*const> { typedef const To* ret_type; // Constant pointer arg case, return const Ty* }; +template <class To, class From> +struct cast_retty_impl<To, std::unique_ptr<From>> { +private: + typedef typename cast_retty_impl<To, From *>::ret_type PointerType; + typedef typename std::remove_pointer<PointerType>::type ResultType; + +public: + typedef std::unique_ptr<ResultType> ret_type; +}; template<class To, class From, class SimpleFrom> struct cast_retty_wrap { @@ -238,6 +256,16 @@ inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) { typename simplify_type<Y*>::SimpleType>::doit(Val); } +template <class X, class Y> +inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type +cast(std::unique_ptr<Y> &&Val) { + assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!"); + using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type; + return ret_type( + cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit( + Val.release())); +} + // cast_or_null<X> - Functionally identical to cast, except that a null value is // accepted. // @@ -271,6 +299,13 @@ cast_or_null(Y *Val) { return cast<X>(Val); } +template <class X, class Y> +inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type +cast_or_null(std::unique_ptr<Y> &&Val) { + if (!Val) + return nullptr; + return cast<X>(std::move(Val)); +} // dyn_cast<X> - Return the argument parameter cast to the specified type. This // casting operator returns null if the argument is of the wrong type, so it can @@ -323,6 +358,41 @@ dyn_cast_or_null(Y *Val) { return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; } +// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>, +// taking ownership of the input pointer iff isa<X>(Val) is true. If the +// cast is successful, From refers to nullptr on exit and the casted value +// is returned. If the cast is unsuccessful, the function returns nullptr +// and From is unchanged. +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val) + -> decltype(cast<X>(Val)) { + if (!isa<X>(Val)) + return nullptr; + return cast<X>(std::move(Val)); +} + +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) + -> decltype(cast<X>(Val)) { + return unique_dyn_cast<X, Y>(Val); +} + +// dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that +// a null value is accepted. +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) + -> decltype(cast<X>(Val)) { + if (!Val) + return nullptr; + return unique_dyn_cast<X, Y>(Val); +} + +template <class X, class Y> +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) + -> decltype(cast<X>(Val)) { + return unique_dyn_cast_or_null<X, Y>(Val); +} + } // End llvm namespace #endif diff --git a/include/llvm/Support/Chrono.h b/include/llvm/Support/Chrono.h index 203439cab919..6118ed0476ed 100644 --- a/include/llvm/Support/Chrono.h +++ b/include/llvm/Support/Chrono.h @@ -11,6 +11,7 @@ #define LLVM_SUPPORT_CHRONO_H #include "llvm/Support/Compiler.h" +#include "llvm/Support/FormatProviders.h" #include <chrono> #include <ctime> @@ -50,6 +51,100 @@ toTimePoint(std::time_t T) { raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); +/// Implementation of format_provider<T> for duration types. +/// +/// The options string of a duration type has the grammar: +/// +/// duration_options ::= [unit][show_unit [number_options]] +/// unit ::= `h`|`m`|`s`|`ms|`us`|`ns` +/// show_unit ::= `+` | `-` +/// number_options ::= options string for a integral or floating point type +/// +/// Examples +/// ================================= +/// | options | Input | Output | +/// ================================= +/// | "" | 1s | 1 s | +/// | "ms" | 1s | 1000 ms | +/// | "ms-" | 1s | 1000 | +/// | "ms-n" | 1s | 1,000 | +/// | "" | 1.0s | 1.00 s | +/// ================================= +/// +/// If the unit of the duration type is not one of the units specified above, +/// it is still possible to format it, provided you explicitly request a +/// display unit or you request that the unit is not displayed. + +namespace detail { +template <typename Period> struct unit { static const char value[]; }; +template <typename Period> const char unit<Period>::value[] = ""; + +template <> struct unit<std::ratio<3600>> { static const char value[]; }; +template <> struct unit<std::ratio<60>> { static const char value[]; }; +template <> struct unit<std::ratio<1>> { static const char value[]; }; +template <> struct unit<std::milli> { static const char value[]; }; +template <> struct unit<std::micro> { static const char value[]; }; +template <> struct unit<std::nano> { static const char value[]; }; +} // namespace detail + +template <typename Rep, typename Period> +struct format_provider<std::chrono::duration<Rep, Period>> { +private: + typedef std::chrono::duration<Rep, Period> Dur; + typedef typename std::conditional< + std::chrono::treat_as_floating_point<Rep>::value, double, intmax_t>::type + InternalRep; + + template <typename AsPeriod> static InternalRep getAs(const Dur &D) { + using namespace std::chrono; + return duration_cast<duration<InternalRep, AsPeriod>>(D).count(); + } + + static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style, + const Dur &D) { + using namespace std::chrono; + if (Style.consume_front("ns")) + return {getAs<std::nano>(D), "ns"}; + if (Style.consume_front("us")) + return {getAs<std::micro>(D), "us"}; + if (Style.consume_front("ms")) + return {getAs<std::milli>(D), "ms"}; + if (Style.consume_front("s")) + return {getAs<std::ratio<1>>(D), "s"}; + if (Style.consume_front("m")) + return {getAs<std::ratio<60>>(D), "m"}; + if (Style.consume_front("h")) + return {getAs<std::ratio<3600>>(D), "h"}; + return {D.count(), detail::unit<Period>::value}; + } + + static bool consumeShowUnit(StringRef &Style) { + if (Style.empty()) + return true; + if (Style.consume_front("-")) + return false; + if (Style.consume_front("+")) + return true; + assert(0 && "Unrecognised duration format"); + return true; + } + +public: + static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) { + InternalRep count; + StringRef unit; + std::tie(count, unit) = consumeUnit(Style, D); + bool show_unit = consumeShowUnit(Style); + + format_provider<InternalRep>::format(count, Stream, Style); + + if (show_unit) { + assert(!unit.empty()); + Stream << " " << unit; + } + } +}; + } // namespace llvm #endif // LLVM_SUPPORT_CHRONO_H diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 8d4ac81d2942..ae32e20d6dab 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -50,9 +50,12 @@ namespace cl { //===----------------------------------------------------------------------===// // ParseCommandLineOptions - Command line option processing entry point. // +// Returns true on success. Otherwise, this will print the error message to +// stderr and exit if \p Errs is not set (nullptr by default), or print the +// error message to \p Errs and return false if \p Errs is provided. bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview = "", - bool IgnoreErrors = false); + raw_ostream *Errs = nullptr); //===----------------------------------------------------------------------===// // ParseEnvironmentOptions - Environment variable option processing alternate @@ -343,6 +346,9 @@ public: virtual void printOptionValue(size_t GlobalWidth, bool Force) const = 0; + static void printHelpStr(StringRef HelpStr, size_t Indent, + size_t FirstLineIndentedBy); + virtual void getExtraOptionNames(SmallVectorImpl<StringRef> &) {} // addOccurrence - Wrapper around handleOccurrence that enforces Flags. diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index 55148a490c29..a56bc93e111b 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -343,7 +343,7 @@ /// int k; /// long long l; /// }; -/// LLVM_PACKED_END +/// LLVM_PACKED_END #ifdef _MSC_VER # define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop)) # define LLVM_PACKED_START __pragma(pack(push, 1)) @@ -445,6 +445,9 @@ void AnnotateIgnoreWritesEnd(const char *file, int line); /// \brief Mark debug helper function definitions like dump() that should not be /// stripped from debug builds. +/// Note that you should also surround dump() functions with +/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always +/// get stripped in release builds. // FIXME: Move this to a private config.h as it's not usable in public headers. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) #define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED @@ -461,7 +464,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line); #define LLVM_PRETTY_FUNCTION __FUNCSIG__ #elif defined(__GNUC__) || defined(__clang__) #define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#else +#else #define LLVM_PRETTY_FUNCTION __func__ #endif diff --git a/include/llvm/Support/Compression.h b/include/llvm/Support/Compression.h index 5bf7031fe9f9..2d191abe4b1a 100644 --- a/include/llvm/Support/Compression.h +++ b/include/llvm/Support/Compression.h @@ -18,6 +18,7 @@ namespace llvm { template <typename T> class SmallVectorImpl; +class Error; class StringRef; namespace zlib { @@ -29,26 +30,17 @@ enum CompressionLevel { BestSizeCompression }; -enum Status { - StatusOK, - StatusUnsupported, // zlib is unavailable - StatusOutOfMemory, // there was not enough memory - StatusBufferTooShort, // there was not enough room in the output buffer - StatusInvalidArg, // invalid input parameter - StatusInvalidData // data was corrupted or incomplete -}; - bool isAvailable(); -Status compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer, - CompressionLevel Level = DefaultCompression); +Error compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer, + CompressionLevel Level = DefaultCompression); -Status uncompress(StringRef InputBuffer, char *UncompressedBuffer, - size_t &UncompressedSize); +Error uncompress(StringRef InputBuffer, char *UncompressedBuffer, + size_t &UncompressedSize); -Status uncompress(StringRef InputBuffer, - SmallVectorImpl<char> &UncompressedBuffer, - size_t UncompressedSize); +Error uncompress(StringRef InputBuffer, + SmallVectorImpl<char> &UncompressedBuffer, + size_t UncompressedSize); uint32_t crc32(StringRef Buffer); diff --git a/include/llvm/Support/Debug.h b/include/llvm/Support/Debug.h index 3465c403361f..48e9e1bc167d 100644 --- a/include/llvm/Support/Debug.h +++ b/include/llvm/Support/Debug.h @@ -33,11 +33,6 @@ namespace llvm { class raw_ostream; #ifndef NDEBUG -/// DebugFlag - This boolean is set to true if the '-debug' command line option -/// is specified. This should probably not be referenced directly, instead, use -/// the DEBUG macro below. -/// -extern bool DebugFlag; /// isCurrentDebugType - Return true if the specified string is the debug type /// specified on the command line, or if none was specified on the command line @@ -77,6 +72,29 @@ void setCurrentDebugTypes(const char **Types, unsigned Count); #define DEBUG_WITH_TYPE(TYPE, X) do { } while (false) #endif +/// This boolean is set to true if the '-debug' command line option +/// is specified. This should probably not be referenced directly, instead, use +/// the DEBUG macro below. +/// +extern bool DebugFlag; + +/// \name Verification flags. +/// +/// These flags turns on/off that are expensive and are turned off by default, +/// unless macro EXPENSIVE_CHECKS is defined. The flags allow selectively +/// turning the checks on without need to recompile. +/// \{ + +/// Enables verification of dominator trees. +/// +extern bool VerifyDomInfo; + +/// Enables verification of loop info. +/// +extern bool VerifyLoopInfo; + +///\} + /// EnableDebugBuffering - This defaults to false. If true, the debug /// stream will install signal handlers to dump any buffered debug /// output. It allows clients to selectively allow the debug stream diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h new file mode 100644 index 000000000000..9687cb7b9d95 --- /dev/null +++ b/include/llvm/Support/DebugCounter.h @@ -0,0 +1,165 @@ +//===- llvm/Support/DebugCounter.h - Debug counter support ------*- 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 provides an implementation of debug counters. Debug +/// counters are a tool that let you narrow down a miscompilation to a specific +/// thing happening. +/// +/// To give a use case: Imagine you have a file, very large, and you +/// are trying to understand the minimal transformation that breaks it. Bugpoint +/// and bisection is often helpful here in narrowing it down to a specific pass, +/// but it's still a very large file, and a very complicated pass to try to +/// debug. That is where debug counting steps in. You can instrument the pass +/// with a debug counter before it does a certain thing, and depending on the +/// counts, it will either execute that thing or not. The debug counter itself +/// consists of a skip and a count. Skip is the number of times shouldExecute +/// needs to be called before it returns true. Count is the number of times to +/// return true once Skip is 0. So a skip=47, count=2 ,would skip the first 47 +/// executions by returning false from shouldExecute, then execute twice, and +/// then return false again. +/// Note that a counter set to a negative number will always execute. +/// For a concrete example, during predicateinfo creation, the renaming pass +/// replaces each use with a renamed use. +//// +/// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and +/// variable name RenameCounter, and then instrument this renaming with a debug +/// counter, like so: +/// +/// if (!DebugCounter::shouldExecute(RenameCounter) +/// <continue or return or whatever not executing looks like> +/// +/// Now I can, from the command line, make it rename or not rename certain uses +/// by setting the skip and count. +/// So for example +/// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1 +/// will skip renaming the first 47 uses, then rename one, then skip the rest. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DEBUGCOUNTER_H +#define LLVM_SUPPORT_DEBUGCOUNTER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/UniqueVector.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace llvm { + +class DebugCounter { +public: + /// \brief Returns a reference to the singleton instance. + static DebugCounter &instance(); + + // Used by the command line option parser to push a new value it parsed. + void push_back(const std::string &); + + // Register a counter with the specified name. + // + // FIXME: Currently, counter registration is required to happen before command + // line option parsing. The main reason to register counters is to produce a + // nice list of them on the command line, but i'm not sure this is worth it. + static unsigned registerCounter(StringRef Name, StringRef Desc) { + return instance().addCounter(Name, Desc); + } + inline static bool shouldExecute(unsigned CounterName) { +// Compile to nothing when debugging is off +#ifdef NDEBUG + return true; +#else + auto &Us = instance(); + auto Result = Us.Counters.find(CounterName); + if (Result != Us.Counters.end()) { + auto &CounterPair = Result->second; + // We only execute while the skip (first) is zero and the count (second) + // is non-zero. + // Negative counters always execute. + if (CounterPair.first < 0) + return true; + if (CounterPair.first != 0) { + --CounterPair.first; + return false; + } + if (CounterPair.second < 0) + return true; + if (CounterPair.second != 0) { + --CounterPair.second; + return true; + } + return false; + } + // Didn't find the counter, should we warn? + return true; +#endif // NDEBUG + } + + // Return true if a given counter had values set (either programatically or on + // the command line). This will return true even if those values are + // currently in a state where the counter will always execute. + static bool isCounterSet(unsigned ID) { + return instance().Counters.count(ID); + } + + // Return the skip and count for a counter. This only works for set counters. + static std::pair<int, int> getCounterValue(unsigned ID) { + auto &Us = instance(); + auto Result = Us.Counters.find(ID); + assert(Result != Us.Counters.end() && "Asking about a non-set counter"); + return Result->second; + } + + // Set a registered counter to a given value. + static void setCounterValue(unsigned ID, const std::pair<int, int> &Val) { + auto &Us = instance(); + Us.Counters[ID] = Val; + } + + // Dump or print the current counter set. + LLVM_DUMP_METHOD void dump() { print(dbgs()); } + + void print(raw_ostream &OS); + + // Get the counter ID for a given named counter, or return 0 if none is found. + unsigned getCounterId(const std::string &Name) const { + return RegisteredCounters.idFor(Name); + } + + // Return the number of registered counters. + unsigned int getNumCounters() const { return RegisteredCounters.size(); } + + // Return the name and description of the counter with the given ID. + std::pair<std::string, std::string> getCounterInfo(unsigned ID) const { + return std::make_pair(RegisteredCounters[ID], CounterDesc.lookup(ID)); + } + + // Iterate through the registered counters + typedef UniqueVector<std::string> CounterVector; + CounterVector::const_iterator begin() const { + return RegisteredCounters.begin(); + } + CounterVector::const_iterator end() const { return RegisteredCounters.end(); } + +private: + unsigned addCounter(const std::string &Name, const std::string &Desc) { + unsigned Result = RegisteredCounters.insert(Name); + CounterDesc[Result] = Desc; + return Result; + } + DenseMap<unsigned, std::pair<long, long>> Counters; + DenseMap<unsigned, std::string> CounterDesc; + CounterVector RegisteredCounters; +}; + +#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \ + static const unsigned VARNAME = \ + DebugCounter::registerCounter(COUNTERNAME, DESC); + +} // namespace llvm +#endif diff --git a/include/llvm/Support/Dwarf.def b/include/llvm/Support/Dwarf.def index 841fc7d4ae22..fdbd8ea70116 100644 --- a/include/llvm/Support/Dwarf.def +++ b/include/llvm/Support/Dwarf.def @@ -19,7 +19,8 @@ defined HANDLE_DW_CC || defined HANDLE_DW_LNS || \ defined HANDLE_DW_LNE || defined HANDLE_DW_LNCT || \ defined HANDLE_DW_MACRO || defined HANDLE_DW_RLE || \ - defined HANDLE_DW_CFA || defined HANDLE_DW_APPLE_PROPERTY) + defined HANDLE_DW_CFA || defined HANDLE_DW_APPLE_PROPERTY || \ + defined HANDLE_DW_UT) #error "Missing macro definition of HANDLE_DW*" #endif @@ -87,6 +88,10 @@ #define HANDLE_DW_APPLE_PROPERTY(ID, NAME) #endif +#ifndef HANDLE_DW_UT +#define HANDLE_DW_UT(ID, NAME) +#endif + HANDLE_DW_TAG(0x0000, null) HANDLE_DW_TAG(0x0001, array_type) HANDLE_DW_TAG(0x0002, class_type) @@ -135,6 +140,7 @@ HANDLE_DW_TAG(0x0032, try_block) HANDLE_DW_TAG(0x0033, variant_part) HANDLE_DW_TAG(0x0034, variable) HANDLE_DW_TAG(0x0035, volatile_type) +// New in DWARF v3: HANDLE_DW_TAG(0x0036, dwarf_procedure) HANDLE_DW_TAG(0x0037, restrict_type) HANDLE_DW_TAG(0x0038, interface_type) @@ -145,11 +151,11 @@ HANDLE_DW_TAG(0x003c, partial_unit) HANDLE_DW_TAG(0x003d, imported_unit) HANDLE_DW_TAG(0x003f, condition) HANDLE_DW_TAG(0x0040, shared_type) +// New in DWARF v4: HANDLE_DW_TAG(0x0041, type_unit) HANDLE_DW_TAG(0x0042, rvalue_reference_type) HANDLE_DW_TAG(0x0043, template_alias) - -// New in DWARF v5. +// New in DWARF v5: HANDLE_DW_TAG(0x0044, coarray_type) HANDLE_DW_TAG(0x0045, generic_subrange) HANDLE_DW_TAG(0x0046, dynamic_type) @@ -158,8 +164,7 @@ HANDLE_DW_TAG(0x0048, call_site) HANDLE_DW_TAG(0x0049, call_site_parameter) HANDLE_DW_TAG(0x004a, skeleton_unit) HANDLE_DW_TAG(0x004b, immutable_type) - -// User-defined tags. +// Vendor extensions: HANDLE_DW_TAG(0x4081, MIPS_loop) HANDLE_DW_TAG(0x4101, format_label) HANDLE_DW_TAG(0x4102, function_template) @@ -234,6 +239,7 @@ HANDLE_DW_AT(0x4a, use_location) HANDLE_DW_AT(0x4b, variable_parameter) HANDLE_DW_AT(0x4c, virtuality) HANDLE_DW_AT(0x4d, vtable_elem_location) +// New in DWARF v3: HANDLE_DW_AT(0x4e, allocated) HANDLE_DW_AT(0x4f, associated) HANDLE_DW_AT(0x50, data_location) @@ -261,14 +267,14 @@ HANDLE_DW_AT(0x65, endianity) HANDLE_DW_AT(0x66, elemental) HANDLE_DW_AT(0x67, pure) HANDLE_DW_AT(0x68, recursive) +// New in DWARF v4: HANDLE_DW_AT(0x69, signature) HANDLE_DW_AT(0x6a, main_subprogram) HANDLE_DW_AT(0x6b, data_bit_offset) HANDLE_DW_AT(0x6c, const_expr) HANDLE_DW_AT(0x6d, enum_class) HANDLE_DW_AT(0x6e, linkage_name) - -// New in DWARF 5: +// New in DWARF v5: HANDLE_DW_AT(0x6f, string_length_bit_size) HANDLE_DW_AT(0x70, string_length_byte_size) HANDLE_DW_AT(0x71, rank) @@ -299,7 +305,7 @@ HANDLE_DW_AT(0x89, export_symbols) HANDLE_DW_AT(0x8a, deleted) HANDLE_DW_AT(0x8b, defaulted) HANDLE_DW_AT(0x8c, loclists_base) - +// Vendor extensions: HANDLE_DW_AT(0x2002, MIPS_loop_begin) HANDLE_DW_AT(0x2003, MIPS_tail_loop_begin) HANDLE_DW_AT(0x2004, MIPS_epilog_begin) @@ -315,11 +321,9 @@ HANDLE_DW_AT(0x200d, MIPS_stride_elem) HANDLE_DW_AT(0x200e, MIPS_ptr_dopetype) HANDLE_DW_AT(0x200f, MIPS_allocatable_dopetype) HANDLE_DW_AT(0x2010, MIPS_assumed_shape_dopetype) - // This one appears to have only been implemented by Open64 for // fortran and may conflict with other extensions. HANDLE_DW_AT(0x2011, MIPS_assumed_size) - // GNU extensions HANDLE_DW_AT(0x2101, sf_names) HANDLE_DW_AT(0x2102, src_info) @@ -329,10 +333,8 @@ HANDLE_DW_AT(0x2105, body_begin) HANDLE_DW_AT(0x2106, body_end) HANDLE_DW_AT(0x2107, GNU_vector) HANDLE_DW_AT(0x2110, GNU_template_name) - HANDLE_DW_AT(0x210f, GNU_odr_signature) HANDLE_DW_AT(0x2119, GNU_macros) - // Extensions for Fission proposal. HANDLE_DW_AT(0x2130, GNU_dwo_name) HANDLE_DW_AT(0x2131, GNU_dwo_id) @@ -341,7 +343,6 @@ HANDLE_DW_AT(0x2133, GNU_addr_base) HANDLE_DW_AT(0x2134, GNU_pubnames) HANDLE_DW_AT(0x2135, GNU_pubtypes) HANDLE_DW_AT(0x2136, GNU_discriminator) - // Borland extensions. HANDLE_DW_AT(0x3b11, BORLAND_property_read) HANDLE_DW_AT(0x3b12, BORLAND_property_write) @@ -360,12 +361,10 @@ HANDLE_DW_AT(0x3b28, BORLAND_Delphi_ABI) HANDLE_DW_AT(0x3b29, BORLAND_Delphi_return) HANDLE_DW_AT(0x3b30, BORLAND_Delphi_frameptr) HANDLE_DW_AT(0x3b31, BORLAND_closure) - // LLVM project extensions. HANDLE_DW_AT(0x3e00, LLVM_include_path) HANDLE_DW_AT(0x3e01, LLVM_config_macros) HANDLE_DW_AT(0x3e02, LLVM_isysroot) - // Apple extensions. HANDLE_DW_AT(0x3fe1, APPLE_optimized) HANDLE_DW_AT(0x3fe2, APPLE_flags) @@ -403,26 +402,34 @@ HANDLE_DW_FORM(0x13, ref4) HANDLE_DW_FORM(0x14, ref8) HANDLE_DW_FORM(0x15, ref_udata) HANDLE_DW_FORM(0x16, indirect) +// New in DWARF v4: HANDLE_DW_FORM(0x17, sec_offset) HANDLE_DW_FORM(0x18, exprloc) HANDLE_DW_FORM(0x19, flag_present) - -// New in DWARF v5. +// This was defined out of sequence. +HANDLE_DW_FORM(0x20, ref_sig8) +// New in DWARF v5: HANDLE_DW_FORM(0x1a, strx) HANDLE_DW_FORM(0x1b, addrx) -HANDLE_DW_FORM(0x1c, ref_sup) +HANDLE_DW_FORM(0x1c, ref_sup4) HANDLE_DW_FORM(0x1d, strp_sup) HANDLE_DW_FORM(0x1e, data16) HANDLE_DW_FORM(0x1f, line_strp) -HANDLE_DW_FORM(0x20, ref_sig8) HANDLE_DW_FORM(0x21, implicit_const) HANDLE_DW_FORM(0x22, loclistx) HANDLE_DW_FORM(0x23, rnglistx) - +HANDLE_DW_FORM(0x24, ref_sup8) +HANDLE_DW_FORM(0x25, strx1) +HANDLE_DW_FORM(0x26, strx2) +HANDLE_DW_FORM(0x27, strx3) +HANDLE_DW_FORM(0x28, strx4) +HANDLE_DW_FORM(0x29, addrx1) +HANDLE_DW_FORM(0x2a, addrx2) +HANDLE_DW_FORM(0x2b, addrx3) +HANDLE_DW_FORM(0x2c, addrx4) // Extensions for Fission proposal HANDLE_DW_FORM(0x1f01, GNU_addr_index) HANDLE_DW_FORM(0x1f02, GNU_str_index) - // Alternate debug sections proposal (output of "dwz" tool). HANDLE_DW_FORM(0x1f20, GNU_ref_alt) HANDLE_DW_FORM(0x1f21, GNU_strp_alt) @@ -462,7 +469,6 @@ HANDLE_DW_OP(0x24, shl) HANDLE_DW_OP(0x25, shr) HANDLE_DW_OP(0x26, shra) HANDLE_DW_OP(0x27, xor) -HANDLE_DW_OP(0x2f, skip) HANDLE_DW_OP(0x28, bra) HANDLE_DW_OP(0x29, eq) HANDLE_DW_OP(0x2a, ge) @@ -470,6 +476,7 @@ HANDLE_DW_OP(0x2b, gt) HANDLE_DW_OP(0x2c, le) HANDLE_DW_OP(0x2d, lt) HANDLE_DW_OP(0x2e, ne) +HANDLE_DW_OP(0x2f, skip) HANDLE_DW_OP(0x30, lit0) HANDLE_DW_OP(0x31, lit1) HANDLE_DW_OP(0x32, lit2) @@ -573,6 +580,7 @@ HANDLE_DW_OP(0x93, piece) HANDLE_DW_OP(0x94, deref_size) HANDLE_DW_OP(0x95, xderef_size) HANDLE_DW_OP(0x96, nop) +// New in DWARF v3: HANDLE_DW_OP(0x97, push_object_address) HANDLE_DW_OP(0x98, call2) HANDLE_DW_OP(0x99, call4) @@ -580,8 +588,10 @@ HANDLE_DW_OP(0x9a, call_ref) HANDLE_DW_OP(0x9b, form_tls_address) HANDLE_DW_OP(0x9c, call_frame_cfa) HANDLE_DW_OP(0x9d, bit_piece) +// New in DWARF v4: HANDLE_DW_OP(0x9e, implicit_value) HANDLE_DW_OP(0x9f, stack_value) +// New in DWARF v5: HANDLE_DW_OP(0xa0, implicit_pointer) HANDLE_DW_OP(0xa1, addrx) HANDLE_DW_OP(0xa2, constx) @@ -592,11 +602,9 @@ HANDLE_DW_OP(0xa6, deref_type) HANDLE_DW_OP(0xa7, xderef_type) HANDLE_DW_OP(0xa8, convert) HANDLE_DW_OP(0xa9, reinterpret) - -// Vendor extensions. +// Vendor extensions: // Extensions for GNU-style thread-local storage. HANDLE_DW_OP(0xe0, GNU_push_tls_address) - // Extensions for Fission proposal. HANDLE_DW_OP(0xfb, GNU_addr_index) HANDLE_DW_OP(0xfc, GNU_const_index) @@ -612,6 +620,7 @@ HANDLE_DW_LANG(0x0007, Fortran77) HANDLE_DW_LANG(0x0008, Fortran90) HANDLE_DW_LANG(0x0009, Pascal83) HANDLE_DW_LANG(0x000a, Modula2) +// New in DWARF v3: HANDLE_DW_LANG(0x000b, Java) HANDLE_DW_LANG(0x000c, C99) HANDLE_DW_LANG(0x000d, Ada95) @@ -621,9 +630,9 @@ HANDLE_DW_LANG(0x0010, ObjC) HANDLE_DW_LANG(0x0011, ObjC_plus_plus) HANDLE_DW_LANG(0x0012, UPC) HANDLE_DW_LANG(0x0013, D) - -// New in DWARF 5: +// New in DWARF v4: HANDLE_DW_LANG(0x0014, Python) +// New in DWARF v5: HANDLE_DW_LANG(0x0015, OpenCL) HANDLE_DW_LANG(0x0016, Go) HANDLE_DW_LANG(0x0017, Modula3) @@ -640,8 +649,8 @@ HANDLE_DW_LANG(0x0021, C_plus_plus_14) HANDLE_DW_LANG(0x0022, Fortran03) HANDLE_DW_LANG(0x0023, Fortran08) HANDLE_DW_LANG(0x0024, RenderScript) - -// Vendor extensions. +HANDLE_DW_LANG(0x0025, BLISS) +// Vendor extensions: HANDLE_DW_LANG(0x8001, Mips_Assembler) HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript) HANDLE_DW_LANG(0xb000, BORLAND_Delphi) @@ -655,6 +664,7 @@ HANDLE_DW_ATE(0x05, signed) HANDLE_DW_ATE(0x06, signed_char) HANDLE_DW_ATE(0x07, unsigned) HANDLE_DW_ATE(0x08, unsigned_char) +// New in DWARF v3: HANDLE_DW_ATE(0x09, imaginary_float) HANDLE_DW_ATE(0x0a, packed_decimal) HANDLE_DW_ATE(0x0b, numeric_string) @@ -662,7 +672,9 @@ HANDLE_DW_ATE(0x0c, edited) HANDLE_DW_ATE(0x0d, signed_fixed) HANDLE_DW_ATE(0x0e, unsigned_fixed) HANDLE_DW_ATE(0x0f, decimal_float) +// New in DWARF v4: HANDLE_DW_ATE(0x10, UTF) +// New in DWARF v5: HANDLE_DW_ATE(0x11, UCS) HANDLE_DW_ATE(0x12, ASCII) @@ -680,8 +692,10 @@ HANDLE_DW_DEFAULTED(0x02, out_of_class) HANDLE_DW_CC(0x01, normal) HANDLE_DW_CC(0x02, program) HANDLE_DW_CC(0x03, nocall) +// New in DWARF v5: HANDLE_DW_CC(0x04, pass_by_reference) HANDLE_DW_CC(0x05, pass_by_value) +// Vendor extensions: HANDLE_DW_CC(0x41, GNU_borland_fastcall_i386) HANDLE_DW_CC(0xb0, BORLAND_safecall) HANDLE_DW_CC(0xb1, BORLAND_stdcall) @@ -696,6 +710,7 @@ HANDLE_DW_CC(0xc0, LLVM_vectorcall) HANDLE_DW_LNE(0x01, end_sequence) HANDLE_DW_LNE(0x02, set_address) HANDLE_DW_LNE(0x03, define_file) +// New in DWARF v4: HANDLE_DW_LNE(0x04, set_discriminator) // Line Number Standard Opcode Encodings. @@ -709,6 +724,7 @@ HANDLE_DW_LNS(0x06, negate_stmt) HANDLE_DW_LNS(0x07, set_basic_block) HANDLE_DW_LNS(0x08, const_add_pc) HANDLE_DW_LNS(0x09, fixed_advance_pc) +// New in DWARF v3: HANDLE_DW_LNS(0x0a, set_prologue_end) HANDLE_DW_LNS(0x0b, set_epilogue_begin) HANDLE_DW_LNS(0x0c, set_isa) @@ -720,6 +736,7 @@ HANDLE_DW_LNCT(0x03, timestamp) HANDLE_DW_LNCT(0x04, size) HANDLE_DW_LNCT(0x05, MD5) +// DWARF v5 Macro information. HANDLE_DW_MACRO(0x01, define) HANDLE_DW_MACRO(0x02, undef) HANDLE_DW_MACRO(0x03, start_file) @@ -733,7 +750,7 @@ HANDLE_DW_MACRO(0x0a, import_sup) HANDLE_DW_MACRO(0x0b, define_strx) HANDLE_DW_MACRO(0x0c, undef_strx) -// Range list entry encoding values. +// DWARF v5 Range List Entry encoding values. HANDLE_DW_RLE(0x00, end_of_list) HANDLE_DW_RLE(0x01, base_addressx) HANDLE_DW_RLE(0x02, startx_endx) @@ -762,6 +779,7 @@ HANDLE_DW_CFA(0x0b, restore_state) HANDLE_DW_CFA(0x0c, def_cfa) HANDLE_DW_CFA(0x0d, def_cfa_register) HANDLE_DW_CFA(0x0e, def_cfa_offset) +// New in DWARF v3: HANDLE_DW_CFA(0x0f, def_cfa_expression) HANDLE_DW_CFA(0x10, expression) HANDLE_DW_CFA(0x11, offset_extended_sf) @@ -770,6 +788,7 @@ HANDLE_DW_CFA(0x13, def_cfa_offset_sf) HANDLE_DW_CFA(0x14, val_offset) HANDLE_DW_CFA(0x15, val_offset_sf) HANDLE_DW_CFA(0x16, val_expression) +// Vendor extensions: HANDLE_DW_CFA(0x1d, MIPS_advance_loc8) HANDLE_DW_CFA(0x2d, GNU_window_save) HANDLE_DW_CFA(0x2e, GNU_args_size) @@ -792,6 +811,13 @@ HANDLE_DW_APPLE_PROPERTY(0x1000, nullability) HANDLE_DW_APPLE_PROPERTY(0x2000, null_resettable) HANDLE_DW_APPLE_PROPERTY(0x4000, class) +// DWARF v5 Unit Types. +HANDLE_DW_UT(0x01, compile) +HANDLE_DW_UT(0x02, type) +HANDLE_DW_UT(0x03, partial) +HANDLE_DW_UT(0x04, skeleton) +HANDLE_DW_UT(0x05, split_compile) +HANDLE_DW_UT(0x06, split_type) #undef HANDLE_DW_TAG #undef HANDLE_DW_AT @@ -809,3 +835,4 @@ HANDLE_DW_APPLE_PROPERTY(0x4000, class) #undef HANDLE_DW_RLE #undef HANDLE_DW_CFA #undef HANDLE_DW_APPLE_PROPERTY +#undef HANDLE_DW_UT diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h index 8336b9df9df0..84056682924e 100644 --- a/include/llvm/Support/Dwarf.h +++ b/include/llvm/Support/Dwarf.h @@ -29,7 +29,7 @@ class StringRef; namespace dwarf { //===----------------------------------------------------------------------===// -// Dwarf constants as gleaned from the DWARF Debugging Information Format V.4 +// DWARF constants as gleaned from the DWARF Debugging Information Format V.5 // reference manual http://www.dwarfstd.org/. // @@ -305,7 +305,15 @@ enum ApplePropertyAttributes { #include "llvm/Support/Dwarf.def" }; -// Constants for the DWARF5 Accelerator Table Proposal +/// Constants for unit types in DWARF v5. +enum UnitType : unsigned char { +#define HANDLE_DW_UT(ID, NAME) DW_UT_##NAME = ID, +#include "llvm/Support/Dwarf.def" + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff +}; + +// Constants for the DWARF v5 Accelerator Table Proposal enum AcceleratorTable { // Data layout descriptors. DW_ATOM_null = 0u, // Marker as the end of a list of atoms. @@ -373,6 +381,7 @@ StringRef LNExtendedString(unsigned Encoding); StringRef MacinfoString(unsigned Encoding); StringRef CallFrameString(unsigned Encoding); StringRef ApplePropertyString(unsigned); +StringRef UnitTypeString(unsigned); StringRef AtomTypeString(unsigned Atom); StringRef GDBIndexEntryKindString(GDBIndexEntryKind Kind); StringRef GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage); diff --git a/include/llvm/Support/DynamicLibrary.h b/include/llvm/Support/DynamicLibrary.h index a7d22212dbdb..aa9bb8938ad3 100644 --- a/include/llvm/Support/DynamicLibrary.h +++ b/include/llvm/Support/DynamicLibrary.h @@ -68,6 +68,15 @@ namespace sys { static DynamicLibrary getPermanentLibrary(const char *filename, std::string *errMsg = nullptr); + /// Registers an externally loaded library. The library will be unloaded + /// when the program terminates. + /// + /// It is safe to call this function multiple times for the same library. + /// + /// \returns An empty \p DynamicLibrary if the library was already loaded. + static DynamicLibrary addPermanentLibrary(void *handle, + std::string *errMsg = nullptr); + /// This function permanently loads the dynamic library at the given path. /// Use this instead of getPermanentLibrary() when you won't need to get /// symbols from the library itself. diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index 3ea4da81ad94..33f20a809d6c 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -556,6 +556,7 @@ enum { EF_HEXAGON_MACH_V5 = 0x00000004, // Hexagon V5 EF_HEXAGON_MACH_V55 = 0x00000005, // Hexagon V55 EF_HEXAGON_MACH_V60 = 0x00000060, // Hexagon V60 + EF_HEXAGON_MACH_V62 = 0x00000062, // Hexagon V62 // Highest ISA version flags EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[11:0] @@ -566,6 +567,7 @@ enum { EF_HEXAGON_ISA_V5 = 0x00000040, // Hexagon V5 ISA EF_HEXAGON_ISA_V55 = 0x00000050, // Hexagon V55 ISA EF_HEXAGON_ISA_V60 = 0x00000060, // Hexagon V60 ISA + EF_HEXAGON_ISA_V62 = 0x00000062, // Hexagon V62 ISA }; // Hexagon-specific section indexes for common small data @@ -703,6 +705,7 @@ enum : unsigned { SHT_MIPS_REGINFO = 0x70000006, // Register usage information SHT_MIPS_OPTIONS = 0x7000000d, // General options + SHT_MIPS_DWARF = 0x7000001e, // DWARF debugging section. SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information. SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. @@ -751,21 +754,21 @@ enum : unsigned { // Start of target-specific flags. - /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped - /// together by the linker to form the constant pool and the cp register is - /// set to the start of the constant pool by the boot code. - XCORE_SHF_CP_SECTION = 0x800U, - - /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped - /// together by the linker to form the data section and the dp register is - /// set to the start of the section by the boot code. - XCORE_SHF_DP_SECTION = 0x1000U, - SHF_MASKOS = 0x0ff00000, // Bits indicating processor-specific flags. SHF_MASKPROC = 0xf0000000, + /// All sections with the "d" flag are grouped together by the linker to form + /// the data section and the dp register is set to the start of the section by + /// the boot code. + XCORE_SHF_DP_SECTION = 0x10000000, + + /// All sections with the "c" flag are grouped together by the linker to form + /// the constant pool and the cp register is set to the start of the constant + /// pool by the boot code. + XCORE_SHF_CP_SECTION = 0x20000000, + // If an object file section does not have this flag set, then it may not hold // more than 2GB and can be freely referred to in objects using smaller code // models. Otherwise, only objects using larger code models can refer to them. @@ -1312,6 +1315,19 @@ enum { VER_NEED_NONE = 0, VER_NEED_CURRENT = 1 }; // SHT_NOTE section types enum { + NT_FREEBSD_THRMISC = 7, + NT_FREEBSD_PROCSTAT_PROC = 8, + NT_FREEBSD_PROCSTAT_FILES = 9, + NT_FREEBSD_PROCSTAT_VMMAP = 10, + NT_FREEBSD_PROCSTAT_GROUPS = 11, + NT_FREEBSD_PROCSTAT_UMASK = 12, + NT_FREEBSD_PROCSTAT_RLIMIT = 13, + NT_FREEBSD_PROCSTAT_OSREL = 14, + NT_FREEBSD_PROCSTAT_PSSTRINGS = 15, + NT_FREEBSD_PROCSTAT_AUXV = 16, +}; + +enum { NT_GNU_ABI_TAG = 1, NT_GNU_HWCAP = 2, NT_GNU_BUILD_ID = 3, diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index cbe3d67b1f9e..06e089ffa166 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -17,6 +17,8 @@ #include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" +#include <stdint.h> + namespace llvm { namespace support { enum endianness {big, little, native}; @@ -33,48 +35,71 @@ namespace detail { } // end namespace detail namespace endian { +constexpr endianness system_endianness() { + return sys::IsBigEndianHost ? big : little; +} + +template <typename value_type> +inline value_type byte_swap(value_type value, endianness endian) { + if ((endian != native) && (endian != system_endianness())) + sys::swapByteOrder(value); + return value; +} + /// Swap the bytes of value to match the given endianness. template<typename value_type, endianness endian> inline value_type byte_swap(value_type value) { - if (endian != native && sys::IsBigEndianHost != (endian == big)) - sys::swapByteOrder(value); - return value; + return byte_swap(value, endian); } /// Read a value of a particular endianness from memory. -template<typename value_type, - endianness endian, - std::size_t alignment> -inline value_type read(const void *memory) { +template <typename value_type, std::size_t alignment> +inline value_type read(const void *memory, endianness endian) { value_type ret; memcpy(&ret, - LLVM_ASSUME_ALIGNED(memory, - (detail::PickAlignment<value_type, alignment>::value)), + LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), sizeof(value_type)); - return byte_swap<value_type, endian>(ret); + return byte_swap<value_type>(ret, endian); +} + +template<typename value_type, + endianness endian, + std::size_t alignment> +inline value_type read(const void *memory) { + return read<value_type, alignment>(memory, endian); } /// Read a value of a particular endianness from a buffer, and increment the /// buffer past that value. +template <typename value_type, std::size_t alignment, typename CharT> +inline value_type readNext(const CharT *&memory, endianness endian) { + value_type ret = read<value_type, alignment>(memory, endian); + memory += sizeof(value_type); + return ret; +} + template<typename value_type, endianness endian, std::size_t alignment, typename CharT> inline value_type readNext(const CharT *&memory) { - value_type ret = read<value_type, endian, alignment>(memory); - memory += sizeof(value_type); - return ret; + return readNext<value_type, alignment, CharT>(memory, endian); } /// Write a value to memory with a particular endianness. +template <typename value_type, std::size_t alignment> +inline void write(void *memory, value_type value, endianness endian) { + value = byte_swap<value_type>(value, endian); + memcpy(LLVM_ASSUME_ALIGNED( + memory, (detail::PickAlignment<value_type, alignment>::value)), + &value, sizeof(value_type)); +} + template<typename value_type, endianness endian, std::size_t alignment> inline void write(void *memory, value_type value) { - value = byte_swap<value_type, endian>(value); - memcpy(LLVM_ASSUME_ALIGNED(memory, - (detail::PickAlignment<value_type, alignment>::value)), - &value, - sizeof(value_type)); + write<value_type, alignment>(memory, value, endian); } template <typename value_type> @@ -300,10 +325,24 @@ typedef detail::packed_endian_specific_integral <int64_t, native, unaligned> unaligned_int64_t; namespace endian { +template <typename T> inline T read(const void *P, endianness E) { + return read<T, unaligned>(P, E); +} + template <typename T, endianness E> inline T read(const void *P) { return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P; } +inline uint16_t read16(const void *P, endianness E) { + return read<uint16_t>(P, E); +} +inline uint32_t read32(const void *P, endianness E) { + return read<uint32_t>(P, E); +} +inline uint64_t read64(const void *P, endianness E) { + return read<uint64_t>(P, E); +} + template <endianness E> inline uint16_t read16(const void *P) { return read<uint16_t, E>(P); } @@ -321,10 +360,24 @@ inline uint16_t read16be(const void *P) { return read16<big>(P); } inline uint32_t read32be(const void *P) { return read32<big>(P); } inline uint64_t read64be(const void *P) { return read64<big>(P); } +template <typename T> inline void write(void *P, T V, endianness E) { + write<T, unaligned>(P, V, E); +} + template <typename T, endianness E> inline void write(void *P, T V) { *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V; } +inline void write16(void *P, uint16_t V, endianness E) { + write<uint16_t>(P, V, E); +} +inline void write32(void *P, uint32_t V, endianness E) { + write<uint32_t>(P, V, E); +} +inline void write64(void *P, uint64_t V, endianness E) { + write<uint64_t>(P, V, E); +} + template <endianness E> inline void write16(void *P, uint16_t V) { write<uint16_t, E>(P, V); } diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index f13c9484b5fd..a3482f5a58b5 100644 --- a/include/llvm/Support/Error.h +++ b/include/llvm/Support/Error.h @@ -64,6 +64,12 @@ public: /// using std::error_code. It will be removed in the future. virtual std::error_code convertToErrorCode() const = 0; + // Returns the class ID for this type. + static const void *classID() { return &ID; } + + // Returns the class ID for the dynamic type of this ErrorInfoBase instance. + virtual const void *dynamicClassID() const = 0; + // Check whether this instance is a subclass of the class identified by // ClassID. virtual bool isA(const void *const ClassID) const { @@ -75,9 +81,6 @@ public: return isA(ErrorInfoT::classID()); } - // Returns the class ID for this type. - static const void *classID() { return &ID; } - private: virtual void anchor(); @@ -233,6 +236,14 @@ public: return getPtr() && getPtr()->isA(ErrT::classID()); } + /// Returns the dynamic class id of this error, or null if this is a success + /// value. + const void* dynamicClassID() const { + if (!getPtr()) + return nullptr; + return getPtr()->dynamicClassID(); + } + private: void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS @@ -316,11 +327,14 @@ template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> class ErrorInfo : public ParentErrT { public: + + static const void *classID() { return &ThisErrT::ID; } + + const void *dynamicClassID() const override { return &ThisErrT::ID; } + 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. @@ -629,6 +643,7 @@ private: /// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the /// error class type. template <class T> class LLVM_NODISCARD Expected { + template <class T1> friend class ExpectedAsOutParameter; template <class OtherT> friend class Expected; static const bool isRef = std::is_reference<T>::value; typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap; @@ -737,7 +752,7 @@ public: /// \brief Check that this Expected<T> is an error of type ErrT. template <typename ErrT> bool errorIsA() const { - return HasError && getErrorStorage()->template isA<ErrT>(); + return HasError && (*getErrorStorage())->template isA<ErrT>(); } /// \brief Take ownership of the stored error. @@ -832,6 +847,18 @@ private: return reinterpret_cast<error_type *>(ErrorStorage.buffer); } + const error_type *getErrorStorage() const { + assert(HasError && "Cannot get error when a value exists!"); + return reinterpret_cast<const error_type *>(ErrorStorage.buffer); + } + + // Used by ExpectedAsOutParameter to reset the checked flag. + void setUnchecked() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + Unchecked = true; +#endif + } + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS if (Unchecked) { @@ -858,6 +885,28 @@ private: #endif }; +/// Helper for Expected<T>s used as out-parameters. +/// +/// See ErrorAsOutParameter. +template <typename T> +class ExpectedAsOutParameter { +public: + + ExpectedAsOutParameter(Expected<T> *ValOrErr) + : ValOrErr(ValOrErr) { + if (ValOrErr) + (void)!!*ValOrErr; + } + + ~ExpectedAsOutParameter() { + if (ValOrErr) + ValOrErr->setUnchecked(); + } + +private: + Expected<T> *ValOrErr; +}; + /// This class wraps a std::error_code in a Error. /// /// This is useful if you're writing an interface that returns a Error @@ -926,6 +975,8 @@ public: void log(raw_ostream &OS) const override; std::error_code convertToErrorCode() const override; + const std::string &getMessage() const { return Msg; } + private: std::string Msg; std::error_code EC; @@ -985,6 +1036,45 @@ private: LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag = true); +/// Report a fatal error if Err is a failure value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns +/// // Error::success(). +/// Error foo(bool DoFallibleOperation); +/// +/// cantFail(foo(false)); +/// @endcode +inline void cantFail(Error Err) { + if (Err) + llvm_unreachable("Failure value returned from cantFail wrapped call"); +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns an int. +/// Expected<int> foo(bool DoFallibleOperation); +/// +/// int X = cantFail(foo(false)); +/// @endcode +template <typename T> +T cantFail(Expected<T> ValOrErr) { + if (ValOrErr) + return std::move(*ValOrErr); + else + llvm_unreachable("Failure value returned from cantFail wrapped call"); +} + } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index ad21d8af66e9..29515c231bc4 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -33,6 +33,7 @@ #include "llvm/Support/Chrono.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MD5.h" #include <cassert> #include <cstdint> #include <ctime> @@ -93,6 +94,7 @@ enum perms { set_uid_on_exe = 04000, set_gid_on_exe = 02000, sticky_bit = 01000, + all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit, perms_not_known = 0xFFFF }; @@ -141,70 +143,61 @@ public: /// a platform-specific member to store the result. class file_status { + friend bool equivalent(file_status A, file_status B); + #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; + dev_t fs_st_dev = 0; + nlink_t fs_st_nlinks = 0; + ino_t fs_st_ino = 0; + time_t fs_st_atime = 0; + time_t fs_st_mtime = 0; + uid_t fs_st_uid = 0; + gid_t fs_st_gid = 0; + off_t fs_st_size = 0; #elif defined (LLVM_ON_WIN32) - uint32_t LastAccessedTimeHigh; - uint32_t LastAccessedTimeLow; - uint32_t LastWriteTimeHigh; - uint32_t LastWriteTimeLow; - uint32_t VolumeSerialNumber; - uint32_t FileSizeHigh; - uint32_t FileSizeLow; - uint32_t FileIndexHigh; - uint32_t FileIndexLow; + uint32_t NumLinks = 0; + uint32_t LastAccessedTimeHigh = 0; + uint32_t LastAccessedTimeLow = 0; + uint32_t LastWriteTimeHigh = 0; + uint32_t LastWriteTimeLow = 0; + uint32_t VolumeSerialNumber = 0; + uint32_t FileSizeHigh = 0; + uint32_t FileSizeLow = 0; + uint32_t FileIndexHigh = 0; + uint32_t FileIndexLow = 0; #endif - friend bool equivalent(file_status A, file_status B); - file_type Type; - perms Perms; + file_type Type = file_type::status_error; + perms Perms = perms_not_known; public: #if defined(LLVM_ON_UNIX) - 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_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 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) {} + file_status() = default; + + file_status(file_type Type) : Type(Type) {} + + file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino, + time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size) + : fs_st_dev(Dev), fs_st_nlinks(Links), 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() - : 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) - : 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 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), + file_status() = default; + + file_status(file_type Type) : Type(Type) {} + + file_status(file_type Type, perms Perms, uint32_t LinkCount, + 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) + : NumLinks(LinkCount), LastAccessedTimeHigh(LastAccessTimeHigh), + LastAccessedTimeLow(LastAccessTimeLow), LastWriteTimeHigh(LastWriteTimeHigh), LastWriteTimeLow(LastWriteTimeLow), VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), - FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} + FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {} #endif // getters @@ -213,6 +206,7 @@ public: TimePoint<> getLastAccessedTime() const; TimePoint<> getLastModificationTime() const; UniqueID getUniqueID() const; + uint32_t getLinkCount() const; #if defined(LLVM_ON_UNIX) uint32_t getUser() const { return fs_st_uid; } @@ -222,9 +216,11 @@ public: uint32_t getUser() const { return 9999; // Not applicable to Windows, so... } + uint32_t getGroup() const { return 9999; // Not applicable to Windows, so... } + uint64_t getSize() const { return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; } @@ -271,12 +267,12 @@ struct file_magic { return V != unknown; } - file_magic() : V(unknown) {} + file_magic() = default; file_magic(Impl V) : V(V) {} operator Impl() const { return V; } private: - Impl V; + Impl V = unknown; }; /// @} @@ -350,6 +346,16 @@ std::error_code create_link(const Twine &to, const Twine &from); /// specific error_code. std::error_code create_hard_link(const Twine &to, const Twine &from); +/// @brief Collapse all . and .. patterns, resolve all symlinks, and optionally +/// expand ~ expressions to the user's home directory. +/// +/// @param path The path to resolve. +/// @param output The location to store the resolved path. +/// @param expand_tilde If true, resolves ~ expressions to the user's home +/// directory. +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output, + bool expand_tilde = false); + /// @brief Get the current path. /// /// @param result Holds the current path on return. @@ -357,6 +363,13 @@ std::error_code create_hard_link(const Twine &to, const Twine &from); /// otherwise a platform-specific error_code. std::error_code current_path(SmallVectorImpl<char> &result); +/// @brief Set the current path. +/// +/// @param path The path to set. +/// @returns errc::success if the current path was successfully set, +/// otherwise a platform-specific error_code. +std::error_code set_current_path(const Twine &path); + /// @brief Remove path. Equivalent to POSIX remove(). /// /// @param path Input path. @@ -365,6 +378,13 @@ std::error_code current_path(SmallVectorImpl<char> &result); /// returns error if the file didn't exist. std::error_code remove(const Twine &path, bool IgnoreNonExisting = true); +/// @brief Recursively delete a directory. +/// +/// @param path Input path. +/// @returns errc::success if path has been removed or didn't exist, otherwise a +/// platform-specific error code. +std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true); + /// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). /// /// @param from The path to rename from. @@ -385,6 +405,16 @@ std::error_code copy_file(const Twine &From, const Twine &To); /// platform-specific error_code. std::error_code resize_file(int FD, uint64_t Size); +/// @brief Compute an MD5 hash of a file's contents. +/// +/// @param FD Input file descriptor. +/// @returns An MD5Result with the hash computed, if successful, otherwise a +/// std::error_code. +ErrorOr<MD5::MD5Result> md5_contents(int FD); + +/// @brief Version of compute_md5 that doesn't require an open file descriptor. +ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path); + /// @} /// @name Physical Observers /// @{ @@ -457,6 +487,40 @@ inline bool equivalent(const Twine &A, const Twine &B) { return !equivalent(A, B, result) && result; } +/// @brief Is the file mounted on a local filesystem? +/// +/// @param path Input path. +/// @param result Set to true if \a path is on fixed media such as a hard disk, +/// false if it is not. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +std::error_code is_local(const Twine &path, bool &result); + +/// @brief Version of is_local accepting an open file descriptor. +std::error_code is_local(int FD, bool &result); + +/// @brief Simpler version of is_local for clients that don't need to +/// differentiate between an error and false. +inline bool is_local(const Twine &Path) { + bool Result; + return !is_local(Path, Result) && Result; +} + +/// @brief Simpler version of is_local accepting an open file descriptor for +/// clients that don't need to differentiate between an error and false. +inline bool is_local(int FD) { + bool Result; + return !is_local(FD, Result) && Result; +} + +/// @brief Does status represent a directory? +/// +/// @param Path The path to get the type of. +/// @param Follow For symbolic links, indicates whether to return the file type +/// of the link itself, or of the target. +/// @returns A value from the file_type enumeration indicating the type of file. +file_type get_file_type(const Twine &Path, bool Follow = true); + /// @brief Does status represent a directory? /// /// @param status A file_status previously returned from status. @@ -466,8 +530,8 @@ bool is_directory(file_status status); /// @brief Is path a directory? /// /// @param path Input path. -/// @param result Set to true if \a path is a directory, false if it is not. -/// Undefined otherwise. +/// @param result Set to true if \a path is a directory (after following +/// symlinks, false if it is not. Undefined otherwise. /// @returns errc::success if result has been successfully set, otherwise a /// platform-specific error_code. std::error_code is_directory(const Twine &path, bool &result); @@ -488,8 +552,8 @@ bool is_regular_file(file_status status); /// @brief Is path a regular file? /// /// @param path Input path. -/// @param result Set to true if \a path is a regular file, false if it is not. -/// Undefined otherwise. +/// @param result Set to true if \a path is a regular file (after following +/// symlinks), false if it is not. Undefined otherwise. /// @returns errc::success if result has been successfully set, otherwise a /// platform-specific error_code. std::error_code is_regular_file(const Twine &path, bool &result); @@ -503,8 +567,32 @@ inline bool is_regular_file(const Twine &Path) { return Result; } +/// @brief Does status represent a symlink file? +/// +/// @param status A file_status previously returned from status. +/// @returns status_known(status) && status.type() == file_type::symlink_file. +bool is_symlink_file(file_status status); + +/// @brief Is path a symlink file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a symlink file, false if it is not. +/// Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_symlink_file(const Twine &path, bool &result); + +/// @brief Simpler version of is_symlink_file for clients that don't need to +/// differentiate between an error and false. +inline bool is_symlink_file(const Twine &Path) { + bool Result; + if (is_symlink_file(Path, Result)) + return false; + return Result; +} + /// @brief Does this status represent something that exists but is not a -/// directory, regular file, or symlink? +/// directory or regular file? /// /// @param status A file_status previously returned from status. /// @returns exists(s) && !is_regular_file(s) && !is_directory(s) @@ -524,13 +612,37 @@ std::error_code is_other(const Twine &path, bool &result); /// /// @param path Input path. /// @param result Set to the file status. +/// @param follow When true, follows symlinks. Otherwise, the symlink itself is +/// statted. /// @returns errc::success if result has been successfully set, otherwise a /// platform-specific error_code. -std::error_code status(const Twine &path, file_status &result); +std::error_code status(const Twine &path, file_status &result, + bool follow = true); /// @brief A version for when a file descriptor is already available. std::error_code status(int FD, file_status &Result); +/// @brief Set file permissions. +/// +/// @param Path File to set permissions on. +/// @param Permissions New file permissions. +/// @returns errc::success if the permissions were successfully set, otherwise +/// a platform-specific error_code. +/// @note On Windows, all permissions except *_write are ignored. Using any of +/// owner_write, group_write, or all_write will make the file writable. +/// Otherwise, the file will be marked as read-only. +std::error_code setPermissions(const Twine &Path, perms Permissions); + +/// @brief Get file permissions. +/// +/// @param Path File to get permissions from. +/// @returns the permissions if they were successfully retrieved, otherwise a +/// platform-specific error_code. +/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY +/// attribute, all_all will be returned. Otherwise, all_read | all_exe +/// will be returned. +ErrorOr<perms> getPermissions(const Twine &Path); + /// @brief Get file size. /// /// @param Path Input path. @@ -735,12 +847,13 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr); /// called. class directory_entry { std::string Path; + bool FollowSymlinks; mutable file_status Status; public: - explicit directory_entry(const Twine &path, file_status st = file_status()) - : Path(path.str()) - , Status(st) {} + explicit directory_entry(const Twine &path, bool follow_symlinks = true, + file_status st = file_status()) + : Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {} directory_entry() = default; @@ -763,9 +876,10 @@ public: }; namespace detail { + struct DirIterState; - std::error_code directory_iterator_construct(DirIterState &, StringRef); + std::error_code directory_iterator_construct(DirIterState &, StringRef, bool); std::error_code directory_iterator_increment(DirIterState &); std::error_code directory_iterator_destruct(DirIterState &); @@ -778,6 +892,7 @@ namespace detail { intptr_t IterationHandle = 0; directory_entry CurrentEntry; }; + } // end namespace detail /// directory_iterator - Iterates through the entries in path. There is no @@ -785,18 +900,24 @@ namespace detail { /// it call report_fatal_error on error. class directory_iterator { std::shared_ptr<detail::DirIterState> State; + bool FollowSymlinks = true; public: - explicit directory_iterator(const Twine &path, std::error_code &ec) { + explicit directory_iterator(const Twine &path, std::error_code &ec, + bool follow_symlinks = true) + : FollowSymlinks(follow_symlinks) { State = std::make_shared<detail::DirIterState>(); SmallString<128> path_storage; - ec = detail::directory_iterator_construct(*State, - path.toStringRef(path_storage)); + ec = detail::directory_iterator_construct( + *State, path.toStringRef(path_storage), FollowSymlinks); } - explicit directory_iterator(const directory_entry &de, std::error_code &ec) { + explicit directory_iterator(const directory_entry &de, std::error_code &ec, + bool follow_symlinks = true) + : FollowSymlinks(follow_symlinks) { State = std::make_shared<detail::DirIterState>(); - ec = detail::directory_iterator_construct(*State, de.path()); + ec = + detail::directory_iterator_construct(*State, de.path(), FollowSymlinks); } /// Construct end iterator. @@ -829,24 +950,29 @@ public: }; namespace detail { + /// Keeps state for the recursive_directory_iterator. struct RecDirIterState { std::stack<directory_iterator, std::vector<directory_iterator>> Stack; uint16_t Level = 0; bool HasNoPushRequest = false; }; + } // end namespace detail /// recursive_directory_iterator - Same as directory_iterator except for it /// recurses down into child directories. class recursive_directory_iterator { std::shared_ptr<detail::RecDirIterState> State; + bool Follow; public: recursive_directory_iterator() = default; - explicit recursive_directory_iterator(const Twine &path, std::error_code &ec) - : State(std::make_shared<detail::RecDirIterState>()) { - State->Stack.push(directory_iterator(path, ec)); + explicit recursive_directory_iterator(const Twine &path, std::error_code &ec, + bool follow_symlinks = true) + : State(std::make_shared<detail::RecDirIterState>()), + Follow(follow_symlinks) { + State->Stack.push(directory_iterator(path, ec, Follow)); if (State->Stack.top() == directory_iterator()) State.reset(); } @@ -861,7 +987,7 @@ public: file_status st; if ((ec = State->Stack.top()->status(st))) return *this; if (is_directory(st)) { - State->Stack.push(directory_iterator(*State->Stack.top(), ec)); + State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow)); if (ec) return *this; if (State->Stack.top() != end_itr) { ++State->Level; diff --git a/include/llvm/Support/FormatAdapters.h b/include/llvm/Support/FormatAdapters.h index 7bacd2e17135..698e134b328d 100644 --- a/include/llvm/Support/FormatAdapters.h +++ b/include/llvm/Support/FormatAdapters.h @@ -22,9 +22,6 @@ protected: explicit FormatAdapter(T &&Item) : Item(Item) {} T Item; - - static_assert(!detail::uses_missing_provider<T>::value, - "Item does not have a format provider!"); }; namespace detail { diff --git a/include/llvm/Support/FormatProviders.h b/include/llvm/Support/FormatProviders.h index 1f0768c3ab08..4e57034ff98e 100644 --- a/include/llvm/Support/FormatProviders.h +++ b/include/llvm/Support/FormatProviders.h @@ -18,6 +18,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/FormatVariadicDetails.h" #include "llvm/Support/NativeFormatting.h" @@ -45,9 +46,8 @@ struct is_cstring template <typename T> struct use_string_formatter - : public std::integral_constant< - bool, is_one_of<T, llvm::StringRef, std::string>::value || - is_cstring<T>::value> {}; + : public std::integral_constant<bool, + std::is_convertible<T, llvm::StringRef>::value> {}; template <typename T> struct use_pointer_formatter @@ -205,11 +205,22 @@ struct format_provider< if (!Style.empty() && Style.getAsInteger(10, N)) { assert(false && "Style is not a valid integer"); } - llvm::StringRef S(V); + llvm::StringRef S = V; Stream << S.substr(0, N); } }; +/// Implementation of format_provider<T> for llvm::Twine. +/// +/// This follows the same rules as the string formatter. + +template <> struct format_provider<Twine> { + static void format(const Twine &V, llvm::raw_ostream &Stream, + StringRef Style) { + format_provider<std::string>::format(V.str(), Stream, Style); + } +}; + /// Implementation of format_provider<T> for characters. /// /// The options string of a character type has the grammar: @@ -359,8 +370,7 @@ template <typename IterT> class format_provider<llvm::iterator_range<IterT>> { return Default; } - std::vector<const char *> Delims = {"[]", "<>", "()"}; - for (const char *D : Delims) { + for (const char *D : {"[]", "<>", "()"}) { if (Style.front() != D[0]) continue; size_t End = Style.find_first_of(D[1]); diff --git a/include/llvm/Support/FormatVariadic.h b/include/llvm/Support/FormatVariadic.h index e5f5c9615cb6..3a4668687cc9 100644 --- a/include/llvm/Support/FormatVariadic.h +++ b/include/llvm/Support/FormatVariadic.h @@ -196,7 +196,7 @@ public: // "}}" to print a literal '}'. // // ===Parameter Indexing=== -// `index` specifies the index of the paramter in the parameter pack to format +// `index` specifies the index of the parameter in the parameter pack to format // into the output. Note that it is possible to refer to the same parameter // index multiple times in a given format string. This makes it possible to // output the same value multiple times without passing it multiple times to the diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h index f297fe609d2a..73fddca8e35b 100644 --- a/include/llvm/Support/GCOV.h +++ b/include/llvm/Support/GCOV.h @@ -63,7 +63,7 @@ struct Options { /// read operations. class GCOVBuffer { public: - GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {} + GCOVBuffer(MemoryBuffer *B) : Buffer(B) {} /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer. bool readGCNOFormat() { @@ -234,39 +234,38 @@ public: private: MemoryBuffer *Buffer; - uint64_t Cursor; + uint64_t Cursor = 0; }; /// GCOVFile - Collects coverage information for one pair of coverage file /// (.gcno and .gcda). class GCOVFile { public: - GCOVFile() - : GCNOInitialized(false), Checksum(0), RunCount(0), - ProgramCount(0) {} + GCOVFile() = default; bool readGCNO(GCOVBuffer &Buffer); bool readGCDA(GCOVBuffer &Buffer); uint32_t getChecksum() const { return Checksum; } + void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: - bool GCNOInitialized; + bool GCNOInitialized = false; GCOV::GCOVVersion Version; - uint32_t Checksum; + uint32_t Checksum = 0; SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions; - uint32_t RunCount; - uint32_t ProgramCount; + uint32_t RunCount = 0; + uint32_t ProgramCount = 0; }; /// GCOVEdge - Collects edge information. struct GCOVEdge { - GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D), Count(0) {} + GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {} GCOVBlock &Src; GCOVBlock &Dst; - uint64_t Count; + uint64_t Count = 0; }; /// GCOVFunction - Collects function information. @@ -275,7 +274,8 @@ public: typedef pointee_iterator<SmallVectorImpl< std::unique_ptr<GCOVBlock>>::const_iterator> BlockIterator; - GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {} + GCOVFunction(GCOVFile &P) : Parent(P) {} + bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); StringRef getName() const { return Name; } @@ -290,14 +290,15 @@ public: return make_range(block_begin(), block_end()); } + void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: GCOVFile &Parent; - uint32_t Ident; + uint32_t Ident = 0; uint32_t Checksum; - uint32_t LineNumber; + uint32_t LineNumber = 0; StringRef Name; StringRef Filename; SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks; @@ -307,10 +308,10 @@ private: /// GCOVBlock - Collects block information. class GCOVBlock { struct EdgeWeight { - EdgeWeight(GCOVBlock *D) : Dst(D), Count(0) {} + EdgeWeight(GCOVBlock *D) : Dst(D) {} GCOVBlock *Dst; - uint64_t Count; + uint64_t Count = 0; }; struct SortDstEdgesFunctor { @@ -322,8 +323,7 @@ class GCOVBlock { public: typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator; - GCOVBlock(GCOVFunction &P, uint32_t N) - : Parent(P), Number(N), Counter(0), DstEdgesAreSorted(true) {} + GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {} ~GCOVBlock(); const GCOVFunction &getParent() const { return Parent; } @@ -361,14 +361,15 @@ public: return make_range(dst_begin(), dst_end()); } + void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: GCOVFunction &Parent; uint32_t Number; - uint64_t Counter; - bool DstEdgesAreSorted; + uint64_t Counter = 0; + bool DstEdgesAreSorted = true; SmallVector<GCOVEdge *, 16> SrcEdges; SmallVector<GCOVEdge *, 16> DstEdges; SmallVector<uint32_t, 16> Lines; @@ -386,30 +387,28 @@ class FileInfo { typedef DenseMap<uint32_t, BlockVector> BlockLines; struct LineData { - LineData() : LastLine(0) {} + LineData() = default; + BlockLines Blocks; FunctionLines Functions; - uint32_t LastLine; + uint32_t LastLine = 0; }; struct GCOVCoverage { - GCOVCoverage(StringRef Name) - : Name(Name), LogicalLines(0), LinesExec(0), Branches(0), - BranchesExec(0), BranchesTaken(0) {} + GCOVCoverage(StringRef Name) : Name(Name) {} StringRef Name; - uint32_t LogicalLines; - uint32_t LinesExec; + uint32_t LogicalLines = 0; + uint32_t LinesExec = 0; - uint32_t Branches; - uint32_t BranchesExec; - uint32_t BranchesTaken; + uint32_t Branches = 0; + uint32_t BranchesExec = 0; + uint32_t BranchesTaken = 0; }; public: - FileInfo(const GCOV::Options &Options) - : Options(Options), RunCount(0), ProgramCount(0) {} + FileInfo(const GCOV::Options &Options) : Options(Options) {} void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) { if (Line > LineInfo[Filename].LastLine) @@ -446,8 +445,8 @@ private: const GCOV::Options &Options; StringMap<LineData> LineInfo; - uint32_t RunCount; - uint32_t ProgramCount; + uint32_t RunCount = 0; + uint32_t ProgramCount = 0; typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> FileCoverageList; typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap; diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index 6e6ee4001644..20f3ffdf3aab 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -13,7 +13,7 @@ /// dominance queries on the CFG, but is fully generic w.r.t. the underlying /// graph types. /// -/// Unlike ADT/* graph algorithms, generic dominator tree has more reuiqrement +/// Unlike ADT/* graph algorithms, generic dominator tree has more requirements /// on the graph's NodeRef. The NodeRef should be a pointer and, depending on /// the implementation, e.g. NodeRef->getParent() return the parent node. /// @@ -25,14 +25,19 @@ #define LLVM_SUPPORT_GENERICDOMTREE_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Compiler.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> namespace llvm { @@ -47,7 +52,7 @@ template <typename GT> struct DominatorTreeBaseTraits { typename std::remove_pointer<typename GT::NodeRef>::type>; }; -} // End namespace detail +} // end namespace detail template <typename GT> using DominatorTreeBaseByGraphTraits = @@ -59,13 +64,16 @@ template <class NodeT> class DominatorBase { protected: std::vector<NodeT *> Roots; bool IsPostDominators; + explicit DominatorBase(bool isPostDom) : Roots(), IsPostDominators(isPostDom) {} + DominatorBase(DominatorBase &&Arg) : Roots(std::move(Arg.Roots)), IsPostDominators(std::move(Arg.IsPostDominators)) { Arg.Roots.clear(); } + DominatorBase &operator=(DominatorBase &&RHS) { Roots = std::move(RHS.Roots); IsPostDominators = std::move(RHS.IsPostDominators); @@ -85,19 +93,21 @@ public: bool isPostDominator() const { return IsPostDominators; } }; -struct PostDominatorTree; - /// \brief Base class for the actual dominator tree node. template <class NodeT> class DomTreeNodeBase { + friend struct PostDominatorTree; + template <class N> friend class DominatorTreeBase; + NodeT *TheBB; DomTreeNodeBase<NodeT> *IDom; std::vector<DomTreeNodeBase<NodeT> *> Children; - mutable int DFSNumIn, DFSNumOut; - - template <class N> friend class DominatorTreeBase; - friend struct PostDominatorTree; + mutable int DFSNumIn = -1; + mutable int DFSNumOut = -1; public: + DomTreeNodeBase(NodeT *BB, DomTreeNodeBase<NodeT> *iDom) + : TheBB(BB), IDom(iDom) {} + typedef typename std::vector<DomTreeNodeBase<NodeT> *>::iterator iterator; typedef typename std::vector<DomTreeNodeBase<NodeT> *>::const_iterator const_iterator; @@ -109,13 +119,11 @@ public: NodeT *getBlock() const { return TheBB; } DomTreeNodeBase<NodeT> *getIDom() const { return IDom; } + const std::vector<DomTreeNodeBase<NodeT> *> &getChildren() const { return Children; } - DomTreeNodeBase(NodeT *BB, DomTreeNodeBase<NodeT> *iDom) - : TheBB(BB), IDom(iDom), DFSNumIn(-1), DFSNumOut(-1) {} - std::unique_ptr<DomTreeNodeBase<NodeT>> addChild(std::unique_ptr<DomTreeNodeBase<NodeT>> C) { Children.push_back(C.get()); @@ -206,9 +214,6 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<N>> &DT, FuncT &F); /// This class is a generic template over graph nodes. It is instantiated for /// various graphs in the LLVM IR or in the code generator. template <class NodeT> class DominatorTreeBase : public DominatorBase<NodeT> { - DominatorTreeBase(const DominatorTreeBase &) = delete; - DominatorTreeBase &operator=(const DominatorTreeBase &) = delete; - bool dominatedBySlowTreeWalk(const DomTreeNodeBase<NodeT> *A, const DomTreeNodeBase<NodeT> *B) const { assert(A != B); @@ -239,16 +244,16 @@ protected: DomTreeNodeMapType DomTreeNodes; DomTreeNodeBase<NodeT> *RootNode; - mutable bool DFSInfoValid; - mutable unsigned int SlowQueries; + mutable bool DFSInfoValid = false; + mutable unsigned int SlowQueries = 0; // Information record used during immediate dominators computation. struct InfoRec { - unsigned DFSNum; - unsigned Parent; - unsigned Semi; - NodeT *Label; + unsigned DFSNum = 0; + unsigned Parent = 0; + unsigned Semi = 0; + NodeT *Label = nullptr; - InfoRec() : DFSNum(0), Parent(0), Semi(0), Label(nullptr) {} + InfoRec() = default; }; DenseMap<NodeT *, NodeT *> IDoms; @@ -336,7 +341,7 @@ protected: public: explicit DominatorTreeBase(bool isPostDom) - : DominatorBase<NodeT>(isPostDom), DFSInfoValid(false), SlowQueries(0) {} + : DominatorBase<NodeT>(isPostDom) {} DominatorTreeBase(DominatorTreeBase &&Arg) : DominatorBase<NodeT>( @@ -348,6 +353,7 @@ public: Vertex(std::move(Arg.Vertex)), Info(std::move(Arg.Info)) { Arg.wipe(); } + DominatorTreeBase &operator=(DominatorTreeBase &&RHS) { DominatorBase<NodeT>::operator=( std::move(static_cast<DominatorBase<NodeT> &>(RHS))); @@ -362,6 +368,9 @@ public: return *this; } + DominatorTreeBase(const DominatorTreeBase &) = delete; + DominatorTreeBase &operator=(const DominatorTreeBase &) = delete; + /// compare - Return false if the other dominator tree base matches this /// dominator tree base. Otherwise return true. bool compare(const DominatorTreeBase &Other) const { @@ -684,6 +693,10 @@ protected: unsigned LastLinked); template <class GraphT> + friend unsigned ReverseDFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, + typename GraphT::NodeRef V, unsigned N); + + template <class GraphT> friend unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, typename GraphT::NodeRef V, unsigned N); @@ -716,7 +729,6 @@ public: /// updateDFSNumbers - Assign In and Out numbers to the nodes while walking /// dominator tree in dfs order. void updateDFSNumbers() const { - if (DFSInfoValid) { SlowQueries = 0; return; @@ -778,11 +790,9 @@ public: Calculate<FT, NodeT *>(*this, F); } else { // Initialize the roots list - for (typename TraitsTy::nodes_iterator I = TraitsTy::nodes_begin(&F), - E = TraitsTy::nodes_end(&F); - I != E; ++I) - if (TraitsTy::child_begin(*I) == TraitsTy::child_end(*I)) - addRoot(*I); + for (auto *Node : nodes(&F)) + if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node)) + addRoot(Node); Calculate<FT, Inverse<NodeT *>>(*this, F); } @@ -815,6 +825,6 @@ bool DominatorTreeBase<NodeT>::properlyDominates(const NodeT *A, getNode(const_cast<NodeT *>(B))); } -} +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_GENERICDOMTREE_H diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h index 54e55cc1a32e..c1d757f3ab6a 100644 --- a/include/llvm/Support/GenericDomTreeConstruction.h +++ b/include/llvm/Support/GenericDomTreeConstruction.h @@ -24,82 +24,77 @@ #ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H #define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/GenericDomTree.h" namespace llvm { -template <class GraphT> -unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, - typename GraphT::NodeRef V, unsigned N) { - // This is more understandable as a recursive algorithm, but we can't use the - // recursive algorithm due to stack depth issues. Keep it here for - // documentation purposes. -#if 0 - InfoRec &VInfo = DT.Info[DT.Roots[i]]; - VInfo.DFSNum = VInfo.Semi = ++N; - VInfo.Label = V; - - Vertex.push_back(V); // Vertex[n] = V; - - for (succ_iterator SI = succ_begin(V), E = succ_end(V); SI != E; ++SI) { - InfoRec &SuccVInfo = DT.Info[*SI]; - if (SuccVInfo.Semi == 0) { - SuccVInfo.Parent = V; - N = DTDFSPass(DT, *SI, N); - } +// External storage for depth first iterator that reuses the info lookup map +// domtree already has. We don't have a set, but a map instead, so we are +// converting the one argument insert calls. +template <class NodeRef, class InfoType> struct df_iterator_dom_storage { +public: + typedef DenseMap<NodeRef, InfoType> BaseSet; + df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {} + + typedef typename BaseSet::iterator iterator; + std::pair<iterator, bool> insert(NodeRef N) { + return Storage.insert({N, InfoType()}); } -#else - bool IsChildOfArtificialExit = (N != 0); + void completed(NodeRef) {} - SmallVector< - std::pair<typename GraphT::NodeRef, typename GraphT::ChildIteratorType>, - 32> - Worklist; - Worklist.push_back(std::make_pair(V, GraphT::child_begin(V))); - while (!Worklist.empty()) { - typename GraphT::NodeRef BB = Worklist.back().first; - typename GraphT::ChildIteratorType NextSucc = Worklist.back().second; +private: + BaseSet &Storage; +}; +template <class GraphT> +unsigned ReverseDFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, + typename GraphT::NodeRef V, unsigned N) { + df_iterator_dom_storage< + typename GraphT::NodeRef, + typename DominatorTreeBaseByGraphTraits<GraphT>::InfoRec> + DFStorage(DT.Info); + bool IsChildOfArtificialExit = (N != 0); + for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage); + I != E; ++I) { + typename GraphT::NodeRef BB = *I; auto &BBInfo = DT.Info[BB]; + BBInfo.DFSNum = BBInfo.Semi = ++N; + BBInfo.Label = BB; + // Set the parent to the top of the visited stack. The stack includes us, + // and is 1 based, so we subtract to account for both of these. + if (I.getPathLength() > 1) + BBInfo.Parent = DT.Info[I.getPath(I.getPathLength() - 2)].DFSNum; + DT.Vertex.push_back(BB); // Vertex[n] = V; - // First time we visited this BB? - if (NextSucc == GraphT::child_begin(BB)) { - BBInfo.DFSNum = BBInfo.Semi = ++N; - BBInfo.Label = BB; - - DT.Vertex.push_back(BB); // Vertex[n] = V; - - if (IsChildOfArtificialExit) - BBInfo.Parent = 1; - - IsChildOfArtificialExit = false; - } - - // store the DFS number of the current BB - the reference to BBInfo might - // get invalidated when processing the successors. - unsigned BBDFSNum = BBInfo.DFSNum; - - // If we are done with this block, remove it from the worklist. - if (NextSucc == GraphT::child_end(BB)) { - Worklist.pop_back(); - continue; - } - - // Increment the successor number for the next time we get to it. - ++Worklist.back().second; - - // Visit the successor next, if it isn't already visited. - typename GraphT::NodeRef Succ = *NextSucc; + if (IsChildOfArtificialExit) + BBInfo.Parent = 1; - auto &SuccVInfo = DT.Info[Succ]; - if (SuccVInfo.Semi == 0) { - SuccVInfo.Parent = BBDFSNum; - Worklist.push_back(std::make_pair(Succ, GraphT::child_begin(Succ))); - } + IsChildOfArtificialExit = false; } -#endif - return N; + return N; +} +template <class GraphT> +unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, + typename GraphT::NodeRef V, unsigned N) { + df_iterator_dom_storage< + typename GraphT::NodeRef, + typename DominatorTreeBaseByGraphTraits<GraphT>::InfoRec> + DFStorage(DT.Info); + for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage); + I != E; ++I) { + typename GraphT::NodeRef BB = *I; + auto &BBInfo = DT.Info[BB]; + BBInfo.DFSNum = BBInfo.Semi = ++N; + BBInfo.Label = BB; + // Set the parent to the top of the visited stack. The stack includes us, + // and is 1 based, so we subtract to account for both of these. + if (I.getPathLength() > 1) + BBInfo.Parent = DT.Info[I.getPath(I.getPathLength() - 2)].DFSNum; + DT.Vertex.push_back(BB); // Vertex[n] = V; + } + return N; } template <class GraphT> @@ -163,9 +158,13 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT, // Step #1: Number blocks in depth-first order and initialize variables used // in later stages of the algorithm. - for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size()); - i != e; ++i) - N = DFSPass<GraphT>(DT, DT.Roots[i], N); + if (DT.isPostDominator()){ + for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size()); + i != e; ++i) + N = ReverseDFSPass<GraphT>(DT, DT.Roots[i], N); + } else { + N = DFSPass<GraphT>(DT, DT.Roots[0], N); + } // it might be that some blocks did not get a DFS number (e.g., blocks of // infinite loops). In these cases an artificial exit node is required. @@ -201,17 +200,12 @@ void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT, // initialize the semi dominator to point to the parent node WInfo.Semi = WInfo.Parent; - typedef GraphTraits<Inverse<NodeT> > InvTraits; - for (typename InvTraits::ChildIteratorType CI = - InvTraits::child_begin(W), - E = InvTraits::child_end(W); CI != E; ++CI) { - typename InvTraits::NodeRef N = *CI; - if (DT.Info.count(N)) { // Only if this predecessor is reachable! + for (const auto &N : inverse_children<NodeT>(W)) + if (DT.Info.count(N)) { // Only if this predecessor is reachable! unsigned SemiU = DT.Info[Eval<GraphT>(DT, N, i + 1)].Semi; if (SemiU < WInfo.Semi) WInfo.Semi = SemiU; } - } // If V is a non-root vertex and sdom(V) = parent(V), then idom(V) is // necessarily parent(V). In this case, set idom(V) here and avoid placing diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h index 9df584c68c0d..89986fdae971 100644 --- a/include/llvm/Support/Host.h +++ b/include/llvm/Support/Host.h @@ -15,6 +15,7 @@ #define LLVM_SUPPORT_HOST_H #include "llvm/ADT/StringMap.h" +#include "llvm/Support/MemoryBuffer.h" #if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) #include <endian.h> @@ -32,9 +33,9 @@ namespace llvm { namespace sys { #if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN - static const bool IsBigEndianHost = true; +constexpr bool IsBigEndianHost = true; #else - static const bool IsBigEndianHost = false; +constexpr bool IsBigEndianHost = false; #endif static const bool IsLittleEndianHost = !IsBigEndianHost; @@ -75,6 +76,13 @@ namespace sys { /// from thread::hardware_concurrency(), which includes hyperthreads). /// Returns -1 if unknown for the current host system. int getHostNumPhysicalCores(); + + namespace detail { + /// Helper functions to extract HostCPUName from /proc/cpuinfo on linux. + StringRef getHostCPUNameForPowerPC(const StringRef &ProcCpuinfoContent); + StringRef getHostCPUNameForARM(const StringRef &ProcCpuinfoContent); + StringRef getHostCPUNameForS390x(const StringRef &ProcCpuinfoContent); + } } } diff --git a/include/llvm/Support/LEB128.h b/include/llvm/Support/LEB128.h index 6a95432ca2d9..ff775f3b7b36 100644 --- a/include/llvm/Support/LEB128.h +++ b/include/llvm/Support/LEB128.h @@ -20,7 +20,8 @@ namespace llvm { /// Utility function to encode a SLEB128 value to an output stream. -inline void encodeSLEB128(int64_t Value, raw_ostream &OS) { +inline void encodeSLEB128(int64_t Value, raw_ostream &OS, + unsigned Padding = 0) { bool More; do { uint8_t Byte = Value & 0x7f; @@ -28,10 +29,45 @@ inline void encodeSLEB128(int64_t Value, raw_ostream &OS) { Value >>= 7; More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || ((Value == -1) && ((Byte & 0x40) != 0)))); - if (More) + if (More || Padding != 0) Byte |= 0x80; // Mark this byte to show that more bytes will follow. OS << char(Byte); } while (More); + + // Pad with 0x80 and emit a terminating byte at the end. + if (Padding != 0) { + uint8_t PadValue = Value < 0 ? 0x7f : 0x00; + for (; Padding != 1; --Padding) + OS << char(PadValue | 0x80); + OS << char(PadValue); + } +} + +/// Utility function to encode a SLEB128 value to a buffer. Returns +/// the length in bytes of the encoded value. +inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, + unsigned Padding = 0) { + uint8_t *orig_p = p; + bool More; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + if (More || Padding != 0) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + *p++ = Byte; + } while (More); + + // Pad with 0x80 and emit a terminating byte at the end. + if (Padding != 0) { + uint8_t PadValue = Value < 0 ? 0x7f : 0x00; + for (; Padding != 1; --Padding) + *p++ = (PadValue | 0x80); + *p++ = PadValue; + } + return (unsigned)(p - orig_p); } /// Utility function to encode a ULEB128 value to an output stream. @@ -77,11 +113,30 @@ inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, /// Utility function to decode a ULEB128 value. -inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr) { +inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, + const uint8_t *end = nullptr, + const char **error = nullptr) { const uint8_t *orig_p = p; uint64_t Value = 0; unsigned Shift = 0; + if(error) + *error = nullptr; do { + if(end && p == end){ + if(error) + *error = "malformed uleb128, extends past end"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } + uint64_t Slice = *p & 0x7f; + if(Shift >= 64 || Slice << Shift >> Shift != Slice){ + if(error) + *error = "uleb128 too big for uint64"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } Value += uint64_t(*p & 0x7f) << Shift; Shift += 7; } while (*p++ >= 128); @@ -91,12 +146,21 @@ inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr) { } /// Utility function to decode a SLEB128 value. -inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr) { +inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, + const uint8_t *end = nullptr, + const char **error = nullptr) { const uint8_t *orig_p = p; int64_t Value = 0; unsigned Shift = 0; uint8_t Byte; do { + if(end && p == end){ + if(error) + *error = "malformed sleb128, extends past end"; + if (n) + *n = (unsigned)(p - orig_p); + return 0; + } Byte = *p++; Value |= ((Byte & 0x7f) << Shift); Shift += 7; diff --git a/include/llvm/Support/LowLevelTypeImpl.h b/include/llvm/Support/LowLevelTypeImpl.h new file mode 100644 index 000000000000..02df4d806f13 --- /dev/null +++ b/include/llvm/Support/LowLevelTypeImpl.h @@ -0,0 +1,202 @@ +//== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Implement a low-level type suitable for MachineInstr level instruction +/// selection. +/// +/// For a type attached to a MachineInstr, we only care about 2 details: total +/// size and the number of vector lanes (if any). Accordingly, there are 4 +/// possible valid type-kinds: +/// +/// * `sN` for scalars and aggregates +/// * `<N x sM>` for vectors, which must have at least 2 elements. +/// * `pN` for pointers +/// +/// Other information required for correct selection is expected to be carried +/// by the opcode, or non-type flags. For example the distinction between G_ADD +/// and G_FADD for int/float or fast-math flags. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H +#define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H + +#include <cassert> +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/CodeGen/MachineValueType.h" + +namespace llvm { + +class DataLayout; +class Type; +class raw_ostream; + +class LLT { +public: + enum TypeKind : uint16_t { + Invalid, + Scalar, + Pointer, + Vector, + }; + + /// Get a low-level scalar or aggregate "bag of bits". + static LLT scalar(unsigned SizeInBits) { + assert(SizeInBits > 0 && "invalid scalar size"); + return LLT{Scalar, 1, SizeInBits}; + } + + /// Get a low-level pointer in the given address space (defaulting to 0). + static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) { + return LLT{Pointer, AddressSpace, SizeInBits}; + } + + /// Get a low-level vector of some number of elements and element width. + /// \p NumElements must be at least 2. + static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { + assert(NumElements > 1 && "invalid number of vector elements"); + return LLT{Vector, NumElements, ScalarSizeInBits}; + } + + /// Get a low-level vector of some number of elements and element type. + static LLT vector(uint16_t NumElements, LLT ScalarTy) { + assert(NumElements > 1 && "invalid number of vector elements"); + assert(ScalarTy.isScalar() && "invalid vector element type"); + return LLT{Vector, NumElements, ScalarTy.getSizeInBits()}; + } + + explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits) + : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) { + assert((Kind != Vector || ElementsOrAddrSpace > 1) && + "invalid number of vector elements"); + } + + explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {} + + explicit LLT(MVT VT); + + bool isValid() const { return Kind != Invalid; } + + bool isScalar() const { return Kind == Scalar; } + + bool isPointer() const { return Kind == Pointer; } + + bool isVector() const { return Kind == Vector; } + + /// Returns the number of elements in a vector LLT. Must only be called on + /// vector types. + uint16_t getNumElements() const { + assert(isVector() && "cannot get number of elements on scalar/aggregate"); + return ElementsOrAddrSpace; + } + + /// Returns the total size of the type. Must only be called on sized types. + unsigned getSizeInBits() const { + if (isPointer() || isScalar()) + return SizeInBits; + return SizeInBits * ElementsOrAddrSpace; + } + + unsigned getScalarSizeInBits() const { + return SizeInBits; + } + + unsigned getAddressSpace() const { + assert(isPointer() && "cannot get address space of non-pointer type"); + return ElementsOrAddrSpace; + } + + /// Returns the vector's element type. Only valid for vector types. + LLT getElementType() const { + assert(isVector() && "cannot get element type of scalar/aggregate"); + return scalar(SizeInBits); + } + + /// Get a low-level type with half the size of the original, by halving the + /// size of the scalar type involved. For example `s32` will become `s16`, + /// `<2 x s32>` will become `<2 x s16>`. + LLT halfScalarSize() const { + assert(!isPointer() && getScalarSizeInBits() > 1 && + getScalarSizeInBits() % 2 == 0 && "cannot half size of this type"); + return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2}; + } + + /// Get a low-level type with twice the size of the original, by doubling the + /// size of the scalar type involved. For example `s32` will become `s64`, + /// `<2 x s32>` will become `<2 x s64>`. + LLT doubleScalarSize() const { + assert(!isPointer() && "cannot change size of this type"); + return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2}; + } + + /// Get a low-level type with half the size of the original, by halving the + /// number of vector elements of the scalar type involved. The source must be + /// a vector type with an even number of elements. For example `<4 x s32>` + /// will become `<2 x s32>`, `<2 x s32>` will become `s32`. + LLT halfElements() const { + assert(isVector() && ElementsOrAddrSpace % 2 == 0 && + "cannot half odd vector"); + if (ElementsOrAddrSpace == 2) + return scalar(SizeInBits); + + return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2), + SizeInBits}; + } + + /// Get a low-level type with twice the size of the original, by doubling the + /// number of vector elements of the scalar type involved. The source must be + /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling + /// the number of elements in sN produces <2 x sN>. + LLT doubleElements() const { + assert(!isPointer() && "cannot double elements in pointer"); + return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2), + SizeInBits}; + } + + void print(raw_ostream &OS) const; + + bool operator==(const LLT &RHS) const { + return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits && + ElementsOrAddrSpace == RHS.ElementsOrAddrSpace; + } + + bool operator!=(const LLT &RHS) const { return !(*this == RHS); } + + friend struct DenseMapInfo<LLT>; +private: + unsigned SizeInBits; + uint16_t ElementsOrAddrSpace; + TypeKind Kind; +}; + +inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { + Ty.print(OS); + return OS; +} + +template<> struct DenseMapInfo<LLT> { + static inline LLT getEmptyKey() { + return LLT{LLT::Invalid, 0, -1u}; + } + static inline LLT getTombstoneKey() { + return LLT{LLT::Invalid, 0, -2u}; + } + static inline unsigned getHashValue(const LLT &Ty) { + uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) | + ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind; + return DenseMapInfo<uint64_t>::getHashValue(Val); + } + static bool isEqual(const LLT &LHS, const LLT &RHS) { + return LHS == RHS; + } +}; + +} + +#endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H diff --git a/include/llvm/Support/MD5.h b/include/llvm/Support/MD5.h index eb181bfe8a5c..2c0dc76485f8 100644 --- a/include/llvm/Support/MD5.h +++ b/include/llvm/Support/MD5.h @@ -1,4 +1,4 @@ -/* +/* -*- C++ -*- * This code is derived from (original license follows): * * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. @@ -29,24 +29,55 @@ #define LLVM_SUPPORT_MD5_H #include "llvm/ADT/SmallString.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" #include <array> +#include <cstdint> namespace llvm { + template <typename T> class ArrayRef; class MD5 { // Any 32-bit or wider unsigned integer data type will do. typedef uint32_t MD5_u32plus; - MD5_u32plus a, b, c, d; - MD5_u32plus hi, lo; + MD5_u32plus a = 0x67452301; + MD5_u32plus b = 0xefcdab89; + MD5_u32plus c = 0x98badcfe; + MD5_u32plus d = 0x10325476; + MD5_u32plus hi = 0; + MD5_u32plus lo = 0; uint8_t buffer[64]; MD5_u32plus block[16]; public: - typedef uint8_t MD5Result[16]; + struct MD5Result { + std::array<uint8_t, 16> Bytes; + + operator std::array<uint8_t, 16>() const { return Bytes; } + + const uint8_t &operator[](size_t I) const { return Bytes[I]; } + uint8_t &operator[](size_t I) { return Bytes[I]; } + + SmallString<32> digest() const; + + uint64_t low() const { + // Our MD5 implementation returns the result in little endian, so the low + // word is first. + using namespace support; + return endian::read<uint64_t, little, unaligned>(Bytes.data()); + } + + uint64_t high() const { + using namespace support; + return endian::read<uint64_t, little, unaligned>(Bytes.data() + 8); + } + std::pair<uint64_t, uint64_t> words() const { + using namespace support; + return std::make_pair(high(), low()); + } + }; MD5(); @@ -70,18 +101,22 @@ private: const uint8_t *body(ArrayRef<uint8_t> Data); }; +inline bool operator==(const MD5::MD5Result &LHS, const MD5::MD5Result &RHS) { + return LHS.Bytes == RHS.Bytes; +} + /// Helper to compute and return lower 64 bits of the given string's MD5 hash. inline uint64_t MD5Hash(StringRef Str) { + using namespace support; + MD5 Hash; Hash.update(Str); - llvm::MD5::MD5Result Result; + 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); + // Return the least significant word. + return Result.low(); } -} +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_MD5_H diff --git a/include/llvm/Support/MachO.def b/include/llvm/Support/MachO.def index 57522897d0fc..95de48d2b19e 100644 --- a/include/llvm/Support/MachO.def +++ b/include/llvm/Support/MachO.def @@ -73,6 +73,8 @@ 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) +HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command) +HANDLE_LOAD_COMMAND(LC_BUILD_VERSION, 0x00000032u, build_version_command) #endif @@ -109,6 +111,8 @@ LOAD_COMMAND_STRUCT(thread_command) LOAD_COMMAND_STRUCT(twolevel_hints_command) LOAD_COMMAND_STRUCT(uuid_command) LOAD_COMMAND_STRUCT(version_min_command) +LOAD_COMMAND_STRUCT(note_command) +LOAD_COMMAND_STRUCT(build_version_command) #endif diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 2b23c0f86448..3d704292c260 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -487,6 +487,22 @@ namespace llvm { VM_PROT_EXECUTE = 0x4 }; + // Values for platform field in build_version_command. + enum { + PLATFORM_MACOS = 1, + PLATFORM_IOS = 2, + PLATFORM_TVOS = 3, + PLATFORM_WATCHOS = 4, + PLATFORM_BRIDGEOS = 5 + }; + + // Values for tools enum in build_tool_version. + enum { + TOOL_CLANG = 1, + TOOL_SWIFT = 2, + TOOL_LD = 3 + }; + // Structs from <mach-o/loader.h> struct mach_header { @@ -819,6 +835,29 @@ namespace llvm { uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz }; + struct note_command { + uint32_t cmd; // LC_NOTE + uint32_t cmdsize; // sizeof(struct note_command) + char data_owner[16]; // owner name for this LC_NOTE + uint64_t offset; // file offset of this data + uint64_t size; // length of data region + }; + + struct build_tool_version { + uint32_t tool; // enum for the tool + uint32_t version; // version of the tool + }; + + struct build_version_command { + uint32_t cmd; // LC_BUILD_VERSION + uint32_t cmdsize; // sizeof(struct build_version_command) + + // ntools * sizeof(struct build_tool_version) + uint32_t platform; // platform + uint32_t minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz + uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz + uint32_t ntools; // number of tool entries following this + }; + struct dyld_info_command { uint32_t cmd; uint32_t cmdsize; @@ -1266,6 +1305,27 @@ namespace llvm { sys::swapByteOrder(C.sdk); } + inline void swapStruct(note_command &C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.offset); + sys::swapByteOrder(C.size); + } + + inline void swapStruct(build_version_command&C) { + sys::swapByteOrder(C.cmd); + sys::swapByteOrder(C.cmdsize); + sys::swapByteOrder(C.platform); + sys::swapByteOrder(C.minos); + sys::swapByteOrder(C.sdk); + sys::swapByteOrder(C.ntools); + } + + inline void swapStruct(build_tool_version&C) { + sys::swapByteOrder(C.tool); + sys::swapByteOrder(C.version); + } + inline void swapStruct(data_in_code_entry &C) { sys::swapByteOrder(C.offset); sys::swapByteOrder(C.length); @@ -1470,6 +1530,25 @@ namespace llvm { CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601 }; + struct x86_thread_state32_t { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ss; + uint32_t eflags; + uint32_t eip; + uint32_t cs; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; + }; + struct x86_thread_state64_t { uint64_t rax; uint64_t rbx; @@ -1599,6 +1678,25 @@ namespace llvm { uint64_t faultvaddr; }; + inline void swapStruct(x86_thread_state32_t &x) { + sys::swapByteOrder(x.eax); + sys::swapByteOrder(x.ebx); + sys::swapByteOrder(x.ecx); + sys::swapByteOrder(x.edx); + sys::swapByteOrder(x.edi); + sys::swapByteOrder(x.esi); + sys::swapByteOrder(x.ebp); + sys::swapByteOrder(x.esp); + sys::swapByteOrder(x.ss); + sys::swapByteOrder(x.eflags); + sys::swapByteOrder(x.eip); + sys::swapByteOrder(x.cs); + sys::swapByteOrder(x.ds); + sys::swapByteOrder(x.es); + sys::swapByteOrder(x.fs); + sys::swapByteOrder(x.gs); + } + inline void swapStruct(x86_thread_state64_t &x) { sys::swapByteOrder(x.rax); sys::swapByteOrder(x.rbx); @@ -1656,6 +1754,7 @@ namespace llvm { x86_state_hdr_t tsh; union { x86_thread_state64_t ts64; + x86_thread_state32_t ts32; } uts; }; @@ -1711,6 +1810,9 @@ namespace llvm { swapStruct(x.ues.es64); } + const uint32_t x86_THREAD_STATE32_COUNT = + sizeof(x86_thread_state32_t) / sizeof(uint32_t); + const uint32_t x86_THREAD_STATE64_COUNT = sizeof(x86_thread_state64_t) / sizeof(uint32_t); const uint32_t x86_FLOAT_STATE64_COUNT = diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 77970f487112..19380b23d9d2 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -112,7 +112,7 @@ std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) { static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, "Only unsigned integral types are allowed."); - return detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB); + return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB); } namespace detail { @@ -181,7 +181,7 @@ std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, "Only unsigned integral types are allowed."); - return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB); + return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB); } /// \brief Get the index of the first set bit starting from the least diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h index f739d19907b0..e8bdc3e89fa7 100644 --- a/include/llvm/Support/MemoryBuffer.h +++ b/include/llvm/Support/MemoryBuffer.h @@ -69,12 +69,12 @@ public: /// means that the client knows that the file exists and that it has the /// specified size. /// - /// \param IsVolatileSize Set to true to indicate that the file size may be - /// changing, e.g. when libclang tries to parse while the user is - /// editing/updating the file. + /// \param IsVolatile Set to true to indicate that the contents of the file + /// can change outside the user's control, e.g. when libclang tries to parse + /// while the user is editing/updating the file or if the file is on an NFS. static ErrorOr<std::unique_ptr<MemoryBuffer>> getFile(const Twine &Filename, int64_t FileSize = -1, - bool RequiresNullTerminator = true, bool IsVolatileSize = false); + bool RequiresNullTerminator = true, bool IsVolatile = false); /// Read all of the specified file into a MemoryBuffer as a stream /// (i.e. until EOF reached). This is useful for special files that @@ -87,17 +87,17 @@ public: /// Since this is in the middle of a file, the buffer is not null terminated. static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, - int64_t Offset); + int64_t Offset, bool IsVolatile = false); /// Given an already-open file descriptor, read the file and return a /// MemoryBuffer. /// - /// \param IsVolatileSize Set to true to indicate that the file size may be - /// changing, e.g. when libclang tries to parse while the user is - /// editing/updating the file. + /// \param IsVolatile Set to true to indicate that the contents of the file + /// can change outside the user's control, e.g. when libclang tries to parse + /// while the user is editing/updating the file or if the file is on an NFS. static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, - bool RequiresNullTerminator = true, bool IsVolatileSize = false); + bool RequiresNullTerminator = true, bool IsVolatile = false); /// Open the specified memory range as a MemoryBuffer. Note that InputData /// must be null terminated if RequiresNullTerminator is true. @@ -136,7 +136,7 @@ public: /// Map a subrange of the specified file as a MemoryBuffer. static ErrorOr<std::unique_ptr<MemoryBuffer>> - getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset); + getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, bool IsVolatile = false); //===--------------------------------------------------------------------===// // Provided for performance analysis. diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h index 2bbcef0c293f..6ac51195519e 100644 --- a/include/llvm/Support/Path.h +++ b/include/llvm/Support/Path.h @@ -24,6 +24,8 @@ namespace llvm { namespace sys { namespace path { +enum class Style { windows, posix, native }; + /// @name Lexical Component Iterator /// @{ @@ -51,9 +53,10 @@ class const_iterator StringRef Path; ///< The entire path. StringRef Component; ///< The current component. Not necessarily in Path. size_t Position; ///< The iterators current position within Path. + Style S; ///< The path style to use. // An end iterator has Position = Path.size() + 1. - friend const_iterator begin(StringRef path); + friend const_iterator begin(StringRef path, Style style); friend const_iterator end(StringRef path); public: @@ -77,8 +80,9 @@ class reverse_iterator StringRef Path; ///< The entire path. StringRef Component; ///< The current component. Not necessarily in Path. size_t Position; ///< The iterators current position within Path. + Style S; ///< The path style to use. - friend reverse_iterator rbegin(StringRef path); + friend reverse_iterator rbegin(StringRef path, Style style); friend reverse_iterator rend(StringRef path); public: @@ -95,7 +99,7 @@ public: /// @brief Get begin iterator over \a path. /// @param path Input path. /// @returns Iterator initialized with the first component of \a path. -const_iterator begin(StringRef path); +const_iterator begin(StringRef path, Style style = Style::native); /// @brief Get end iterator over \a path. /// @param path Input path. @@ -105,7 +109,7 @@ const_iterator end(StringRef path); /// @brief Get reverse begin iterator over \a path. /// @param path Input path. /// @returns Iterator initialized with the first reverse component of \a path. -reverse_iterator rbegin(StringRef path); +reverse_iterator rbegin(StringRef path, Style style = Style::native); /// @brief Get reverse end iterator over \a path. /// @param path Input path. @@ -126,7 +130,7 @@ reverse_iterator rend(StringRef path); /// @endcode /// /// @param path A path that is modified to not have a file component. -void remove_filename(SmallVectorImpl<char> &path); +void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native); /// @brief Replace the file extension of \a path with \a extension. /// @@ -140,7 +144,8 @@ void remove_filename(SmallVectorImpl<char> &path); /// @param extension The extension to be added. It may be empty. It may also /// optionally start with a '.', if it does not, one will be /// prepended. -void replace_extension(SmallVectorImpl<char> &path, const Twine &extension); +void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, + Style style = Style::native); /// @brief Replace matching path prefix with another path. /// @@ -156,8 +161,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension); /// @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); + const StringRef &OldPrefix, const StringRef &NewPrefix, + Style style = Style::native); /// @brief Append to path. /// @@ -174,6 +179,9 @@ void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &c = "", const Twine &d = ""); +void append(SmallVectorImpl<char> &path, Style style, const Twine &a, + const Twine &b = "", const Twine &c = "", const Twine &d = ""); + /// @brief Append to path. /// /// @code @@ -185,8 +193,8 @@ void append(SmallVectorImpl<char> &path, const Twine &a, /// @param path Set to \a path + [\a begin, \a end). /// @param begin Start of components to append. /// @param end One past the end of components to append. -void append(SmallVectorImpl<char> &path, - const_iterator begin, const_iterator end); +void append(SmallVectorImpl<char> &path, const_iterator begin, + const_iterator end, Style style = Style::native); /// @} /// @name Transforms (or some other better name) @@ -198,14 +206,15 @@ void append(SmallVectorImpl<char> &path, /// /// @param path A path that is transformed to native format. /// @param result Holds the result of the transformation. -void native(const Twine &path, SmallVectorImpl<char> &result); +void native(const Twine &path, SmallVectorImpl<char> &result, + Style style = Style::native); /// Convert path to the native form in place. This is used to give paths to /// users and operating system calls in the platform's normal way. For example, /// on Windows all '/' are converted to '\'. /// /// @param path A path that is transformed to native format. -void native(SmallVectorImpl<char> &path); +void native(SmallVectorImpl<char> &path, Style style = Style::native); /// @brief Replaces backslashes with slashes if Windows. /// @@ -213,7 +222,7 @@ void native(SmallVectorImpl<char> &path); /// @result The result of replacing backslashes with forward slashes if Windows. /// On Unix, this function is a no-op because backslashes are valid path /// chracters. -std::string convert_to_slash(StringRef path); +std::string convert_to_slash(StringRef path, Style style = Style::native); /// @} /// @name Lexical Observers @@ -229,7 +238,7 @@ std::string convert_to_slash(StringRef path); /// /// @param path Input path. /// @result The root name of \a path if it has one, otherwise "". -StringRef root_name(StringRef path); +StringRef root_name(StringRef path, Style style = Style::native); /// @brief Get root directory. /// @@ -242,7 +251,7 @@ StringRef root_name(StringRef path); /// @param path Input path. /// @result The root directory of \a path if it has one, otherwise /// "". -StringRef root_directory(StringRef path); +StringRef root_directory(StringRef path, Style style = Style::native); /// @brief Get root path. /// @@ -250,7 +259,7 @@ StringRef root_directory(StringRef path); /// /// @param path Input path. /// @result The root path of \a path if it has one, otherwise "". -StringRef root_path(StringRef path); +StringRef root_path(StringRef path, Style style = Style::native); /// @brief Get relative path. /// @@ -262,7 +271,7 @@ StringRef root_path(StringRef path); /// /// @param path Input path. /// @result The path starting after root_path if one exists, otherwise "". -StringRef relative_path(StringRef path); +StringRef relative_path(StringRef path, Style style = Style::native); /// @brief Get parent path. /// @@ -274,7 +283,7 @@ StringRef relative_path(StringRef path); /// /// @param path Input path. /// @result The parent path of \a path if one exists, otherwise "". -StringRef parent_path(StringRef path); +StringRef parent_path(StringRef path, Style style = Style::native); /// @brief Get filename. /// @@ -288,7 +297,7 @@ StringRef parent_path(StringRef path); /// @param path Input path. /// @result The filename part of \a path. This is defined as the last component /// of \a path. -StringRef filename(StringRef path); +StringRef filename(StringRef path, Style style = Style::native); /// @brief Get stem. /// @@ -306,7 +315,7 @@ StringRef filename(StringRef path); /// /// @param path Input path. /// @result The stem of \a path. -StringRef stem(StringRef path); +StringRef stem(StringRef path, Style style = Style::native); /// @brief Get extension. /// @@ -322,18 +331,18 @@ StringRef stem(StringRef path); /// /// @param path Input path. /// @result The extension of \a path. -StringRef extension(StringRef path); +StringRef extension(StringRef path, Style style = Style::native); /// @brief Check whether the given char is a path separator on the host OS. /// /// @param value a character /// @result true if \a value is a path separator character on the host OS -bool is_separator(char value); +bool is_separator(char value, Style style = Style::native); /// @brief Return the preferred separator for this platform. /// /// @result StringRef of the preferred separator, null-terminated. -StringRef get_separator(); +StringRef get_separator(Style style = Style::native); /// @brief Get the typical temporary directory for the system, e.g., /// "/var/tmp" or "C:/TEMP" @@ -374,7 +383,7 @@ bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1, /// /// @param path Input path. /// @result True if the path has a root name, false otherwise. -bool has_root_name(const Twine &path); +bool has_root_name(const Twine &path, Style style = Style::native); /// @brief Has root directory? /// @@ -382,7 +391,7 @@ bool has_root_name(const Twine &path); /// /// @param path Input path. /// @result True if the path has a root directory, false otherwise. -bool has_root_directory(const Twine &path); +bool has_root_directory(const Twine &path, Style style = Style::native); /// @brief Has root path? /// @@ -390,7 +399,7 @@ bool has_root_directory(const Twine &path); /// /// @param path Input path. /// @result True if the path has a root path, false otherwise. -bool has_root_path(const Twine &path); +bool has_root_path(const Twine &path, Style style = Style::native); /// @brief Has relative path? /// @@ -398,7 +407,7 @@ bool has_root_path(const Twine &path); /// /// @param path Input path. /// @result True if the path has a relative path, false otherwise. -bool has_relative_path(const Twine &path); +bool has_relative_path(const Twine &path, Style style = Style::native); /// @brief Has parent path? /// @@ -406,7 +415,7 @@ bool has_relative_path(const Twine &path); /// /// @param path Input path. /// @result True if the path has a parent path, false otherwise. -bool has_parent_path(const Twine &path); +bool has_parent_path(const Twine &path, Style style = Style::native); /// @brief Has filename? /// @@ -414,7 +423,7 @@ bool has_parent_path(const Twine &path); /// /// @param path Input path. /// @result True if the path has a filename, false otherwise. -bool has_filename(const Twine &path); +bool has_filename(const Twine &path, Style style = Style::native); /// @brief Has stem? /// @@ -422,7 +431,7 @@ bool has_filename(const Twine &path); /// /// @param path Input path. /// @result True if the path has a stem, false otherwise. -bool has_stem(const Twine &path); +bool has_stem(const Twine &path, Style style = Style::native); /// @brief Has extension? /// @@ -430,25 +439,25 @@ bool has_stem(const Twine &path); /// /// @param path Input path. /// @result True if the path has a extension, false otherwise. -bool has_extension(const Twine &path); +bool has_extension(const Twine &path, Style style = Style::native); /// @brief Is path absolute? /// /// @param path Input path. /// @result True if the path is absolute, false if it is not. -bool is_absolute(const Twine &path); +bool is_absolute(const Twine &path, Style style = Style::native); /// @brief Is path relative? /// /// @param path Input path. /// @result True if the path is relative, false if it is not. -bool is_relative(const Twine &path); +bool is_relative(const Twine &path, Style style = Style::native); /// @brief Remove redundant leading "./" pieces and consecutive separators. /// /// @param path Input path. /// @result The cleaned-up \a path. -StringRef remove_leading_dotslash(StringRef path); +StringRef remove_leading_dotslash(StringRef path, Style style = Style::native); /// @brief In-place remove any './' and optionally '../' components from a path. /// @@ -456,7 +465,8 @@ StringRef remove_leading_dotslash(StringRef path); /// @param remove_dot_dot specify if '../' (except for leading "../") should be /// removed /// @result True if path was changed -bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false); +bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false, + Style style = Style::native); } // end namespace path } // end namespace sys diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h index 9ff894edbeb0..521a49684e45 100644 --- a/include/llvm/Support/PointerLikeTypeTraits.h +++ b/include/llvm/Support/PointerLikeTypeTraits.h @@ -60,6 +60,20 @@ public: enum { NumLowBitsAvailable = 2 }; }; +// Provide PointerLikeTypeTraits for const things. +template <typename T> class PointerLikeTypeTraits<const T> { + typedef PointerLikeTypeTraits<T> NonConst; + +public: + static inline const void *getAsVoidPointer(const T P) { + return NonConst::getAsVoidPointer(P); + } + static inline const T getFromVoidPointer(const void *P) { + return NonConst::getFromVoidPointer(const_cast<void *>(P)); + } + enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; +}; + // Provide PointerLikeTypeTraits for const pointers. template <typename T> class PointerLikeTypeTraits<const T *> { typedef PointerLikeTypeTraits<T *> NonConst; diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h index e4736b8e24eb..85f4fc09fb87 100644 --- a/include/llvm/Support/RWMutex.h +++ b/include/llvm/Support/RWMutex.h @@ -14,7 +14,7 @@ #ifndef LLVM_SUPPORT_RWMUTEX_H #define LLVM_SUPPORT_RWMUTEX_H -#include "llvm/Support/Compiler.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Threading.h" #include <cassert> @@ -32,6 +32,13 @@ namespace sys { /// @brief Default Constructor. explicit RWMutexImpl(); + /// @} + /// @name Do Not Implement + /// @{ + RWMutexImpl(const RWMutexImpl & original) = delete; + RWMutexImpl &operator=(const RWMutexImpl &) = delete; + /// @} + /// Releases and removes the lock /// @brief Destructor ~RWMutexImpl(); @@ -70,16 +77,8 @@ namespace sys { /// @{ private: #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 - void* data_; ///< We don't know what the data will be + void* data_ = nullptr; ///< We don't know what the data will be #endif - - /// @} - /// @name Do Not Implement - /// @{ - private: - RWMutexImpl(const RWMutexImpl & original) = delete; - void operator=(const RWMutexImpl &) = delete; - /// @} }; /// SmartMutex - An R/W mutex with a compile time constant parameter that @@ -93,6 +92,8 @@ namespace sys { public: explicit SmartRWMutex() = default; + SmartRWMutex(const SmartRWMutex<mt_only> & original) = delete; + SmartRWMutex<mt_only> &operator=(const SmartRWMutex<mt_only> &) = delete; bool lock_shared() { if (!mt_only || llvm_is_multithreaded()) @@ -136,10 +137,6 @@ namespace sys { --writers; return true; } - - private: - SmartRWMutex(const SmartRWMutex<mt_only> & original); - void operator=(const SmartRWMutex<mt_only> &); }; typedef SmartRWMutex<false> RWMutex; diff --git a/include/llvm/Support/SMLoc.h b/include/llvm/Support/SMLoc.h index eb3a1ba7db51..5b8be5505540 100644 --- a/include/llvm/Support/SMLoc.h +++ b/include/llvm/Support/SMLoc.h @@ -22,10 +22,10 @@ namespace llvm { /// Represents a location in source code. class SMLoc { - const char *Ptr; + const char *Ptr = nullptr; public: - SMLoc() : Ptr(nullptr) {} + SMLoc() = default; bool isValid() const { return Ptr != nullptr; } diff --git a/include/llvm/Support/SourceMgr.h b/include/llvm/Support/SourceMgr.h index bc7478e0d703..cb90d968c44c 100644 --- a/include/llvm/Support/SourceMgr.h +++ b/include/llvm/Support/SourceMgr.h @@ -17,18 +17,24 @@ #define LLVM_SUPPORT_SOURCEMGR_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/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" +#include <algorithm> +#include <cassert> +#include <memory> #include <string> +#include <utility> +#include <vector> namespace llvm { - class SourceMgr; - class SMDiagnostic; - class SMFixIt; - class Twine; - class raw_ostream; + +class raw_ostream; +class SMDiagnostic; +class SMFixIt; /// This owns the files read by a parser, handles include stacks, /// and handles diagnostic wrangling. @@ -44,6 +50,7 @@ public: /// register a function pointer+context as a diagnostic handler. /// It gets called each time PrintMessage is invoked. typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context); + private: struct SrcBuffer { /// The memory buffer for the file. @@ -61,18 +68,17 @@ private: /// This is a cache for line number queries, its implementation is really /// private to SourceMgr.cpp. - mutable void *LineNoCache; + mutable void *LineNoCache = nullptr; - DiagHandlerTy DiagHandler; - void *DiagContext; + DiagHandlerTy DiagHandler = nullptr; + void *DiagContext = nullptr; bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } - SourceMgr(const SourceMgr&) = delete; - void operator=(const SourceMgr&) = delete; public: - SourceMgr() - : LineNoCache(nullptr), DiagHandler(nullptr), DiagContext(nullptr) {} + SourceMgr() = default; + SourceMgr(const SourceMgr &) = delete; + SourceMgr &operator=(const SourceMgr &) = delete; ~SourceMgr(); void setIncludeDirs(const std::vector<std::string> &Dirs) { @@ -190,7 +196,6 @@ public: void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const; }; - /// Represents a single fixit, a replacement of one range of text with another. class SMFixIt { SMRange Range; @@ -222,33 +227,31 @@ public: } }; - /// Instances of this class encapsulate one diagnostic report, allowing /// printing to a raw_ostream as a caret diagnostic. class SMDiagnostic { - const SourceMgr *SM; + const SourceMgr *SM = nullptr; SMLoc Loc; std::string Filename; - int LineNo, ColumnNo; - SourceMgr::DiagKind Kind; + int LineNo = 0; + int ColumnNo = 0; + SourceMgr::DiagKind Kind = SourceMgr::DK_Error; std::string Message, LineContents; - std::vector<std::pair<unsigned, unsigned> > Ranges; + std::vector<std::pair<unsigned, unsigned>> Ranges; SmallVector<SMFixIt, 4> FixIts; public: // Null diagnostic. - SMDiagnostic() - : SM(nullptr), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {} + SMDiagnostic() = default; // Diagnostic with no location (e.g. file not found, command line arg error). SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) - : SM(nullptr), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), - Message(Msg) {} + : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {} // Diagnostic with a location. SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line, int Col, SourceMgr::DiagKind Kind, StringRef Msg, StringRef LineStr, - ArrayRef<std::pair<unsigned,unsigned> > Ranges, + ArrayRef<std::pair<unsigned,unsigned>> Ranges, ArrayRef<SMFixIt> FixIts = None); const SourceMgr *getSourceMgr() const { return SM; } @@ -259,9 +262,7 @@ public: SourceMgr::DiagKind getKind() const { return Kind; } StringRef getMessage() const { return Message; } StringRef getLineContents() const { return LineContents; } - ArrayRef<std::pair<unsigned, unsigned> > getRanges() const { - return Ranges; - } + ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; } void addFixIt(const SMFixIt &Hint) { FixIts.push_back(Hint); @@ -275,6 +276,6 @@ public: bool ShowKindLabel = true) const; }; -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_SOURCEMGR_H diff --git a/include/llvm/Support/TargetParser.h b/include/llvm/Support/TargetParser.h index 63aeca7f4e1e..68e6b2765810 100644 --- a/include/llvm/Support/TargetParser.h +++ b/include/llvm/Support/TargetParser.h @@ -142,7 +142,7 @@ unsigned parseArchVersion(StringRef Arch); } // namespace ARM -// FIXME:This should be made into class design,to avoid dupplication. +// FIXME:This should be made into class design,to avoid dupplication. namespace AArch64 { // Arch names. diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index 954cdb13abaf..bd68d2414487 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -1,4 +1,4 @@ -//===-- Support/TargetRegistry.h - Target Registration ----------*- C++ -*-===// +//===- Support/TargetRegistry.h - Target Registration -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -20,15 +20,22 @@ #define LLVM_SUPPORT_TARGETREGISTRY_H #include "llvm-c/Disassembler.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include <algorithm> #include <cassert> +#include <cstddef> +#include <iterator> #include <memory> #include <string> namespace llvm { + class AsmPrinter; class MCAsmBackend; class MCAsmInfo; @@ -36,22 +43,20 @@ class MCAsmParser; class MCCodeEmitter; class MCContext; class MCDisassembler; -class MCInstrAnalysis; class MCInstPrinter; +class MCInstrAnalysis; class MCInstrInfo; class MCRegisterInfo; +class MCRelocationInfo; class MCStreamer; class MCSubtargetInfo; class MCSymbolizer; -class MCRelocationInfo; class MCTargetAsmParser; class MCTargetOptions; class MCTargetStreamer; +class raw_pwrite_stream; class TargetMachine; class TargetOptions; -class raw_ostream; -class raw_pwrite_stream; -class formatted_raw_ostream; MCStreamer *createNullStreamer(MCContext &Ctx); MCStreamer *createAsmStreamer(MCContext &Ctx, @@ -68,6 +73,9 @@ MCStreamer *createMachOStreamer(MCContext &Ctx, MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *CE, bool RelaxAll, bool DWARFMustBeAtTheEnd, bool LabelSections = false); +MCStreamer *createWasmStreamer(MCContext &Ctx, MCAsmBackend &TAB, + raw_pwrite_stream &OS, MCCodeEmitter *CE, + bool RelaxAll); MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx); @@ -143,6 +151,11 @@ public: MCCodeEmitter *Emitter, bool RelaxAll, bool IncrementalLinkerCompatible); + typedef MCStreamer *(*WasmStreamerCtorTy)(const Triple &T, MCContext &Ctx, + MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll); typedef MCTargetStreamer *(*NullTargetStreamerCtorTy)(MCStreamer &S); typedef MCTargetStreamer *(*AsmTargetStreamerCtorTy)( MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, @@ -224,36 +237,33 @@ private: MCCodeEmitterCtorTy MCCodeEmitterCtorFn; // Construction functions for the various object formats, if registered. - COFFStreamerCtorTy COFFStreamerCtorFn; - MachOStreamerCtorTy MachOStreamerCtorFn; - ELFStreamerCtorTy ELFStreamerCtorFn; + COFFStreamerCtorTy COFFStreamerCtorFn = nullptr; + MachOStreamerCtorTy MachOStreamerCtorFn = nullptr; + ELFStreamerCtorTy ELFStreamerCtorFn = nullptr; + WasmStreamerCtorTy WasmStreamerCtorFn = nullptr; /// Construction function for this target's null TargetStreamer, if /// registered (default = nullptr). - NullTargetStreamerCtorTy NullTargetStreamerCtorFn; + NullTargetStreamerCtorTy NullTargetStreamerCtorFn = nullptr; /// Construction function for this target's asm TargetStreamer, if /// registered (default = nullptr). - AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn; + AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn = nullptr; /// Construction function for this target's obj TargetStreamer, if /// registered (default = nullptr). - ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn; + ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn = nullptr; /// MCRelocationInfoCtorFn - Construction function for this target's /// MCRelocationInfo, if registered (default = llvm::createMCRelocationInfo) - MCRelocationInfoCtorTy MCRelocationInfoCtorFn; + MCRelocationInfoCtorTy MCRelocationInfoCtorFn = nullptr; /// MCSymbolizerCtorFn - Construction function for this target's /// MCSymbolizer, if registered (default = llvm::createMCSymbolizer) - MCSymbolizerCtorTy MCSymbolizerCtorFn; + MCSymbolizerCtorTy MCSymbolizerCtorFn = nullptr; public: - Target() - : COFFStreamerCtorFn(nullptr), MachOStreamerCtorFn(nullptr), - ELFStreamerCtorFn(nullptr), NullTargetStreamerCtorFn(nullptr), - AsmTargetStreamerCtorFn(nullptr), ObjectTargetStreamerCtorFn(nullptr), - MCRelocationInfoCtorFn(nullptr), MCSymbolizerCtorFn(nullptr) {} + Target() = default; /// @name Target Information /// @{ @@ -461,6 +471,12 @@ public: else S = createELFStreamer(Ctx, TAB, OS, Emitter, RelaxAll); break; + case Triple::Wasm: + if (WasmStreamerCtorFn) + S = WasmStreamerCtorFn(T, Ctx, TAB, OS, Emitter, RelaxAll); + else + S = createWasmStreamer(Ctx, TAB, OS, Emitter, RelaxAll); + break; } if (ObjectTargetStreamerCtorFn) ObjectTargetStreamerCtorFn(*S, STI); @@ -548,12 +564,14 @@ struct TargetRegistry { class iterator : public std::iterator<std::forward_iterator_tag, Target, ptrdiff_t> { - const Target *Current; - explicit iterator(Target *T) : Current(T) {} friend struct TargetRegistry; + const Target *Current = nullptr; + + explicit iterator(Target *T) : Current(T) {} + public: - iterator() : Current(nullptr) {} + iterator() = default; bool operator==(const iterator &x) const { return Current == x.Current; } bool operator!=(const iterator &x) const { return !operator==(x); } @@ -800,6 +818,10 @@ struct TargetRegistry { T.ELFStreamerCtorFn = Fn; } + static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) { + T.WasmStreamerCtorFn = Fn; + } + static void RegisterNullTargetStreamer(Target &T, Target::NullTargetStreamerCtorTy Fn) { T.NullTargetStreamerCtorFn = Fn; @@ -1147,6 +1169,7 @@ private: return new MCCodeEmitterImpl(); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_SUPPORT_TARGETREGISTRY_H diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h index 665cec2465bf..f0e3ffa0999c 100644 --- a/include/llvm/Support/ThreadPool.h +++ b/include/llvm/Support/ThreadPool.h @@ -16,23 +16,8 @@ #include "llvm/Support/thread.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 - #include <atomic> #include <condition_variable> #include <functional> diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h index 4bef7ec8dd3f..03963a24c107 100644 --- a/include/llvm/Support/Threading.h +++ b/include/llvm/Support/Threading.h @@ -15,16 +15,22 @@ #ifndef LLVM_SUPPORT_THREADING_H #define LLVM_SUPPORT_THREADING_H +#include "llvm/ADT/SmallVector.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> +#if defined(_MSC_VER) +// MSVC's call_once implementation worked since VS 2015, which is the minimum +// supported version as of this writing. +#define LLVM_THREADING_USE_STD_CALL_ONCE 1 +#elif defined(LLVM_ON_UNIX) && \ + (defined(_LIBCPP_VERSION) || \ + !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__))) // std::call_once from libc++ is used on all Unix platforms. Other // implementations like libstdc++ are known to have problems on NetBSD, // OpenBSD and PowerPC. -#if defined(LLVM_ON_UNIX) && (defined(_LIBCPP_VERSION) || \ - !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__))) #define LLVM_THREADING_USE_STD_CALL_ONCE 1 #else #define LLVM_THREADING_USE_STD_CALL_ONCE 0 @@ -37,41 +43,43 @@ #endif namespace llvm { - /// Returns true if LLVM is compiled with support for multi-threading, and - /// false otherwise. - bool llvm_is_multithreaded(); - - /// llvm_execute_on_thread - Execute the given \p UserFn on a separate - /// thread, passing it the provided \p UserData and waits for thread - /// completion. - /// - /// This function does not guarantee that the code will actually be executed - /// on a separate thread or honoring the requested stack size, but tries to do - /// so where system support is available. - /// - /// \param UserFn - The callback to execute. - /// \param UserData - An argument to pass to the callback function. - /// \param RequestedStackSize - If non-zero, a requested size (in bytes) for - /// the thread stack. - void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData, - unsigned RequestedStackSize = 0); +class Twine; + +/// Returns true if LLVM is compiled with support for multi-threading, and +/// false otherwise. +bool llvm_is_multithreaded(); + +/// llvm_execute_on_thread - Execute the given \p UserFn on a separate +/// thread, passing it the provided \p UserData and waits for thread +/// completion. +/// +/// This function does not guarantee that the code will actually be executed +/// on a separate thread or honoring the requested stack size, but tries to do +/// so where system support is available. +/// +/// \param UserFn - The callback to execute. +/// \param UserData - An argument to pass to the callback function. +/// \param RequestedStackSize - If non-zero, a requested size (in bytes) for +/// 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 + /// \brief The llvm::once_flag structure + /// + /// This type is modeled after std::once_flag to use with llvm::call_once. + /// This structure must be used as an opaque object. It is a struct to force + /// autoinitialization and behave like std::once_flag. + struct once_flag { + volatile sys::cas_flag status = Uninitialized; + }; #endif @@ -81,7 +89,7 @@ namespace llvm { /// \code /// void foo() {...}; /// ... - /// LLVM_DEFINE_ONCE_FLAG(flag); + /// static once_flag flag; /// call_once(flag, foo); /// \endcode /// @@ -95,24 +103,24 @@ namespace llvm { #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); + sys::cas_flag old_val = sys::CompareAndSwap(&flag.status, Wait, Uninitialized); if (old_val == Uninitialized) { std::forward<Function>(F)(std::forward<Args>(ArgList)...); sys::MemoryFence(); TsanIgnoreWritesBegin(); - TsanHappensBefore(&flag); - flag = Done; + TsanHappensBefore(&flag.status); + flag.status = Done; TsanIgnoreWritesEnd(); } else { // Wait until any thread doing the call has finished. - sys::cas_flag tmp = flag; + sys::cas_flag tmp = flag.status; sys::MemoryFence(); while (tmp != Done) { - tmp = flag; + tmp = flag.status; sys::MemoryFence(); } } - TsanHappensAfter(&flag); + TsanHappensAfter(&flag.status); #endif } @@ -122,6 +130,32 @@ namespace llvm { /// thread::hardware_concurrency(). /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF unsigned heavyweight_hardware_concurrency(); + + /// \brief Return the current thread id, as used in various OS system calls. + /// Note that not all platforms guarantee that the value returned will be + /// unique across the entire system, so portable code should not assume + /// this. + uint64_t get_threadid(); + + /// \brief Get the maximum length of a thread name on this platform. + /// A value of 0 means there is no limit. + uint32_t get_max_thread_name_length(); + + /// \brief Set the name of the current thread. Setting a thread's name can + /// be helpful for enabling useful diagnostics under a debugger or when + /// logging. The level of support for setting a thread's name varies + /// wildly across operating systems, and we only make a best effort to + /// perform the operation on supported platforms. No indication of success + /// or failure is returned. + void set_thread_name(const Twine &Name); + + /// \brief Get the name of the current thread. The level of support for + /// getting a thread's name varies wildly across operating systems, and it + /// is not even guaranteed that if you can successfully set a thread's name + /// that you can later get it back. This function is intended for diagnostic + /// purposes, and as with setting a thread's name no indication of whether + /// the operation succeeded or failed is returned. + void get_thread_name(SmallVectorImpl<char> &Name); } #endif diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index 80e8f13dccfe..198855ae0377 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -207,6 +207,9 @@ public: /// This static method prints all timers and clears them all out. static void printAll(raw_ostream &OS); + /// Prints all timers as JSON key/value pairs, and clears them all out. + static const char *printAllJSONValues(raw_ostream &OS, const char *delim); + /// Ensure global timer group lists are initialized. This function is mostly /// used by the Statistic code to influence the construction and destruction /// order of the global timer lists. @@ -221,7 +224,6 @@ private: void printJSONValue(raw_ostream &OS, const PrintRecord &R, const char *suffix, double Value); const char *printJSONValues(raw_ostream &OS, const char *delim); - static const char *printAllJSONValues(raw_ostream &OS, const char *delim); }; } // end namespace llvm diff --git a/include/llvm/Support/TrailingObjects.h b/include/llvm/Support/TrailingObjects.h index 4d355724149c..cb5a52b0d861 100644 --- a/include/llvm/Support/TrailingObjects.h +++ b/include/llvm/Support/TrailingObjects.h @@ -294,7 +294,14 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< public: // Make this (privately inherited) member public. +#ifndef _MSC_VER using ParentType::OverloadToken; +#else + // MSVC bug prevents the above from working, at least up through CL + // 19.10.24629. + template <typename T> + using OverloadToken = typename ParentType::template OverloadToken<T>; +#endif /// Returns a pointer to the trailing object array of the given type /// (which must be one of those specified in the class template). The diff --git a/include/llvm/Support/UniqueLock.h b/include/llvm/Support/UniqueLock.h index 529284d3868b..b4675f4b43ae 100644 --- a/include/llvm/Support/UniqueLock.h +++ b/include/llvm/Support/UniqueLock.h @@ -1,4 +1,4 @@ -//===-- Support/UniqueLock.h - Acquire/Release Mutex In Scope ---*- C++ -*-===// +//===- Support/UniqueLock.h - Acquire/Release Mutex In Scope ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,9 +15,10 @@ #ifndef LLVM_SUPPORT_UNIQUE_LOCK_H #define LLVM_SUPPORT_UNIQUE_LOCK_H -#include "llvm/Support/Mutex.h" +#include <cassert> namespace llvm { + /// A pared-down imitation of std::unique_lock from C++11. Contrary to the /// name, it's really more of a wrapper for a lock. It may or may not have /// an associated mutex, which is guaranteed to be locked upon creation @@ -26,14 +27,14 @@ namespace llvm { /// @brief Guard a section of code with a mutex. template<typename MutexT> class unique_lock { - MutexT *M; - bool locked; + MutexT *M = nullptr; + bool locked = false; - unique_lock(const unique_lock &) = delete; - void operator=(const unique_lock &) = delete; public: - unique_lock() : M(nullptr), locked(false) {} + unique_lock() = default; explicit unique_lock(MutexT &m) : M(&m), locked(true) { M->lock(); } + unique_lock(const unique_lock &) = delete; + unique_lock &operator=(const unique_lock &) = delete; void operator=(unique_lock &&o) { if (owns_lock()) @@ -62,6 +63,7 @@ namespace llvm { bool owns_lock() { return locked; } }; -} + +} // end namespace llvm #endif // LLVM_SUPPORT_UNIQUE_LOCK_H diff --git a/include/llvm/Support/Wasm.h b/include/llvm/Support/Wasm.h index 8ac6b9038e91..8e6c418c8189 100644 --- a/include/llvm/Support/Wasm.h +++ b/include/llvm/Support/Wasm.h @@ -23,22 +23,94 @@ namespace wasm { // Object file magic string. const char WasmMagic[] = {'\0', 'a', 's', 'm'}; // Wasm binary format version -const uint32_t WasmVersion = 0xd; +const uint32_t WasmVersion = 0x1; struct WasmObjectHeader { StringRef Magic; uint32_t Version; }; -struct WasmSection { - uint32_t Type; // Section type (See below) - uint32_t Offset; // Offset with in the file - StringRef Name; // Section name (User-defined sections only) - ArrayRef<uint8_t> Content; // Section content +struct WasmSignature { + std::vector<int32_t> ParamTypes; + int32_t ReturnType; +}; + +struct WasmImport { + StringRef Module; + StringRef Field; + uint32_t Kind; + union { + uint32_t SigIndex; + int32_t GlobalType; + }; + bool GlobalMutable; +}; + +struct WasmExport { + StringRef Name; + uint32_t Kind; + uint32_t Index; +}; + +struct WasmLimits { + uint32_t Flags; + uint32_t Initial; + uint32_t Maximum; +}; + +struct WasmTable { + int32_t ElemType; + WasmLimits Limits; +}; + +struct WasmInitExpr { + uint8_t Opcode; + union { + int32_t Int32; + int64_t Int64; + int32_t Float32; + int64_t Float64; + uint32_t Global; + } Value; +}; + +struct WasmGlobal { + int32_t Type; + bool Mutable; + WasmInitExpr InitExpr; +}; + +struct WasmLocalDecl { + int32_t Type; + uint32_t Count; +}; + +struct WasmFunction { + std::vector<WasmLocalDecl> Locals; + ArrayRef<uint8_t> Body; +}; + +struct WasmDataSegment { + uint32_t Index; + WasmInitExpr Offset; + ArrayRef<uint8_t> Content; +}; + +struct WasmElemSegment { + uint32_t TableIndex; + WasmInitExpr Offset; + std::vector<uint32_t> Functions; +}; + +struct WasmRelocation { + uint32_t Type; // The type of the relocation. + int32_t Index; // Index into function to global index space. + uint64_t Offset; // Offset from the start of the section. + uint64_t Addend; // A value to add to the symbol. }; enum : unsigned { - WASM_SEC_USER = 0, // User-defined section + WASM_SEC_CUSTOM = 0, // Custom / User-defined section WASM_SEC_TYPE = 1, // Function signature declarations WASM_SEC_IMPORT = 2, // Import declarations WASM_SEC_FUNCTION = 3, // Function declarations @@ -53,14 +125,14 @@ enum : unsigned { }; // Type immediate encodings used in various contexts. -enum : unsigned { - WASM_TYPE_I32 = 0x7f, - WASM_TYPE_I64 = 0x7e, - WASM_TYPE_F32 = 0x7d, - WASM_TYPE_F64 = 0x7c, - WASM_TYPE_ANYFUNC = 0x70, - WASM_TYPE_FUNC = 0x60, - WASM_TYPE_NORESULT = 0x40, // for blocks with no result values +enum { + WASM_TYPE_I32 = -0x01, + WASM_TYPE_I64 = -0x02, + WASM_TYPE_F32 = -0x03, + WASM_TYPE_F64 = -0x04, + WASM_TYPE_ANYFUNC = -0x10, + WASM_TYPE_FUNC = -0x20, + WASM_TYPE_NORESULT = -0x40, // for blocks with no result values }; // Kinds of externals (for imports and exports). @@ -81,6 +153,49 @@ enum : unsigned { WASM_OPCODE_F64_CONST = 0x44, }; +enum : unsigned { + WASM_NAMES_FUNCTION = 0x1, + WASM_NAMES_LOCAL = 0x2, +}; + +enum : unsigned { + WASM_LIMITS_FLAG_HAS_MAX = 0x1, +}; + +// Subset of types that a value can have +enum class ValType { + I32 = WASM_TYPE_I32, + I64 = WASM_TYPE_I64, + F32 = WASM_TYPE_F32, + F64 = WASM_TYPE_F64, +}; + +// Linking metadata kinds. +enum : unsigned { + WASM_STACK_POINTER = 0x1, +}; + +#define WASM_RELOC(name, value) name = value, + +enum : unsigned { +#include "WasmRelocs/WebAssembly.def" +}; + +#undef WASM_RELOC + +struct Global { + ValType Type; + bool Mutable; + + // The initial value for this global is either the value of an imported + // global, in which case InitialModule and InitialName specify the global + // import, or a value, in which case InitialModule is empty and InitialValue + // holds the value. + StringRef InitialModule; + StringRef InitialName; + uint64_t InitialValue; +}; + } // end namespace wasm } // end namespace llvm diff --git a/include/llvm/Support/WasmRelocs/WebAssembly.def b/include/llvm/Support/WasmRelocs/WebAssembly.def new file mode 100644 index 000000000000..da64e025478d --- /dev/null +++ b/include/llvm/Support/WasmRelocs/WebAssembly.def @@ -0,0 +1,13 @@ + +#ifndef WASM_RELOC +#error "WASM_RELOC must be defined" +#endif + +WASM_RELOC(R_WEBASSEMBLY_FUNCTION_INDEX_LEB, 0) +WASM_RELOC(R_WEBASSEMBLY_TABLE_INDEX_SLEB, 1) +WASM_RELOC(R_WEBASSEMBLY_TABLE_INDEX_I32, 2) +WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_LEB, 3) +WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_SLEB, 4) +WASM_RELOC(R_WEBASSEMBLY_GLOBAL_ADDR_I32, 5) +WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6) +WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7) diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index cbba9c08275a..6d02e4aba48a 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -689,11 +689,12 @@ private: assert(DefaultValue.hasValue() == false && "Optional<T> shouldn't have a value!"); void *SaveInfo; - bool UseDefault; + bool UseDefault = true; const bool sameAsDefault = outputting() && !Val.hasValue(); if (!outputting() && !Val.hasValue()) Val = T(); - if (this->preflightKey(Key, Required, sameAsDefault, UseDefault, + if (Val.hasValue() && + this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { yamlize(*this, Val.getValue(), Required, Ctx); this->postflightKey(SaveInfo); @@ -731,7 +732,7 @@ private: } private: - void *Ctxt; + void *Ctxt; }; namespace detail { @@ -1251,6 +1252,13 @@ public: Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); ~Output() override; + /// \brief Set whether or not to output optional values which are equal + /// to the default value. By default, when outputting if you attempt + /// to write a value that is equal to the default, the value gets ignored. + /// Sometimes, it is useful to be able to see these in the resulting YAML + /// anyway. + void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } + bool outputting() override; bool mapTag(StringRef, bool) override; void beginMapping() override; @@ -1314,6 +1322,7 @@ private: bool NeedFlowSequenceComma; bool EnumerationMatchFound; bool NeedsNewLine; + bool WriteDefaultValues; }; /// YAML I/O does conversion based on types. But often native data types diff --git a/include/llvm/Support/thread.h b/include/llvm/Support/thread.h index 9c45418df55c..787a513d6017 100644 --- a/include/llvm/Support/thread.h +++ b/include/llvm/Support/thread.h @@ -21,22 +21,8 @@ #if LLVM_ENABLE_THREADS -#ifdef _MSC_VER -// concrt.h depends on eh.h for __uncaught_exception declaration -// even if we disable exceptions. -#include <eh.h> - -// Suppress 'C++ exception handler used, but unwind semantics are not enabled.' -#pragma warning(push) -#pragma warning(disable:4530) -#endif - #include <thread> -#ifdef _MSC_VER -#pragma warning(pop) -#endif - namespace llvm { typedef std::thread thread; } diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 7706ff527197..ce4bbf8cb2cc 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -95,6 +95,15 @@ struct add_const_past_pointer< typedef const typename std::remove_pointer<T>::type *type; }; +template <typename T, typename Enable = void> +struct const_pointer_or_const_ref { + using type = const T &; +}; +template <typename T> +struct const_pointer_or_const_ref< + T, typename std::enable_if<std::is_pointer<T>::value>::type> { + using type = typename add_const_past_pointer<T>::type; +}; } // If the compiler supports detecting whether a class is final, define diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h index 5a100f0cba76..fef5bf304566 100644 --- a/include/llvm/TableGen/Record.h +++ b/include/llvm/TableGen/Record.h @@ -1196,6 +1196,9 @@ public: inline const_arg_iterator arg_begin() const { return Args.begin(); } inline const_arg_iterator arg_end () const { return Args.end(); } + inline iterator_range<const_arg_iterator> args() const { + return llvm::make_range(arg_begin(), arg_end()); + } inline size_t arg_size () const { return Args.size(); } inline bool arg_empty() const { return Args.empty(); } @@ -1462,6 +1465,7 @@ public: ResolveFirst = b; } + void print(raw_ostream &OS) const; void dump() const; //===--------------------------------------------------------------------===// diff --git a/include/llvm/TableGen/StringMatcher.h b/include/llvm/TableGen/StringMatcher.h index b43877910834..11a8ad8183aa 100644 --- a/include/llvm/TableGen/StringMatcher.h +++ b/include/llvm/TableGen/StringMatcher.h @@ -38,7 +38,7 @@ private: raw_ostream &OS; public: - StringMatcher(StringRef strVariableName, + StringMatcher(StringRef strVariableName, const std::vector<StringPair> &matches, raw_ostream &os) : StrVariableName(strVariableName), Matches(matches), OS(os) {} diff --git a/include/llvm/TableGen/StringToOffsetTable.h b/include/llvm/TableGen/StringToOffsetTable.h index e5b61ed1195e..aaf2a356ffab 100644 --- a/include/llvm/TableGen/StringToOffsetTable.h +++ b/include/llvm/TableGen/StringToOffsetTable.h @@ -60,10 +60,10 @@ public: if (AggregateString[i] != '\\') continue; - assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); - if (isdigit(AggregateString[i+1])) { - assert(isdigit(AggregateString[i+2]) && - isdigit(AggregateString[i+3]) && + assert(i + 1 < AggregateString.size() && "Incomplete escape sequence!"); + if (isdigit(AggregateString[i + 1])) { + assert(isdigit(AggregateString[i + 2]) && + isdigit(AggregateString[i + 3]) && "Expected 3 digit octal escape!"); O << AggregateString[++i]; O << AggregateString[++i]; diff --git a/include/llvm/Target/GenericOpcodes.td b/include/llvm/Target/GenericOpcodes.td index 8694eb5797d0..de3796cd4ee5 100644 --- a/include/llvm/Target/GenericOpcodes.td +++ b/include/llvm/Target/GenericOpcodes.td @@ -91,6 +91,21 @@ def G_FCONSTANT : Instruction { let hasSideEffects = 0; } +def G_VASTART : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins type0:$list); + let hasSideEffects = 0; + let mayStore = 1; +} + +def G_VAARG : Instruction { + let OutOperandList = (outs type0:$val); + let InOperandList = (ins type1:$list, unknown:$align); + let hasSideEffects = 0; + let mayLoad = 1; + let mayStore = 1; +} + //------------------------------------------------------------------------------ // Binary ops. //------------------------------------------------------------------------------ @@ -103,13 +118,6 @@ def G_ADD : Instruction { let isCommutable = 1; } -// Generic pointer offset. -def G_GEP : Instruction { - let OutOperandList = (outs type0:$dst); - let InOperandList = (ins type0:$src1, type1:$src2); - let hasSideEffects = 0; -} - // Generic subtraction. def G_SUB : Instruction { let OutOperandList = (outs type0:$dst); @@ -224,6 +232,19 @@ def G_SELECT : Instruction { let hasSideEffects = 0; } +// Generic pointer offset. +def G_GEP : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type1:$src2); + let hasSideEffects = 0; +} + +def G_PTR_MASK : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, unknown:$bits); + let hasSideEffects = 0; +} + //------------------------------------------------------------------------------ // Overflow ops //------------------------------------------------------------------------------ @@ -273,10 +294,34 @@ def G_SMULO : Instruction { let isCommutable = 1; } +// Multiply two numbers at twice the incoming bit width (unsigned) and return +// the high half of the result. +def G_UMULH : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +// Multiply two numbers at twice the incoming bit width (signed) and return +// the high half of the result. +def G_SMULH : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + //------------------------------------------------------------------------------ // Floating Point Unary Ops. //------------------------------------------------------------------------------ +def G_FNEG : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src); + let hasSideEffects = 0; +} + def G_FPEXT : Instruction { let OutOperandList = (outs type0:$dst); let InOperandList = (ins type1:$src); @@ -355,6 +400,13 @@ def G_FREM : Instruction { let hasSideEffects = 0; } +// Floating point exponentiation. +def G_FPOW : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; +} + //------------------------------------------------------------------------------ // Memory ops //------------------------------------------------------------------------------ @@ -383,17 +435,24 @@ def G_STORE : Instruction { // indexes. This will almost certainly be mapped to sub-register COPYs after // register banks have been selected. def G_EXTRACT : Instruction { + let OutOperandList = (outs type0:$res); + let InOperandList = (ins type1:$src, unknown:$offset); + let hasSideEffects = 0; +} + +// Extract multiple registers specified size, starting from blocks given by +// indexes. This will almost certainly be mapped to sub-register COPYs after +// register banks have been selected. +def G_UNMERGE_VALUES : Instruction { let OutOperandList = (outs); let InOperandList = (ins variable_ops); let hasSideEffects = 0; } -// Insert a sequence of smaller registers into a larger one at the specified -// indices (interleaved with the values in the operand list "op0, bit0, op1, -// bit1, ...")). +// Insert a smaller register into a larger one at the specified bit-index. def G_INSERT : Instruction { let OutOperandList = (outs type0:$dst); - let InOperandList = (ins type0:$src, variable_ops); + let InOperandList = (ins type0:$src, type1:$op, unknown:$offset); let hasSideEffects = 0; } @@ -406,6 +465,12 @@ def G_SEQUENCE : Instruction { let hasSideEffects = 0; } +def G_MERGE_VALUES : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins variable_ops); + let hasSideEffects = 0; +} + // Intrinsic without side effects. def G_INTRINSIC : Instruction { let OutOperandList = (outs); @@ -445,4 +510,38 @@ def G_BRCOND : Instruction { let isTerminator = 1; } +// Generic indirect branch. +def G_BRINDIRECT : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins type0:$src1); + let hasSideEffects = 0; + let isBranch = 1; + let isTerminator = 1; +} + +//------------------------------------------------------------------------------ +// Vector ops +//------------------------------------------------------------------------------ + +// Generic insertelement. +def G_INSERT_VECTOR_ELT : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, type1:$elt, type2:$idx); + let hasSideEffects = 0; +} + +// Generic extractelement. +def G_EXTRACT_VECTOR_ELT : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type1:$src, type2:$idx); + let hasSideEffects = 0; +} + +// Generic shufflevector. +def G_SHUFFLE_VECTOR: Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type1:$v1, type1:$v2, type2:$mask); + let hasSideEffects = 0; +} + // TODO: Add the other generic opcodes. diff --git a/include/llvm/Target/GlobalISel/RegisterBank.td b/include/llvm/Target/GlobalISel/RegisterBank.td new file mode 100644 index 000000000000..4dfd139e9fb6 --- /dev/null +++ b/include/llvm/Target/GlobalISel/RegisterBank.td @@ -0,0 +1,16 @@ +//===- RegisterBank.td - Register bank definitions ---------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +class RegisterBank<string name, list<RegisterClass> classes> { + string Name = name; + list<RegisterClass> RegisterClasses = classes; +} diff --git a/include/llvm/Target/TargetGlobalISel.td b/include/llvm/Target/GlobalISel/SelectionDAGCompat.td index 0727c9802e5e..9f034220815f 100644 --- a/include/llvm/Target/TargetGlobalISel.td +++ b/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -25,5 +25,29 @@ class GINodeEquiv<Instruction i, SDNode node> { SDNode Node = node; } +def : GINodeEquiv<G_ZEXT, zext>; +def : GINodeEquiv<G_SEXT, sext>; def : GINodeEquiv<G_ADD, add>; +def : GINodeEquiv<G_SUB, sub>; +def : GINodeEquiv<G_MUL, mul>; + +def : GINodeEquiv<G_OR, or>; +def : GINodeEquiv<G_XOR, xor>; +def : GINodeEquiv<G_AND, and>; + +def : GINodeEquiv<G_SHL, shl>; +def : GINodeEquiv<G_LSHR, srl>; +def : GINodeEquiv<G_ASHR, sra>; + +def : GINodeEquiv<G_SDIV, sdiv>; +def : GINodeEquiv<G_UDIV, udiv>; +def : GINodeEquiv<G_SREM, srem>; +def : GINodeEquiv<G_UREM, urem>; + def : GINodeEquiv<G_BR, br>; + +// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern. +// Should be used on defs that subclass GIComplexOperandMatcher<>. +class GIComplexPatternEquiv<ComplexPattern seldag> { + ComplexPattern SelDAGEquivalent = seldag; +} diff --git a/include/llvm/Target/GlobalISel/Target.td b/include/llvm/Target/GlobalISel/Target.td new file mode 100644 index 000000000000..fa1a424b5895 --- /dev/null +++ b/include/llvm/Target/GlobalISel/Target.td @@ -0,0 +1,56 @@ +//===- Target.td - Define GlobalISel rules -----------------*- 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 target-independent interfaces used to support +// SelectionDAG instruction selection patterns (specified in +// TargetSelectionDAG.td) when generating GlobalISel instruction selectors. +// +// This is intended as a compatibility layer, to enable reuse of target +// descriptions written for SelectionDAG without requiring explicit GlobalISel +// support. It will eventually supersede SelectionDAG patterns. +// +//===----------------------------------------------------------------------===// + +// Definitions that inherit from LLT define types that will be used in the +// GlobalISel matcher. +class LLT; + +def s32 : LLT; +def s64 : LLT; + +// Defines a matcher for complex operands. This is analogous to ComplexPattern +// from SelectionDAG. +// +// Definitions that inherit from this may also inherit from +// GIComplexPatternEquiv to enable the import of SelectionDAG patterns involving +// those ComplexPatterns. +class GIComplexOperandMatcher<LLT type, dag operands, string matcherfn> { + // The expected type of the root of the match. + // + // TODO: We should probably support, any-type, any-scalar, and multiple types + // in the future. + LLT Type = type; + + // The operands that result from a successful match + // Should be of the form '(ops ty1, ty2, ...)' where ty1/ty2 are definitions + // that inherit from Operand. + // + // FIXME: Which definition is used for ty1/ty2 doesn't actually matter at the + // moment. Only the number of operands is used. + dag Operands = operands; + + // The function that determines whether the operand matches. It should be of + // the form: + // bool select(const MatchOperand &Root, MatchOperand &Result1) + // and should have the same number of ResultX arguments as the number of + // result operands. It must return true on successful match and false + // otherwise. If it returns true, then all the ResultX arguments must be + // overwritten. + string MatcherFn = matcherfn; +} diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index 729d7669e0fa..b21689e0e134 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -402,11 +402,8 @@ class Instruction { // If so, make sure to override // TargetInstrInfo::getInsertSubregLikeInputs. - // Side effect flags - When set, the flags have these meanings: - // - // hasSideEffects - The instruction has side effects that are not - // captured by any operands of the instruction or other flags. - // + // Does the instruction have side effects that are not captured by any + // operands of the instruction or other flags? bit hasSideEffects = ?; // Is this instruction a "real" instruction (with a distinct machine @@ -951,11 +948,12 @@ def LOCAL_ESCAPE : Instruction { let hasSideEffects = 0; let hasCtrlDep = 1; } -def FAULTING_LOAD_OP : Instruction { +def FAULTING_OP : Instruction { let OutOperandList = (outs unknown:$dst); let InOperandList = (ins variable_ops); let usesCustomInserter = 1; let mayLoad = 1; + let mayStore = 1; let isTerminator = 1; let isBranch = 1; } @@ -998,6 +996,15 @@ def PATCHABLE_TAIL_CALL : Instruction { let hasSideEffects = 1; let isReturn = 1; } +def FENTRY_CALL : Instruction { + let OutOperandList = (outs unknown:$dst); + let InOperandList = (ins variable_ops); + let AsmString = "# FEntry call"; + let usesCustomInserter = 1; + let mayLoad = 1; + let mayStore = 1; + let hasSideEffects = 1; +} // Generic opcodes used in GlobalISel. include "llvm/Target/GenericOpcodes.td" @@ -1342,6 +1349,16 @@ include "llvm/Target/TargetCallingConv.td" include "llvm/Target/TargetSelectionDAG.td" //===----------------------------------------------------------------------===// -// Pull in the common support for Global ISel generation. +// Pull in the common support for Global ISel register bank info generation. +// +include "llvm/Target/GlobalISel/RegisterBank.td" + +//===----------------------------------------------------------------------===// +// Pull in the common support for DAG isel generation. +// +include "llvm/Target/GlobalISel/Target.td" + +//===----------------------------------------------------------------------===// +// Pull in the common support for the Global ISel DAG-based selector generation. // -include "llvm/Target/TargetGlobalISel.td" +include "llvm/Target/GlobalISel/SelectionDAGCompat.td" diff --git a/include/llvm/Target/TargetCallingConv.h b/include/llvm/Target/TargetCallingConv.h index be09236cdab0..4f750b8a289f 100644 --- a/include/llvm/Target/TargetCallingConv.h +++ b/include/llvm/Target/TargetCallingConv.h @@ -14,146 +14,120 @@ #ifndef LLVM_TARGET_TARGETCALLINGCONV_H #define LLVM_TARGET_TARGETCALLINGCONV_H +#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/ValueTypes.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" +#include <cassert> #include <climits> +#include <cstdint> namespace llvm { - namespace ISD { + struct ArgFlagsTy { private: - static const uint64_t NoFlagSet = 0ULL; - static const uint64_t ZExt = 1ULL<<0; ///< Zero extended - static const uint64_t ZExtOffs = 0; - static const uint64_t SExt = 1ULL<<1; ///< Sign extended - static const uint64_t SExtOffs = 1; - static const uint64_t InReg = 1ULL<<2; ///< Passed in register - static const uint64_t InRegOffs = 2; - static const uint64_t SRet = 1ULL<<3; ///< Hidden struct-ret ptr - static const uint64_t SRetOffs = 3; - static const uint64_t ByVal = 1ULL<<4; ///< Struct passed by value - static const uint64_t ByValOffs = 4; - static const uint64_t Nest = 1ULL<<5; ///< Nested fn static chain - static const uint64_t NestOffs = 5; - static const uint64_t Returned = 1ULL<<6; ///< Always returned - static const uint64_t ReturnedOffs = 6; - static const uint64_t ByValAlign = 0xFULL<<7; ///< Struct alignment - static const uint64_t ByValAlignOffs = 7; - static const uint64_t Split = 1ULL<<11; - static const uint64_t SplitOffs = 11; - static const uint64_t InAlloca = 1ULL<<12; ///< Passed with inalloca - 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 Hva = 1ULL << 16; ///< HVA field for - ///< vectorcall - static const uint64_t HvaOffs = 16; - static const uint64_t HvaStart = 1ULL << 17; ///< HVA structure start - ///< for vectorcall - static const uint64_t HvaStartOffs = 17; - static const uint64_t SecArgPass = 1ULL << 18; ///< Second argument - ///< pass for vectorcall - static const uint64_t SecArgPassOffs = 18; - static const uint64_t OrigAlign = 0x1FULL<<27; - static const uint64_t OrigAlignOffs = 27; - static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size - static const uint64_t ByValSizeOffs = 32; - static const uint64_t InConsecutiveRegsLast = 0x1ULL<<62; ///< Struct size - static const uint64_t InConsecutiveRegsLastOffs = 62; - static const uint64_t InConsecutiveRegs = 0x1ULL<<63; ///< Struct size - static const uint64_t InConsecutiveRegsOffs = 63; - - static const uint64_t One = 1ULL; ///< 1 of this type, for shifts - - uint64_t Flags; + unsigned IsZExt : 1; ///< Zero extended + unsigned IsSExt : 1; ///< Sign extended + unsigned IsInReg : 1; ///< Passed in register + unsigned IsSRet : 1; ///< Hidden struct-ret ptr + unsigned IsByVal : 1; ///< Struct passed by value + unsigned IsNest : 1; ///< Nested fn static chain + unsigned IsReturned : 1; ///< Always returned + unsigned IsSplit : 1; + unsigned IsInAlloca : 1; ///< Passed with inalloca + unsigned IsSplitEnd : 1; ///< Last part of a split + unsigned IsSwiftSelf : 1; ///< Swift self parameter + unsigned IsSwiftError : 1; ///< Swift error parameter + unsigned IsHva : 1; ///< HVA field for + unsigned IsHvaStart : 1; ///< HVA structure start + unsigned IsSecArgPass : 1; ///< Second argument + unsigned ByValAlign : 4; ///< Log 2 of byval alignment + unsigned OrigAlign : 5; ///< Log 2 of original alignment + unsigned IsInConsecutiveRegsLast : 1; + unsigned IsInConsecutiveRegs : 1; + unsigned IsCopyElisionCandidate : 1; ///< Argument copy elision candidate + + unsigned ByValSize; ///< Byval struct size public: - ArgFlagsTy() : Flags(0) { } + ArgFlagsTy() + : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0), + IsReturned(0), IsSplit(0), IsInAlloca(0), IsSplitEnd(0), + IsSwiftSelf(0), IsSwiftError(0), IsHva(0), IsHvaStart(0), + IsSecArgPass(0), ByValAlign(0), OrigAlign(0), + IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), + IsCopyElisionCandidate(0), ByValSize(0) { + static_assert(sizeof(*this) == 2 * sizeof(unsigned), "flags are too big"); + } - bool isZExt() const { return Flags & ZExt; } - void setZExt() { Flags |= One << ZExtOffs; } + bool isZExt() const { return IsZExt; } + void setZExt() { IsZExt = 1; } - bool isSExt() const { return Flags & SExt; } - void setSExt() { Flags |= One << SExtOffs; } + bool isSExt() const { return IsSExt; } + void setSExt() { IsSExt = 1; } - bool isInReg() const { return Flags & InReg; } - void setInReg() { Flags |= One << InRegOffs; } + bool isInReg() const { return IsInReg; } + void setInReg() { IsInReg = 1; } - bool isSRet() const { return Flags & SRet; } - void setSRet() { Flags |= One << SRetOffs; } + bool isSRet() const { return IsSRet; } + void setSRet() { IsSRet = 1; } - bool isByVal() const { return Flags & ByVal; } - void setByVal() { Flags |= One << ByValOffs; } + bool isByVal() const { return IsByVal; } + void setByVal() { IsByVal = 1; } - bool isInAlloca() const { return Flags & InAlloca; } - void setInAlloca() { Flags |= One << InAllocaOffs; } + bool isInAlloca() const { return IsInAlloca; } + void setInAlloca() { IsInAlloca = 1; } - bool isSwiftSelf() const { return Flags & SwiftSelf; } - void setSwiftSelf() { Flags |= One << SwiftSelfOffs; } + bool isSwiftSelf() const { return IsSwiftSelf; } + void setSwiftSelf() { IsSwiftSelf = 1; } - bool isSwiftError() const { return Flags & SwiftError; } - void setSwiftError() { Flags |= One << SwiftErrorOffs; } + bool isSwiftError() const { return IsSwiftError; } + void setSwiftError() { IsSwiftError = 1; } - bool isHva() const { return Flags & Hva; } - void setHva() { Flags |= One << HvaOffs; } + bool isHva() const { return IsHva; } + void setHva() { IsHva = 1; } - bool isHvaStart() const { return Flags & HvaStart; } - void setHvaStart() { Flags |= One << HvaStartOffs; } + bool isHvaStart() const { return IsHvaStart; } + void setHvaStart() { IsHvaStart = 1; } - bool isSecArgPass() const { return Flags & SecArgPass; } - void setSecArgPass() { Flags |= One << SecArgPassOffs; } + bool isSecArgPass() const { return IsSecArgPass; } + void setSecArgPass() { IsSecArgPass = 1; } - bool isNest() const { return Flags & Nest; } - void setNest() { Flags |= One << NestOffs; } + bool isNest() const { return IsNest; } + void setNest() { IsNest = 1; } - bool isReturned() const { return Flags & Returned; } - void setReturned() { Flags |= One << ReturnedOffs; } + bool isReturned() const { return IsReturned; } + void setReturned() { IsReturned = 1; } - bool isInConsecutiveRegs() const { return Flags & InConsecutiveRegs; } - void setInConsecutiveRegs() { Flags |= One << InConsecutiveRegsOffs; } + bool isInConsecutiveRegs() const { return IsInConsecutiveRegs; } + void setInConsecutiveRegs() { IsInConsecutiveRegs = 1; } - bool isInConsecutiveRegsLast() const { return Flags & InConsecutiveRegsLast; } - void setInConsecutiveRegsLast() { Flags |= One << InConsecutiveRegsLastOffs; } + bool isInConsecutiveRegsLast() const { return IsInConsecutiveRegsLast; } + void setInConsecutiveRegsLast() { IsInConsecutiveRegsLast = 1; } - unsigned getByValAlign() const { - return (unsigned) - ((One << ((Flags & ByValAlign) >> ByValAlignOffs)) / 2); - } - void setByValAlign(unsigned A) { - Flags = (Flags & ~ByValAlign) | - (uint64_t(Log2_32(A) + 1) << ByValAlignOffs); - } + bool isSplit() const { return IsSplit; } + void setSplit() { IsSplit = 1; } - bool isSplit() const { return Flags & Split; } - void setSplit() { Flags |= One << SplitOffs; } + bool isSplitEnd() const { return IsSplitEnd; } + void setSplitEnd() { IsSplitEnd = 1; } - bool isSplitEnd() const { return Flags & SplitEnd; } - void setSplitEnd() { Flags |= One << SplitEndOffs; } + bool isCopyElisionCandidate() const { return IsCopyElisionCandidate; } + void setCopyElisionCandidate() { IsCopyElisionCandidate = 1; } - unsigned getOrigAlign() const { - return (unsigned) - ((One << ((Flags & OrigAlign) >> OrigAlignOffs)) / 2); - } - void setOrigAlign(unsigned A) { - Flags = (Flags & ~OrigAlign) | - (uint64_t(Log2_32(A) + 1) << OrigAlignOffs); + unsigned getByValAlign() const { return (1U << ByValAlign) / 2; } + void setByValAlign(unsigned A) { + ByValAlign = Log2_32(A) + 1; + assert(getByValAlign() == A && "bitfield overflow"); } - unsigned getByValSize() const { - return (unsigned)((Flags & ByValSize) >> ByValSizeOffs); - } - void setByValSize(unsigned S) { - Flags = (Flags & ~ByValSize) | (uint64_t(S) << ByValSizeOffs); + unsigned getOrigAlign() const { return (1U << OrigAlign) / 2; } + void setOrigAlign(unsigned A) { + OrigAlign = Log2_32(A) + 1; + assert(getOrigAlign() == A && "bitfield overflow"); } - /// getRawBits - Represent the flags as a bunch of bits. - uint64_t getRawBits() const { return Flags; } + unsigned getByValSize() const { return ByValSize; } + void setByValSize(unsigned S) { ByValSize = S; } }; /// InputArg - This struct carries flags and type information about a @@ -162,9 +136,9 @@ namespace ISD { /// struct InputArg { ArgFlagsTy Flags; - MVT VT; + MVT VT = MVT::Other; EVT ArgVT; - bool Used; + bool Used = false; /// Index original Function's argument. unsigned OrigArgIndex; @@ -176,7 +150,7 @@ namespace ISD { /// registers, we got 4 InputArgs with PartOffsets 0, 4, 8 and 12. unsigned PartOffset; - InputArg() : VT(MVT::Other), Used(false) {} + InputArg() = default; InputArg(ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx, unsigned partOffs) : Flags(flags), Used(used), OrigArgIndex(origIdx), PartOffset(partOffs) { @@ -204,7 +178,7 @@ namespace ISD { EVT ArgVT; /// IsFixed - Is this a "fixed" value, ie not passed through a vararg "...". - bool IsFixed; + bool IsFixed = false; /// Index original Function's argument. unsigned OrigArgIndex; @@ -214,7 +188,7 @@ namespace ISD { /// registers, we got 4 OutputArgs with PartOffsets 0, 4, 8 and 12. unsigned PartOffset; - OutputArg() : IsFixed(false) {} + OutputArg() = default; OutputArg(ArgFlagsTy flags, EVT vt, EVT argvt, bool isfixed, unsigned origIdx, unsigned partOffs) : Flags(flags), IsFixed(isfixed), OrigArgIndex(origIdx), @@ -223,8 +197,8 @@ namespace ISD { ArgVT = argvt; } }; -} // end namespace ISD -} // end llvm namespace +} // end namespace ISD +} // end namespace llvm #endif // LLVM_TARGET_TARGETCALLINGCONV_H diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h index 247d694f2e47..0dc9cf70d335 100644 --- a/include/llvm/Target/TargetInstrInfo.h +++ b/include/llvm/Target/TargetInstrInfo.h @@ -152,6 +152,31 @@ public: unsigned getCallFrameSetupOpcode() const { return CallFrameSetupOpcode; } unsigned getCallFrameDestroyOpcode() const { return CallFrameDestroyOpcode; } + /// Returns true if the argument is a frame pseudo instruction. + bool isFrameInstr(const MachineInstr &I) const { + return I.getOpcode() == getCallFrameSetupOpcode() || + I.getOpcode() == getCallFrameDestroyOpcode(); + } + + /// Returns true if the argument is a frame setup pseudo instruction. + bool isFrameSetup(const MachineInstr &I) const { + return I.getOpcode() == getCallFrameSetupOpcode(); + } + + /// Returns size of the frame associated with the given frame instruction. + /// For frame setup instruction this is frame that is set up space set up + /// after the instruction. For frame destroy instruction this is the frame + /// freed by the caller. + /// Note, in some cases a call frame (or a part of it) may be prepared prior + /// to the frame setup instruction. It occurs in the calls that involve + /// inalloca arguments. This function reports only the size of the frame part + /// that is set up between the frame setup and destroy pseudo instructions. + int64_t getFrameSize(const MachineInstr &I) const { + assert(isFrameInstr(I)); + assert(I.getOperand(0).getImm() >= 0); + return I.getOperand(0).getImm(); + } + unsigned getCatchReturnOpcode() const { return CatchRetOpcode; } unsigned getReturnOpcode() const { return ReturnOpcode; } @@ -1070,15 +1095,6 @@ public: llvm_unreachable("target did not implement shouldClusterMemOps()"); } - /// Can this target fuse the given instructions if they are scheduled - /// adjacent. Note that you have to add: - /// DAG.addMutation(createMacroFusionDAGMutation()); - /// to TargetPassConfig::createMachineScheduler() to have an effect. - virtual bool shouldScheduleAdjacent(const MachineInstr &First, - const MachineInstr &Second) const { - llvm_unreachable("target did not implement shouldScheduleAdjacent()"); - } - /// Reverses the branch condition of the specified condition list, /// returning false on success and true if it cannot be reversed. virtual @@ -1108,6 +1124,25 @@ public: /// terminator instruction that has not been predicated. virtual bool isUnpredicatedTerminator(const MachineInstr &MI) const; + /// Returns true if MI is an unconditional tail call. + virtual bool isUnconditionalTailCall(const MachineInstr &MI) const { + return false; + } + + /// Returns true if the tail call can be made conditional on BranchCond. + virtual bool + canMakeTailCallConditional(SmallVectorImpl<MachineOperand> &Cond, + const MachineInstr &TailCall) const { + return false; + } + + /// Replace the conditional branch in MBB with a conditional tail call. + virtual void replaceBranchWithTailCall(MachineBasicBlock &MBB, + SmallVectorImpl<MachineOperand> &Cond, + const MachineInstr &TailCall) const { + llvm_unreachable("Target didn't implement replaceBranchWithTailCall!"); + } + /// Convert the instruction into a predicated instruction. /// It returns true if the operation was successful. virtual bool PredicateInstruction(MachineInstr &MI, @@ -1132,7 +1167,7 @@ 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 { + virtual bool isPredicable(const MachineInstr &MI) const { return MI.getDesc().isPredicable(); } @@ -1427,10 +1462,17 @@ public: return nullptr; } - // Sometimes, it is possible for the target - // to tell, even without aliasing information, that two MIs access different - // memory addresses. This function returns true if two MIs access different - // memory addresses and false otherwise. + /// Sometimes, it is possible for the target + /// to tell, even without aliasing information, that two MIs access different + /// memory addresses. This function returns true if two MIs access different + /// memory addresses and false otherwise. + /// + /// Assumes any physical registers used to compute addresses have the same + /// value for both instructions. (This is the most useful assumption for + /// post-RA scheduling.) + /// + /// See also MachineInstr::mayAlias, which is implemented on top of this + /// function. virtual bool areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb, AliasAnalysis *AA = nullptr) const { @@ -1486,11 +1528,79 @@ public: return None; } - /// Determines whether |Inst| is a tail call instruction. + /// Determines whether \p Inst is a tail call instruction. Override this + /// method on targets that do not properly set MCID::Return and MCID::Call on + /// tail call instructions." virtual bool isTailCall(const MachineInstr &Inst) const { + return Inst.isReturn() && Inst.isCall(); + } + + /// True if the instruction is bound to the top of its basic block and no + /// other instructions shall be inserted before it. This can be implemented + /// to prevent register allocator to insert spills before such instructions. + virtual bool isBasicBlockPrologue(const MachineInstr &MI) const { return false; } + /// \brief Return how many instructions would be saved by outlining a + /// sequence containing \p SequenceSize instructions that appears + /// \p Occurrences times in a module. + virtual unsigned getOutliningBenefit(size_t SequenceSize, size_t Occurrences, + bool CanBeTailCall) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::getOutliningBenefit!"); + } + + /// Represents how an instruction should be mapped by the outliner. + /// \p Legal instructions are those which are safe to outline. + /// \p Illegal instructions are those which cannot be outlined. + /// \p Invisible instructions are instructions which can be outlined, but + /// shouldn't actually impact the outlining result. + enum MachineOutlinerInstrType {Legal, Illegal, Invisible}; + + /// Returns how or if \p MI should be outlined. + virtual MachineOutlinerInstrType getOutliningType(MachineInstr &MI) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::getOutliningType!"); + } + + /// Insert a custom epilogue for outlined functions. + /// This may be empty, in which case no epilogue or return statement will be + /// emitted. + virtual void insertOutlinerEpilogue(MachineBasicBlock &MBB, + MachineFunction &MF, + bool IsTailCall) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::insertOutlinerEpilogue!"); + } + + /// Insert a call to an outlined function into the program. + /// Returns an iterator to the spot where we inserted the call. This must be + /// implemented by the target. + virtual MachineBasicBlock::iterator + insertOutlinedCall(Module &M, MachineBasicBlock &MBB, + MachineBasicBlock::iterator &It, MachineFunction &MF, + bool IsTailCall) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::insertOutlinedCall!"); + } + + /// Insert a custom prologue for outlined functions. + /// This may be empty, in which case no prologue will be emitted. + virtual void insertOutlinerPrologue(MachineBasicBlock &MBB, + MachineFunction &MF, + bool IsTailCall) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::insertOutlinerPrologue!"); + } + + /// Return true if the function can safely be outlined from. + /// By default, this means that the function has no red zone. + virtual bool isFunctionSafeToOutlineFrom(MachineFunction &MF) const { + llvm_unreachable("Target didn't implement " + "TargetInstrInfo::isFunctionSafeToOutlineFrom!"); + } + private: unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode; unsigned CatchRetOpcode; diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 3728a7a8cb17..85297ae837c5 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -25,13 +25,14 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/DAGCombine.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/RuntimeLibcalls.h" +#include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/Attributes.h" @@ -163,6 +164,35 @@ public: // or custom. }; + class ArgListEntry { + public: + Value *Val = nullptr; + SDValue Node = SDValue(); + Type *Ty = nullptr; + bool IsSExt : 1; + bool IsZExt : 1; + bool IsInReg : 1; + bool IsSRet : 1; + bool IsNest : 1; + bool IsByVal : 1; + bool IsInAlloca : 1; + bool IsReturned : 1; + bool IsSwiftSelf : 1; + bool IsSwiftError : 1; + uint16_t Alignment = 0; + + ArgListEntry() + : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), + IsNest(false), IsByVal(false), IsInAlloca(false), IsReturned(false), + IsSwiftSelf(false), IsSwiftError(false) {} + + void setAttributes(ImmutableCallSite *CS, unsigned ArgIdx); + }; + typedef std::vector<ArgListEntry> ArgListTy; + + virtual void markLibCallAttributes(MachineFunction *MF, unsigned CC, + ArgListTy &Args) const {}; + static ISD::NodeType getExtendForContent(BooleanContent Content) { switch (Content) { case UndefinedBooleanContent: @@ -254,9 +284,7 @@ public: /// several shifts, adds, and multiplies for this target. /// The definition of "cheaper" may depend on whether we're optimizing /// for speed or for size. - virtual bool isIntDivCheap(EVT VT, AttributeSet Attr) const { - return false; - } + virtual bool isIntDivCheap(EVT VT, AttributeList Attr) const { return false; } /// Return true if the target can handle a standalone remainder operation. virtual bool hasStandaloneRem(EVT VT) const { @@ -363,6 +391,9 @@ public: return false; } + /// Returns if it's reasonable to merge stores to MemVT size. + virtual bool canMergeStoresTo(EVT MemVT) const { return true; } + /// \brief Return true if it is cheap to speculate a call to intrinsic cttz. virtual bool isCheapToSpeculateCttz() const { return false; @@ -395,16 +426,33 @@ public: /// \brief Return if the target supports combining a /// chain like: /// \code - /// %andResult = and %val1, #imm-with-one-bit-set; + /// %andResult = and %val1, #mask /// %icmpResult = icmp %andResult, 0 - /// br i1 %icmpResult, label %dest1, label %dest2 /// \endcode /// into a single machine instruction of a form like: /// \code - /// brOnBitSet %register, #bitNumber, dest + /// cc = test %register, #mask /// \endcode - bool isMaskAndBranchFoldingLegal() const { - return MaskAndBranchFoldingIsLegal; + virtual bool isMaskAndCmp0FoldingBeneficial(const Instruction &AndI) const { + return false; + } + + /// Use bitwise logic to make pairs of compares more efficient. For example: + /// and (seteq A, B), (seteq C, D) --> seteq (or (xor A, B), (xor C, D)), 0 + /// This should be true when it takes more than one instruction to lower + /// setcc (cmp+set on x86 scalar), when bitwise ops are faster than logic on + /// condition bits (crand on PowerPC), and/or when reducing cmp+br is a win. + virtual bool convertSetCCLogicToBitwiseLogic(EVT VT) const { + return false; + } + + /// Return the preferred operand type if the target has a quick way to compare + /// integer values of the given size. Assume that any legal integer type can + /// be compared efficiently. Targets may override this to allow illegal wide + /// types to return a vector type if there is support to compare that type. + virtual MVT hasFastEqualityCompare(unsigned NumBits) const { + MVT VT = MVT::getIntegerVT(NumBits); + return isTypeLegal(VT) ? VT : MVT::INVALID_SIMPLE_VALUE_TYPE; } /// Return true if the target should transform: @@ -987,6 +1035,11 @@ public: return GatherAllAliasesMaxDepth; } + /// Returns the size of the platform's va_list object. + virtual unsigned getVaListSizeInBits(const DataLayout &DL) const { + return getPointerTy(DL).getSizeInBits(); + } + /// \brief Get maximum # of store operations permitted for llvm.memset /// /// This function returns the maximum number of store operations permitted @@ -1384,6 +1437,13 @@ public: Action != TypeSplitVector; } + /// Return true if a select of constants (select Cond, C1, C2) should be + /// transformed into simple math ops with the condition value. For example: + /// select Cond, C1, C1-1 --> add (zext Cond), C1-1 + virtual bool convertSelectOfConstantsToMath() const { + return false; + } + //===--------------------------------------------------------------------===// // TargetLowering Configuration Methods - These methods should be invoked by // the derived class constructor to configure this object for the target. @@ -1490,7 +1550,8 @@ protected: void computeRegisterProperties(const TargetRegisterInfo *TRI); /// Indicate that the specified operation does not work with the specified - /// type and indicate what to do about it. + /// type and indicate what to do about it. Note that VT may refer to either + /// the type of a result or that of an operand of Op. void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action) { assert(Op < array_lengthof(OpActions[0]) && "Table isn't big enough!"); @@ -1642,10 +1703,9 @@ public: /// possible to be done in the address mode for that operand. This hook lets /// targets also pass back when this should be done on intrinsics which /// load/store. - virtual bool GetAddrModeArguments(IntrinsicInst * /*I*/, + virtual bool getAddrModeArguments(IntrinsicInst * /*I*/, SmallVectorImpl<Value*> &/*Ops*/, - Type *&/*AccessTy*/, - unsigned AddrSpace = 0) const { + Type *&/*AccessTy*/) const { return false; } @@ -2197,10 +2257,6 @@ protected: /// the branch is usually predicted right. bool PredictableSelectIsExpensive; - /// MaskAndBranchFoldingIsLegal - Indicates if the target supports folding - /// a mask of a single bit, a compare, and a branch into a single instruction. - bool MaskAndBranchFoldingIsLegal; - /// \see enableExtLdPromotion. bool EnableExtLdPromotion; @@ -2357,11 +2413,11 @@ public: /// expression and return a mask of KnownOne and KnownZero bits for the /// expression (used to simplify the caller). The KnownZero/One bits may only /// be accurate for those bits in the DemandedMask. - /// \p AssumeSingleUse When this paramater is true, this function will + /// \p AssumeSingleUse When this parameter is true, this function will /// attempt to simplify \p Op even if there are multiple uses. /// Callers are responsible for correctly updating the DAG based on the /// results of this function, because simply replacing replacing TLO.Old - /// with TLO.New will be incorrect when this paramater is true and TLO.Old + /// with TLO.New will be incorrect when this parameter is true and TLO.Old /// has multiple uses. bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedMask, APInt &KnownZero, APInt &KnownOne, @@ -2369,17 +2425,27 @@ public: unsigned Depth = 0, bool AssumeSingleUse = false) const; + /// Helper wrapper around SimplifyDemandedBits + bool SimplifyDemandedBits(SDValue Op, APInt &DemandedMask, + DAGCombinerInfo &DCI) const; + /// Determine which of the bits specified in Mask are known to be either zero - /// or one and return them in the KnownZero/KnownOne bitsets. + /// or one and return them in the KnownZero/KnownOne bitsets. The DemandedElts + /// argument allows us to only collect the known bits that are shared by the + /// requested vector elements. virtual void computeKnownBitsForTargetNode(const SDValue Op, APInt &KnownZero, APInt &KnownOne, + const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth = 0) const; /// This method can be implemented by targets that want to expose additional - /// information about sign bits to the DAG Combiner. + /// information about sign bits to the DAG Combiner. The DemandedElts + /// argument allows us to only collect the minimum sign bits that are shared + /// by the requested vector elements. virtual unsigned ComputeNumSignBitsForTargetNode(SDValue Op, + const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth = 0) const; @@ -2536,30 +2602,6 @@ public: llvm_unreachable("Not Implemented"); } - struct ArgListEntry { - SDValue Node; - Type* Ty; - bool isSExt : 1; - bool isZExt : 1; - bool isInReg : 1; - bool isSRet : 1; - bool isNest : 1; - 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), isSwiftSelf(false), isSwiftError(false), - Alignment(0) {} - - void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx); - }; - typedef std::vector<ArgListEntry> ArgListTy; - /// This structure contains all information that is necessary for lowering /// calls. It is passed to TLI::LowerCallTo when the SelectionDAG builder /// needs to lower a call, and targets will see this struct in their LowerCall @@ -2609,6 +2651,20 @@ public: return *this; } + // setCallee with target/module-specific attributes + CallLoweringInfo &setLibCallee(CallingConv::ID CC, Type *ResultType, + SDValue Target, ArgListTy &&ArgsList) { + RetTy = ResultType; + Callee = Target; + CallConv = CC; + NumFixedArgs = Args.size(); + Args = std::move(ArgsList); + + DAG.getTargetLoweringInfo().markLibCallAttributes( + &(DAG.getMachineFunction()), CC, Args); + return *this; + } + CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultType, SDValue Target, ArgListTy &&ArgsList) { RetTy = ResultType; @@ -2624,15 +2680,15 @@ public: ImmutableCallSite &Call) { RetTy = ResultType; - IsInReg = Call.paramHasAttr(0, Attribute::InReg); + IsInReg = Call.hasRetAttr(Attribute::InReg); DoesNotReturn = Call.doesNotReturn() || (!Call.isInvoke() && isa<UnreachableInst>(Call.getInstruction()->getNextNode())); IsVarArg = FTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); - RetSExt = Call.paramHasAttr(0, Attribute::SExt); - RetZExt = Call.paramHasAttr(0, Attribute::ZExt); + RetSExt = Call.hasRetAttr(Attribute::SExt); + RetZExt = Call.hasRetAttr(Attribute::ZExt); Callee = Target; @@ -3183,7 +3239,7 @@ private: /// Given an LLVM IR type and return type attributes, compute the return value /// EVTs and flags, and optionally also the offsets, if the return value is /// being lowered to memory. -void GetReturnInfo(Type *ReturnType, AttributeSet attr, +void GetReturnInfo(Type *ReturnType, AttributeList attr, SmallVectorImpl<ISD::OutputArg> &Outs, const TargetLowering &TLI, const DataLayout &DL); diff --git a/include/llvm/Target/TargetLoweringObjectFile.h b/include/llvm/Target/TargetLoweringObjectFile.h index 72bae0a38e65..0ffd4b7f8c78 100644 --- a/include/llvm/Target/TargetLoweringObjectFile.h +++ b/include/llvm/Target/TargetLoweringObjectFile.h @@ -16,37 +16,35 @@ #define LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/SectionKind.h" +#include <cstdint> namespace llvm { - class MachineModuleInfo; - class Mangler; - class MCContext; - class MCExpr; - class MCSection; - class MCSymbol; - class MCSymbolRefExpr; - class MCStreamer; - class MCValue; - class ConstantExpr; - class GlobalValue; - class TargetMachine; + +class GlobalValue; +class MachineModuleInfo; +class Mangler; +class MCContext; +class MCExpr; +class MCSection; +class MCSymbol; +class MCSymbolRefExpr; +class MCStreamer; +class MCValue; +class TargetMachine; class TargetLoweringObjectFile : public MCObjectFileInfo { - MCContext *Ctx; + MCContext *Ctx = nullptr; /// Name-mangler for global names. Mangler *Mang = nullptr; - TargetLoweringObjectFile( - const TargetLoweringObjectFile&) = delete; - void operator=(const TargetLoweringObjectFile&) = delete; - protected: - bool SupportIndirectSymViaGOTPCRel; - bool SupportGOTPCRelWithOffset; + bool SupportIndirectSymViaGOTPCRel = false; + bool SupportGOTPCRelWithOffset = true; /// This section contains the static constructor pointer list. MCSection *StaticCtorSection; @@ -55,15 +53,15 @@ protected: MCSection *StaticDtorSection; public: + TargetLoweringObjectFile() = default; + TargetLoweringObjectFile(const TargetLoweringObjectFile &) = delete; + TargetLoweringObjectFile & + operator=(const TargetLoweringObjectFile &) = delete; + virtual ~TargetLoweringObjectFile(); + MCContext &getContext() const { return *Ctx; } Mangler &getMangler() const { return *Mang; } - TargetLoweringObjectFile() - : MCObjectFileInfo(), Ctx(nullptr), Mang(nullptr), - SupportIndirectSymViaGOTPCRel(false), SupportGOTPCRelWithOffset(true) {} - - virtual ~TargetLoweringObjectFile(); - /// This method must be called before any actual lowering is done. This /// specifies the current context for codegen, and gives the lowering /// implementations a chance to set up their default sections. @@ -194,4 +192,4 @@ protected: } // end namespace llvm -#endif +#endif // LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index b1d8f8f1e917..73ae2ad12988 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -34,6 +34,7 @@ class MCRegisterInfo; class MCSubtargetInfo; class MCSymbol; class raw_pwrite_stream; +class PassManagerBuilder; class Target; class TargetIntrinsicInfo; class TargetIRAnalysis; @@ -205,10 +206,9 @@ 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 &) {} + /// Allow the target to modify the pass manager, e.g. by calling + /// PassManagerBuilder::addExtension. + virtual void adjustPassManager(PassManagerBuilder &) {} /// 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 @@ -268,8 +268,8 @@ class LLVMTargetMachine : public TargetMachine { protected: // Can only create subclasses. LLVMTargetMachine(const Target &T, StringRef DataLayoutString, const Triple &TargetTriple, StringRef CPU, StringRef FS, - TargetOptions Options, Reloc::Model RM, CodeModel::Model CM, - CodeGenOpt::Level OL); + const TargetOptions &Options, Reloc::Model RM, + CodeModel::Model CM, CodeGenOpt::Level OL); void initAsmInfo(); public: diff --git a/include/llvm/Target/TargetOpcodes.def b/include/llvm/Target/TargetOpcodes.def index edb9b7350ca7..96db6e0a9769 100644 --- a/include/llvm/Target/TargetOpcodes.def +++ b/include/llvm/Target/TargetOpcodes.def @@ -107,6 +107,9 @@ HANDLE_TARGET_OPCODE(LIFETIME_END) /// that must lie within the function and not contain another stackmap. HANDLE_TARGET_OPCODE(STACKMAP) +/// FEntry all - This is a marker instruction which gets translated into a raw fentry call. +HANDLE_TARGET_OPCODE(FENTRY_CALL) + /// 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 @@ -131,11 +134,13 @@ HANDLE_TARGET_OPCODE(STATEPOINT) /// frame index of the local stack allocation. HANDLE_TARGET_OPCODE(LOCAL_ESCAPE) -/// Loading instruction that may page fault, bundled with associated +/// Wraps a machine instruction which can fault, bundled with associated +/// information on how to handle such a fault. +/// For example 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) +HANDLE_TARGET_OPCODE(FAULTING_OP) /// Wraps a machine instruction to add patchability constraints. An /// instruction wrapped in PATCHABLE_OP has to either have a minimum @@ -224,6 +229,8 @@ HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE) /// (typically a sub-register COPY after instruction selection). HANDLE_TARGET_OPCODE(G_EXTRACT) +HANDLE_TARGET_OPCODE(G_UNMERGE_VALUES) + /// Generic instruction to insert blocks of bits from the registers given into /// the source. HANDLE_TARGET_OPCODE(G_INSERT) @@ -232,6 +239,8 @@ HANDLE_TARGET_OPCODE(G_INSERT) /// larger register. HANDLE_TARGET_OPCODE(G_SEQUENCE) +HANDLE_TARGET_OPCODE(G_MERGE_VALUES) + /// Generic pointer to int conversion. HANDLE_TARGET_OPCODE(G_PTRTOINT) @@ -251,6 +260,9 @@ HANDLE_TARGET_OPCODE(G_STORE) /// Generic conditional branch instruction. HANDLE_TARGET_OPCODE(G_BRCOND) +/// Generic indirect branch instruction. +HANDLE_TARGET_OPCODE(G_BRINDIRECT) + /// Generic intrinsic use (without side effects). HANDLE_TARGET_OPCODE(G_INTRINSIC) @@ -272,6 +284,12 @@ HANDLE_TARGET_OPCODE(G_CONSTANT) /// Generic floating constant. HANDLE_TARGET_OPCODE(G_FCONSTANT) +/// Generic va_start instruction. Stores to its one pointer operand. +HANDLE_TARGET_OPCODE(G_VASTART) + +/// Generic va_start instruction. Stores to its one pointer operand. +HANDLE_TARGET_OPCODE(G_VAARG) + // Generic sign extend HANDLE_TARGET_OPCODE(G_SEXT) @@ -320,6 +338,14 @@ HANDLE_TARGET_OPCODE(G_UMULO) /// overflow flag. HANDLE_TARGET_OPCODE(G_SMULO) +// Multiply two numbers at twice the incoming bit width (unsigned) and return +// the high half of the result. +HANDLE_TARGET_OPCODE(G_UMULH) + +// Multiply two numbers at twice the incoming bit width (signed) and return +// the high half of the result. +HANDLE_TARGET_OPCODE(G_SMULH) + /// Generic FP addition. HANDLE_TARGET_OPCODE(G_FADD) @@ -335,7 +361,13 @@ HANDLE_TARGET_OPCODE(G_FDIV) /// Generic FP remainder. HANDLE_TARGET_OPCODE(G_FREM) -/// Generic float to signed-int conversion +/// Generic FP exponentiation. +HANDLE_TARGET_OPCODE(G_FPOW) + +/// Generic FP negation. +HANDLE_TARGET_OPCODE(G_FNEG) + +/// Generic FP extension. HANDLE_TARGET_OPCODE(G_FPEXT) /// Generic float to signed-int conversion @@ -353,18 +385,31 @@ HANDLE_TARGET_OPCODE(G_SITOFP) /// Generic unsigned-int to float conversion HANDLE_TARGET_OPCODE(G_UITOFP) -/// Generic unsigned-int to float conversion +/// Generic pointer offset HANDLE_TARGET_OPCODE(G_GEP) +/// Clear the specified number of low bits in a pointer. This rounds the value +/// *down* to the given alignment. +HANDLE_TARGET_OPCODE(G_PTR_MASK) + /// Generic BRANCH instruction. This is an unconditional branch. HANDLE_TARGET_OPCODE(G_BR) +/// Generic insertelement. +HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT) + +/// Generic extractelement. +HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT) + +/// Generic shufflevector. +HANDLE_TARGET_OPCODE(G_SHUFFLE_VECTOR) + // 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) +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_SHUFFLE_VECTOR) /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific post-isel opcode values start here. diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h index f5134d99b039..7cc33f2fdccb 100644 --- a/include/llvm/Target/TargetOptions.h +++ b/include/llvm/Target/TargetOptions.h @@ -99,22 +99,16 @@ namespace llvm { class TargetOptions { public: TargetOptions() - : PrintMachineCode(false), LessPreciseFPMADOption(false), - UnsafeFPMath(false), NoInfsFPMath(false), NoNaNsFPMath(false), - NoTrappingFPMath(false), + : PrintMachineCode(false), UnsafeFPMath(false), NoInfsFPMath(false), + NoNaNsFPMath(false), NoTrappingFPMath(false), + NoSignedZerosFPMath(false), HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false), - GuaranteedTailCallOpt(false), StackAlignmentOverride(0), - StackSymbolOrdering(true), EnableFastISel(false), UseInitArray(false), + GuaranteedTailCallOpt(false), StackSymbolOrdering(true), + EnableFastISel(false), UseInitArray(false), DisableIntegratedAS(false), CompressDebugSections(false), RelaxELFRelocations(false), FunctionSections(false), DataSections(false), UniqueSectionNames(true), TrapUnreachable(false), - EmulatedTLS(false), EnableIPRA(false), - FloatABIType(FloatABI::Default), - AllowFPOpFusion(FPOpFusion::Standard), - ThreadModel(ThreadModel::POSIX), - EABIVersion(EABI::Default), DebuggerTuning(DebuggerKind::Default), - FPDenormalMode(FPDenormal::IEEE), - ExceptionModel(ExceptionHandling::None) {} + EmulatedTLS(false), EnableIPRA(false) {} /// PrintMachineCode - This flag is enabled when the -print-machineinstrs /// option is specified on the command line, and should enable debugging @@ -125,20 +119,11 @@ namespace llvm { /// optimization should be disabled for the given machine function. bool DisableFramePointerElim(const MachineFunction &MF) const; - /// LessPreciseFPMAD - This flag is enabled when the - /// -enable-fp-mad is specified on the command line. When this flag is off - /// (the default), the code generator is not allowed to generate mad - /// (multiply add) if the result is "less precise" than doing those - /// operations individually. - unsigned LessPreciseFPMADOption : 1; - bool LessPreciseFPMAD() const; - /// UnsafeFPMath - This flag is enabled when the /// -enable-unsafe-fp-math flag is specified on the command line. When /// this flag is off (the default), the code generator is not allowed to /// produce results that are "less precise" than IEEE allows. This includes /// use of X86 instructions like FSIN and FCOS instead of libcalls. - /// UnsafeFPMath implies LessPreciseFPMAD. unsigned UnsafeFPMath : 1; /// NoInfsFPMath - This flag is enabled when the @@ -153,11 +138,17 @@ namespace llvm { /// assume the FP arithmetic arguments and results are never NaNs. unsigned NoNaNsFPMath : 1; - /// NoTrappingFPMath - This flag is enabled when the - /// -enable-no-trapping-fp-math is specified on the command line. This + /// NoTrappingFPMath - This flag is enabled when the + /// -enable-no-trapping-fp-math is specified on the command line. This /// specifies that there are no trap handlers to handle exceptions. unsigned NoTrappingFPMath : 1; + /// NoSignedZerosFPMath - This flag is enabled when the + /// -enable-no-signed-zeros-fp-math is specified on the command line. This + /// specifies that optimizations are allowed to treat the sign of a zero + /// argument or result as insignificant. + unsigned NoSignedZerosFPMath : 1; + /// HonorSignDependentRoundingFPMath - This returns true when the /// -enable-sign-dependent-rounding-fp-math is specified. If this returns /// false (the default), the code generator is allowed to assume that the @@ -182,7 +173,7 @@ namespace llvm { unsigned GuaranteedTailCallOpt : 1; /// StackAlignmentOverride - Override default stack alignment for target. - unsigned StackAlignmentOverride; + unsigned StackAlignmentOverride = 0; /// StackSymbolOrdering - When true, this will allow CodeGen to order /// the local stack symbols (for code size, code locality, or any other @@ -231,7 +222,7 @@ namespace llvm { /// software floating point, but does not indicate that FP hardware may not /// be used. Such a combination is unfortunately popular (e.g. /// arm-apple-darwin). Hard presumes that the normal FP ABI is used. - FloatABI::ABIType FloatABIType; + FloatABI::ABIType FloatABIType = FloatABI::Default; /// AllowFPOpFusion - This flag is set by the -fuse-fp-ops=xxx option. /// This controls the creation of fused FP ops that store intermediate @@ -249,65 +240,29 @@ namespace llvm { /// optimizers. Fused operations that are explicitly specified (e.g. FMA /// via the llvm.fma.* intrinsic) will always be honored, regardless of /// the value of this option. - FPOpFusion::FPOpFusionMode AllowFPOpFusion; + FPOpFusion::FPOpFusionMode AllowFPOpFusion = FPOpFusion::Standard; /// ThreadModel - This flag specifies the type of threading model to assume /// for things like atomics - ThreadModel::Model ThreadModel; + ThreadModel::Model ThreadModel = ThreadModel::POSIX; /// EABIVersion - This flag specifies the EABI version - EABI EABIVersion; + EABI EABIVersion = EABI::Default; /// Which debugger to tune for. - DebuggerKind DebuggerTuning; + DebuggerKind DebuggerTuning = DebuggerKind::Default; /// FPDenormalMode - This flags specificies which denormal numbers the code /// is permitted to require. - FPDenormal::DenormalMode FPDenormalMode; + FPDenormal::DenormalMode FPDenormalMode = FPDenormal::IEEE; /// What exception model to use - ExceptionHandling ExceptionModel; + ExceptionHandling ExceptionModel = ExceptionHandling::None; /// Machine level options. MCTargetOptions MCOptions; }; -// Comparison operators: - - -inline bool operator==(const TargetOptions &LHS, - const TargetOptions &RHS) { -#define ARE_EQUAL(X) LHS.X == RHS.X - return - ARE_EQUAL(UnsafeFPMath) && - ARE_EQUAL(NoInfsFPMath) && - ARE_EQUAL(NoNaNsFPMath) && - ARE_EQUAL(NoTrappingFPMath) && - ARE_EQUAL(HonorSignDependentRoundingFPMathOption) && - ARE_EQUAL(NoZerosInBSS) && - ARE_EQUAL(GuaranteedTailCallOpt) && - ARE_EQUAL(StackAlignmentOverride) && - ARE_EQUAL(EnableFastISel) && - ARE_EQUAL(UseInitArray) && - ARE_EQUAL(TrapUnreachable) && - ARE_EQUAL(EmulatedTLS) && - ARE_EQUAL(FloatABIType) && - ARE_EQUAL(AllowFPOpFusion) && - ARE_EQUAL(ThreadModel) && - ARE_EQUAL(EABIVersion) && - ARE_EQUAL(DebuggerTuning) && - ARE_EQUAL(FPDenormalMode) && - ARE_EQUAL(ExceptionModel) && - ARE_EQUAL(MCOptions) && - ARE_EQUAL(EnableIPRA); -#undef ARE_EQUAL -} - -inline bool operator!=(const TargetOptions &LHS, - const TargetOptions &RHS) { - return !(LHS == RHS); -} - } // End llvm namespace #endif diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index 3080e9a32c3a..3f5daea63ab5 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -45,6 +45,7 @@ public: // Instance variables filled by tablegen, do not use! const MCRegisterClass *MC; + const uint16_t SpillSize, SpillAlignment; const vt_iterator VTs; const uint32_t *SubClassMask; const uint16_t *SuperRegIndices; @@ -94,10 +95,10 @@ public: /// Return the size of the register in bytes, which is also the size /// of a stack slot allocated to hold a spilled copy of this register. - unsigned getSize() const { return MC->getSize(); } + unsigned getSize() const { return SpillSize; } /// Return the minimum required alignment for a register of this class. - unsigned getAlignment() const { return MC->getAlignment(); } + unsigned getAlignment() const { return SpillAlignment; } /// Return the cost of copying a value between two registers in this class. /// A negative number means the register class is very expensive @@ -426,7 +427,9 @@ public: /// this target. The register should be in the order of desired callee-save /// stack frame offset. The first register is closest to the incoming stack /// pointer if stack grows down, and vice versa. - /// + /// Notice: This function does not take into account disabled CSRs. + /// In most cases you will want to use instead the function + /// getCalleeSavedRegs that is implemented in MachineRegisterInfo. virtual const MCPhysReg* getCalleeSavedRegs(const MachineFunction *MF) const = 0; @@ -633,6 +636,9 @@ public: /// regclass_iterator regclass_begin() const { return RegClassBegin; } regclass_iterator regclass_end() const { return RegClassEnd; } + iterator_range<regclass_iterator> regclasses() const { + return make_range(regclass_begin(), regclass_end()); + } unsigned getNumRegClasses() const { return (unsigned)(regclass_end()-regclass_begin()); diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index 74b98ac5f6c5..d342e4fe2613 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -139,7 +139,7 @@ class ProcResourceKind; // changes this to an in-order issue/dispatch resource. In this case, // the scheduler counts down from the cycle that the instruction // issues in-order, forcing a stall whenever a subsequent instruction -// requires the same resource until the number of ResourceCyles +// requires the same resource until the number of ResourceCycles // specified in WriteRes expire. Setting BufferSize=1 changes this to // an in-order latency resource. In this case, the scheduler models // producer/consumer stalls between instructions that use the @@ -255,6 +255,9 @@ class ProcWriteResources<list<ProcResourceKind> resources> { // Allow a processor to mark some scheduling classes as unsupported // for stronger verification. bit Unsupported = 0; + // Allow a processor to mark some scheduling classes as single-issue. + // SingleIssue is an alias for Begin/End Group. + bit SingleIssue = 0; SchedMachineModel SchedModel = ?; } diff --git a/include/llvm/Target/TargetSelectionDAG.td b/include/llvm/Target/TargetSelectionDAG.td index 55e2c2bce3db..45a842f77a21 100644 --- a/include/llvm/Target/TargetSelectionDAG.td +++ b/include/llvm/Target/TargetSelectionDAG.td @@ -136,30 +136,34 @@ def SDTIntUnaryOp : SDTypeProfile<1, 1, [ // ctlz SDTCisSameAs<0, 1>, SDTCisInt<0> ]>; def SDTIntExtendOp : SDTypeProfile<1, 1, [ // sext, zext, anyext - SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<1, 0> + SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<1, 0>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTIntTruncOp : SDTypeProfile<1, 1, [ // trunc - SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<0, 1> + SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<0, 1>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTFPUnaryOp : SDTypeProfile<1, 1, [ // fneg, fsqrt, etc SDTCisSameAs<0, 1>, SDTCisFP<0> ]>; def SDTFPRoundOp : SDTypeProfile<1, 1, [ // fround - SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<0, 1> + SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<0, 1>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTFPExtendOp : SDTypeProfile<1, 1, [ // fextend - SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<1, 0> + SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<1, 0>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTIntToFPOp : SDTypeProfile<1, 1, [ // [su]int_to_fp - SDTCisFP<0>, SDTCisInt<1> + SDTCisFP<0>, SDTCisInt<1>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTFPToIntOp : SDTypeProfile<1, 1, [ // fp_to_[su]int - SDTCisInt<0>, SDTCisFP<1> + SDTCisInt<0>, SDTCisFP<1>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTExtInreg : SDTypeProfile<1, 2, [ // sext_inreg SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisVT<2, OtherVT>, SDTCisVTSmallerThanOp<2, 1> ]>; +def SDTExtInvec : SDTypeProfile<1, 1, [ // sext_invec + SDTCisInt<0>, SDTCisVec<0>, SDTCisInt<1>, SDTCisVec<1>, + SDTCisOpSmallerThanOp<1, 0>, SDTCisSameSizeAs<0,1> +]>; def SDTSetCC : SDTypeProfile<1, 3, [ // setcc SDTCisInt<0>, SDTCisSameAs<1, 2>, SDTCisVT<3, OtherVT> @@ -170,7 +174,7 @@ def SDTSelect : SDTypeProfile<1, 3, [ // select ]>; def SDTVSelect : SDTypeProfile<1, 3, [ // vselect - SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>, SDTCisSameNumEltsAs<0, 1> + SDTCisVec<0>, SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>, SDTCisSameNumEltsAs<0, 1> ]>; def SDTSelectCC : SDTypeProfile<1, 5, [ // select_cc @@ -406,6 +410,10 @@ def umax : SDNode<"ISD::UMAX" , SDTIntBinOp, [SDNPCommutative, SDNPAssociative]>; def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>; +def sext_invec : SDNode<"ISD::SIGN_EXTEND_VECTOR_INREG", SDTExtInvec>; +def zext_invec : SDNode<"ISD::ZERO_EXTEND_VECTOR_INREG", SDTExtInvec>; + +def abs : SDNode<"ISD::ABS" , SDTIntUnaryOp>; def bitreverse : SDNode<"ISD::BITREVERSE" , SDTIntUnaryOp>; def bswap : SDNode<"ISD::BSWAP" , SDTIntUnaryOp>; def ctlz : SDNode<"ISD::CTLZ" , SDTIntUnaryOp>; diff --git a/include/llvm/Target/TargetSubtargetInfo.h b/include/llvm/Target/TargetSubtargetInfo.h index 0b4351596021..83950a9cd027 100644 --- a/include/llvm/Target/TargetSubtargetInfo.h +++ b/include/llvm/Target/TargetSubtargetInfo.h @@ -20,6 +20,7 @@ #include "llvm/CodeGen/PBQPRAConstraint.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/ScheduleDAGMutation.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/CodeGen.h" #include <memory> @@ -143,6 +144,9 @@ public: /// TargetLowering preference). It does not yet disable the postRA scheduler. virtual bool enableMachineScheduler() const; + /// \brief Support printing of [latency:throughput] comment in output .S file. + virtual bool supportPrintSchedInfo() const { return false; } + /// \brief True if the machine scheduler should disable the TLI preference /// for preRA scheduling with the source level scheduler. virtual bool enableMachineSchedDefaultSched() const { return true; } @@ -227,6 +231,10 @@ public: /// Please use MachineRegisterInfo::subRegLivenessEnabled() instead where /// possible. virtual bool enableSubRegLiveness() const { return false; } + + /// Returns string representation of scheduler comment + std::string getSchedInfoStr(const MachineInstr &MI) const override; + std::string getSchedInfoStr(MCInst const &MCI) const override; }; } // end namespace llvm diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index dd55062e56f1..39ceb19525b3 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -50,12 +50,12 @@ ModulePass *createStripNonLineTableDebugInfoPass(); //===----------------------------------------------------------------------===// // -// These pass removes llvm.dbg.declare intrinsics. +// This pass removes llvm.dbg.declare intrinsics. ModulePass *createStripDebugDeclarePass(); //===----------------------------------------------------------------------===// // -// These pass removes unused symbols' debug info. +// This pass removes unused symbols' debug info. ModulePass *createStripDeadDebugInfoPass(); //===----------------------------------------------------------------------===// @@ -108,7 +108,8 @@ Pass *createFunctionImportPass(); /// threshold given here. Pass *createFunctionInliningPass(); Pass *createFunctionInliningPass(int Threshold); -Pass *createFunctionInliningPass(unsigned OptLevel, unsigned SizeOptLevel); +Pass *createFunctionInliningPass(unsigned OptLevel, unsigned SizeOptLevel, + bool DisableInlineHotCallSite); Pass *createFunctionInliningPass(InlineParams &Params); //===----------------------------------------------------------------------===// @@ -215,27 +216,42 @@ ModulePass *createMetaRenamerPass(); /// manager. ModulePass *createBarrierNoopPass(); -/// What to do with the summary when running the LowerTypeTests pass. -enum class LowerTypeTestsSummaryAction { +/// What to do with the summary when running passes that operate on it. +enum class PassSummaryAction { None, ///< Do nothing. - Import, ///< Import typeid resolutions from summary and globals. - Export, ///< Export typeid resolutions to summary and globals. + Import, ///< Import information from summary. + Export, ///< Export information to summary. }; /// \brief This pass lowers type metadata and the llvm.type.test intrinsic to /// bitsets. -/// \param Action What to do with the summary passed as Index. -/// \param Index The summary to use for importing or exporting, this can be null -/// when Action is None. -ModulePass *createLowerTypeTestsPass(LowerTypeTestsSummaryAction Action, - ModuleSummaryIndex *Index); +/// +/// The behavior depends on the summary arguments: +/// - If ExportSummary is non-null, this pass will export type identifiers to +/// the given summary. +/// - Otherwise, if ImportSummary is non-null, this pass will import type +/// identifiers from the given summary. +/// - Otherwise it does neither. +/// It is invalid for both ExportSummary and ImportSummary to be non-null. +ModulePass *createLowerTypeTestsPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary); /// \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(); +/// +/// The behavior depends on the summary arguments: +/// - If ExportSummary is non-null, this pass will export type identifiers to +/// the given summary. +/// - Otherwise, if ImportSummary is non-null, this pass will import type +/// identifiers from the given summary. +/// - Otherwise it does neither. +/// It is invalid for both ExportSummary and ImportSummary to be non-null. +ModulePass * +createWholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary); /// This pass splits globals into pieces for the benefit of whole-program /// devirtualization and control-flow integrity. @@ -248,7 +264,8 @@ ModulePass *createSampleProfileLoaderPass(); ModulePass *createSampleProfileLoaderPass(StringRef Name); /// Write ThinLTO-ready bitcode to Str. -ModulePass *createWriteThinLTOBitcodePass(raw_ostream &Str); +ModulePass *createWriteThinLTOBitcodePass(raw_ostream &Str, + raw_ostream *ThinLinkOS = nullptr); } // End llvm namespace diff --git a/include/llvm/Transforms/IPO/ArgumentPromotion.h b/include/llvm/Transforms/IPO/ArgumentPromotion.h new file mode 100644 index 000000000000..724ff72f3b5a --- /dev/null +++ b/include/llvm/Transforms/IPO/ArgumentPromotion.h @@ -0,0 +1,31 @@ +//===- ArgumentPromotion.h - Promote by-reference arguments -----*- 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_IPO_ARGUMENTPROMOTION_H +#define LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H + +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LazyCallGraph.h" + +namespace llvm { + +/// Argument promotion pass. +/// +/// This pass walks the functions in each SCC and for each one tries to +/// transform it and all of its callers to replace indirect arguments with +/// direct (by-value) arguments. +class ArgumentPromotionPass : public PassInfoMixin<ArgumentPromotionPass> { +public: + PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, + LazyCallGraph &CG, CGSCCUpdateResult &UR); +}; + +} + +#endif diff --git a/include/llvm/Transforms/IPO/FunctionAttrs.h b/include/llvm/Transforms/IPO/FunctionAttrs.h index ee45f35bf11b..85d6364c8bbc 100644 --- a/include/llvm/Transforms/IPO/FunctionAttrs.h +++ b/include/llvm/Transforms/IPO/FunctionAttrs.h @@ -20,6 +20,19 @@ namespace llvm { +class AAResults; + +/// The three kinds of memory access relevant to 'readonly' and +/// 'readnone' attributes. +enum MemoryAccessKind { + MAK_ReadNone = 0, + MAK_ReadOnly = 1, + MAK_MayWrite = 2 +}; + +/// Returns the memory access properties of this copy of the function. +MemoryAccessKind computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR); + /// Computes function attributes in post-order over the call graph. /// /// By operating in post-order, this pass computes precise attributes for @@ -43,7 +56,7 @@ Pass *createPostOrderFunctionAttrsLegacyPass(); /// 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 +/// provides the complement 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 diff --git a/include/llvm/Transforms/IPO/FunctionImport.h b/include/llvm/Transforms/IPO/FunctionImport.h index eaea092c9179..ed5742ab8b56 100644 --- a/include/llvm/Transforms/IPO/FunctionImport.h +++ b/include/llvm/Transforms/IPO/FunctionImport.h @@ -53,12 +53,8 @@ public: : 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. Expected<bool> - importFunctions(Module &M, const ImportMapTy &ImportList, - bool ForceImportReferencedDiscardableSymbols = false); + importFunctions(Module &M, const ImportMapTy &ImportList); private: /// The summaries index used to trigger importing. diff --git a/include/llvm/Transforms/IPO/GlobalDCE.h b/include/llvm/Transforms/IPO/GlobalDCE.h index 57e174c2a37f..9ca939c15b62 100644 --- a/include/llvm/Transforms/IPO/GlobalDCE.h +++ b/include/llvm/Transforms/IPO/GlobalDCE.h @@ -18,6 +18,8 @@ #ifndef LLVM_TRANSFORMS_IPO_GLOBALDCE_H #define LLVM_TRANSFORMS_IPO_GLOBALDCE_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include <unordered_map> @@ -31,14 +33,23 @@ public: private: SmallPtrSet<GlobalValue*, 32> AliveGlobals; - SmallPtrSet<Constant *, 8> SeenConstants; + + /// Global -> Global that uses this global. + std::unordered_multimap<GlobalValue *, GlobalValue *> GVDependencies; + + /// Constant -> Globals that use this global cache. + std::unordered_map<Constant *, SmallPtrSet<GlobalValue *, 8>> + ConstantDependenciesCache; + + /// Comdat -> Globals in that Comdat section. 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); + void UpdateGVDependencies(GlobalValue &GV); + void MarkLive(GlobalValue &GV, + SmallVectorImpl<GlobalValue *> *Updates = nullptr); bool RemoveUnusedGlobalValue(GlobalValue &GV); + + void ComputeDependencies(Value *V, SmallPtrSetImpl<GlobalValue *> &U); }; } diff --git a/include/llvm/Transforms/IPO/LowerTypeTests.h b/include/llvm/Transforms/IPO/LowerTypeTests.h index ca6e1b878dff..a2b888ce9ffa 100644 --- a/include/llvm/Transforms/IPO/LowerTypeTests.h +++ b/include/llvm/Transforms/IPO/LowerTypeTests.h @@ -15,11 +15,9 @@ #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 <cstdint> #include <cstring> #include <limits> @@ -28,9 +26,6 @@ namespace llvm { -class DataLayout; -class GlobalObject; -class Value; class raw_ostream; namespace lowertypetests { @@ -65,9 +60,10 @@ struct BitSetInfo { struct BitSetBuilder { SmallVector<uint64_t, 16> Offsets; - uint64_t Min, Max; + uint64_t Min = std::numeric_limits<uint64_t>::max(); + uint64_t Max = 0; - BitSetBuilder() : Min(std::numeric_limits<uint64_t>::max()), Max(0) {} + BitSetBuilder() = default; void addOffset(uint64_t Offset) { if (Min > Offset) diff --git a/include/llvm/Transforms/IPO/PassManagerBuilder.h b/include/llvm/Transforms/IPO/PassManagerBuilder.h index abfb24f0fe50..247382c35eeb 100644 --- a/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ b/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -21,6 +21,7 @@ #include <vector> namespace llvm { +class ModuleSummaryIndex; class Pass; class TargetLibraryInfoImpl; class TargetMachine; @@ -100,6 +101,14 @@ public: /// will be inserted after each instance of the instruction combiner pass. EP_Peephole, + /// EP_LateLoopOptimizations - This extension point allows adding late loop + /// canonicalization and simplification passes. This is the last point in + /// the loop optimization pipeline before loop deletion. Each pass added + /// here must be an instance of LoopPass. + /// This is the place to add passes that can remove loops, such as target- + /// specific loop idiom recognition. + EP_LateLoopOptimizations, + /// EP_CGSCCOptimizerLate - This extension point allows adding CallGraphSCC /// passes at the end of the main CallGraphSCC passes and before any /// function simplification passes run by CGPassManager. @@ -123,6 +132,16 @@ public: /// added to the per-module passes. Pass *Inliner; + /// The module summary index to use for exporting information from the + /// regular LTO phase, for example for the CFI and devirtualization type + /// tests. + ModuleSummaryIndex *ExportSummary = nullptr; + + /// The module summary index to use for importing information to the + /// thin LTO backends, for example for the CFI and devirtualization type + /// tests. + const ModuleSummaryIndex *ImportSummary = nullptr; + bool DisableTailCalls; bool DisableUnitAtATime; bool DisableUnrollLoops; @@ -139,6 +158,7 @@ public: bool PrepareForLTO; bool PrepareForThinLTO; bool PerformThinLTO; + bool DivergentTarget; /// Enable profile instrumentation pass. bool EnablePGOInstrGen; diff --git a/include/llvm/Transforms/InstrProfiling.h b/include/llvm/Transforms/InstrProfiling.h index b7c2935f4d84..65e69761badd 100644 --- a/include/llvm/Transforms/InstrProfiling.h +++ b/include/llvm/Transforms/InstrProfiling.h @@ -1,4 +1,4 @@ -//===- Transforms/InstrProfiling.h - Instrumentation passes ---*- C++ -*-===// +//===- Transforms/InstrProfiling.h - Instrumentation passes -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,10 +14,16 @@ #ifndef LLVM_TRANSFORMS_INSTRPROFILING_H #define LLVM_TRANSFORMS_INSTRPROFILING_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PassManager.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Transforms/Instrumentation.h" +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <vector> namespace llvm { @@ -28,7 +34,7 @@ class TargetLibraryInfo; /// instrumentation pass. class InstrProfiling : public PassInfoMixin<InstrProfiling> { public: - InstrProfiling() {} + InstrProfiling() = default; InstrProfiling(const InstrProfOptions &Options) : Options(Options) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); @@ -37,12 +43,14 @@ public: private: InstrProfOptions Options; Module *M; + Triple TT; const TargetLibraryInfo *TLI; struct PerFunctionProfileData { uint32_t NumValueSites[IPVK_Last + 1]; - GlobalVariable *RegionCounters; - GlobalVariable *DataVar; - PerFunctionProfileData() : RegionCounters(nullptr), DataVar(nullptr) { + GlobalVariable *RegionCounters = nullptr; + GlobalVariable *DataVar = nullptr; + + PerFunctionProfileData() { memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last + 1)); } }; @@ -52,19 +60,10 @@ private: 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; + // The start value of precise value profile range for memory intrinsic sizes. + int64_t MemOPSizeRangeStart; + // The end value of precise value profile range for memory intrinsic sizes. + int64_t MemOPSizeRangeLast; /// Count the number of instrumented value sites for the function. void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins); @@ -104,5 +103,6 @@ private: void emitInitialization(); }; -} // End llvm namespace -#endif +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_INSTRPROFILING_H diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 7fb9a5442081..01a3975a4f2c 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -16,6 +16,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" +#include <cassert> +#include <cstdint> +#include <limits> +#include <string> #include <vector> #if defined(__GNUC__) && defined(__linux__) && !defined(ANDROID) @@ -34,7 +38,8 @@ inline void *getDFSanRetValTLSPtrForJIT() { namespace llvm { -class TargetMachine; +class FunctionPass; +class ModulePass; /// Instrumentation passes often insert conditional checks into entry blocks. /// Call this function before splitting the entry block to move instructions @@ -44,9 +49,6 @@ class TargetMachine; BasicBlock::iterator PrepareToSplitEntryBlock(BasicBlock &BB, BasicBlock::iterator IP); -class ModulePass; -class FunctionPass; - // Insert GCOV profiling instrumentation struct GCOVOptions { static GCOVOptions getDefault(); @@ -76,6 +78,7 @@ struct GCOVOptions { // all of the function body's blocks. bool ExitBlockBeforeBody; }; + ModulePass *createGCOVProfilerPass(const GCOVOptions &Options = GCOVOptions::getDefault()); @@ -83,17 +86,40 @@ ModulePass *createGCOVProfilerPass(const GCOVOptions &Options = ModulePass *createPGOInstrumentationGenLegacyPass(); ModulePass * createPGOInstrumentationUseLegacyPass(StringRef Filename = StringRef("")); -ModulePass *createPGOIndirectCallPromotionLegacyPass(bool InLTO = false); +ModulePass *createPGOIndirectCallPromotionLegacyPass(bool InLTO = false, + bool SamplePGO = false); +FunctionPass *createPGOMemOPSizeOptLegacyPass(); + +// Helper function to check if it is legal to promote indirect call \p Inst +// to a direct call of function \p F. Stores the reason in \p Reason. +bool isLegalToPromote(Instruction *Inst, Function *F, const char **Reason); + +// Helper function that transforms Inst (either an indirect-call instruction, or +// an invoke instruction , to a conditional call to F. This is like: +// if (Inst.CalledValue == F) +// F(...); +// else +// Inst(...); +// end +// TotalCount is the profile count value that the instruction executes. +// Count is the profile count value that F is the target function. +// These two values are used to update the branch weight. +// If \p AttachProfToDirectCall is true, a prof metadata is attached to the +// new direct call to contain \p Count. +// Returns the promoted direct call instruction. +Instruction *promoteIndirectCall(Instruction *Inst, Function *F, uint64_t Count, + uint64_t TotalCount, + bool AttachProfToDirectCall); /// Options for the frontend instrumentation based profiling pass. struct InstrProfOptions { - InstrProfOptions() : NoRedZone(false) {} - // Add the 'noredzone' attribute to added runtime library calls. - bool NoRedZone; + bool NoRedZone = false; // Name of the profile file to use as output std::string InstrProfileOutput; + + InstrProfOptions() = default; }; /// Insert frontend instrumentation based profiling. @@ -121,12 +147,13 @@ ModulePass *createDataFlowSanitizerPass( // Options for EfficiencySanitizer sub-tools. struct EfficiencySanitizerOptions { - EfficiencySanitizerOptions() : ToolType(ESAN_None) {} enum Type { ESAN_None = 0, ESAN_CacheFrag, ESAN_WorkingSet, - } ToolType; + } ToolType = ESAN_None; + + EfficiencySanitizerOptions() = default; }; // Insert EfficiencySanitizer instrumentation. @@ -135,25 +162,22 @@ ModulePass *createEfficiencySanitizerPass( // Options for sanitizer coverage instrumentation. struct SanitizerCoverageOptions { - SanitizerCoverageOptions() - : CoverageType(SCK_None), IndirectCalls(false), TraceBB(false), - TraceCmp(false), TraceDiv(false), TraceGep(false), - Use8bitCounters(false), TracePC(false), TracePCGuard(false) {} - enum Type { SCK_None = 0, SCK_Function, SCK_BB, SCK_Edge - } CoverageType; - bool IndirectCalls; - bool TraceBB; - bool TraceCmp; - bool TraceDiv; - bool TraceGep; - bool Use8bitCounters; - bool TracePC; - bool TracePCGuard; + } CoverageType = SCK_None; + bool IndirectCalls = false; + bool TraceBB = false; + bool TraceCmp = false; + bool TraceDiv = false; + bool TraceGep = false; + bool Use8bitCounters = false; + bool TracePC = false; + bool TracePCGuard = false; + + SanitizerCoverageOptions() = default; }; // Insert SanitizerCoverage instrumentation. @@ -175,9 +199,11 @@ FunctionPass *createBoundsCheckingPass(); /// \brief Calculate what to divide by to scale counts. /// /// Given the maximum count, calculate a divisor that will scale all the -/// weights to strictly less than UINT32_MAX. +/// weights to strictly less than std::numeric_limits<uint32_t>::max(). static inline uint64_t calculateCountScale(uint64_t MaxCount) { - return MaxCount < UINT32_MAX ? 1 : MaxCount / UINT32_MAX + 1; + return MaxCount < std::numeric_limits<uint32_t>::max() + ? 1 + : MaxCount / std::numeric_limits<uint32_t>::max() + 1; } /// \brief Scale an individual branch count. @@ -186,10 +212,10 @@ static inline uint64_t calculateCountScale(uint64_t MaxCount) { /// static inline uint32_t scaleBranchCount(uint64_t Count, uint64_t Scale) { uint64_t Scaled = Count / Scale; - assert(Scaled <= UINT32_MAX && "overflow 32-bits"); + assert(Scaled <= std::numeric_limits<uint32_t>::max() && "overflow 32-bits"); return Scaled; } -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_INSTRUMENTATION_H diff --git a/include/llvm/Transforms/PGOInstrumentation.h b/include/llvm/Transforms/PGOInstrumentation.h index 1b449c9abdc2..19263f0f8071 100644 --- a/include/llvm/Transforms/PGOInstrumentation.h +++ b/include/llvm/Transforms/PGOInstrumentation.h @@ -38,11 +38,24 @@ private: /// The indirect function call promotion pass. class PGOIndirectCallPromotion : public PassInfoMixin<PGOIndirectCallPromotion> { public: - PGOIndirectCallPromotion(bool IsInLTO = false) : InLTO(IsInLTO) {} + PGOIndirectCallPromotion(bool IsInLTO = false, bool SamplePGO = false) + : InLTO(IsInLTO), SamplePGO(SamplePGO) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + private: bool InLTO; + bool SamplePGO; }; +/// The profile size based optimization pass for memory intrinsics. +class PGOMemOPSizeOpt : public PassInfoMixin<PGOMemOPSizeOpt> { +public: + PGOMemOPSizeOpt() {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +void setProfMetadata(Module *M, Instruction *TI, ArrayRef<uint64_t> EdgeCounts, + uint64_t MaxCount); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 92558937d047..ba0a3ee1287a 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -147,6 +147,12 @@ Pass *createLoopSinkPass(); //===----------------------------------------------------------------------===// // +// LoopPredication - This pass does loop predication on guards. +// +Pass *createLoopPredicationPass(); + +//===----------------------------------------------------------------------===// +// // LoopInterchange - This pass interchanges loops to provide a more // cache-friendly memory access patterns. // @@ -163,7 +169,8 @@ Pass *createLoopStrengthReducePass(); // // LoopUnswitch - This pass is a simple loop unswitching pass. // -Pass *createLoopUnswitchPass(bool OptimizeForSize = false); +Pass *createLoopUnswitchPass(bool OptimizeForSize = false, + bool hasBranchDivergence = false); //===----------------------------------------------------------------------===// // @@ -175,11 +182,11 @@ Pass *createLoopInstSimplifyPass(); // // LoopUnroll - This pass is a simple loop unrolling pass. // -Pass *createLoopUnrollPass(int Threshold = -1, int Count = -1, +Pass *createLoopUnrollPass(int OptLevel = 2, int Threshold = -1, int Count = -1, int AllowPartial = -1, int Runtime = -1, int UpperBound = -1); // Create an unrolling pass for full unrolling that uses exact trip count only. -Pass *createSimpleLoopUnrollPass(); +Pass *createSimpleLoopUnrollPass(int OptLevel = 2); //===----------------------------------------------------------------------===// // @@ -255,6 +262,14 @@ FunctionPass *createCFGSimplificationPass( //===----------------------------------------------------------------------===// // +// LateCFGSimplification - Like CFGSimplification, but may also +// convert switches to lookup tables. +// +FunctionPass *createLateCFGSimplificationPass( + int Threshold = -1, std::function<bool(const Function &)> Ftor = nullptr); + +//===----------------------------------------------------------------------===// +// // FlattenCFG - flatten CFG, reduce number of conditional branches by using // parallel-and and parallel-or mode, etc... // @@ -406,6 +421,15 @@ Pass *createCorrelatedValuePropagationPass(); //===----------------------------------------------------------------------===// // +// InferAddressSpaces - Modify users of addrspacecast instructions with values +// in the source address space if using the destination address space is slower +// on the target. +// +FunctionPass *createInferAddressSpacesPass(); +extern char &InferAddressSpacesID; + +//===----------------------------------------------------------------------===// +// // InstructionSimplifier - Remove redundant instructions. // FunctionPass *createInstructionSimplifierPass(); diff --git a/include/llvm/Transforms/Scalar/GVNExpression.h b/include/llvm/Transforms/Scalar/GVNExpression.h index 3458696e0687..2670a0c1a533 100644 --- a/include/llvm/Transforms/Scalar/GVNExpression.h +++ b/include/llvm/Transforms/Scalar/GVNExpression.h @@ -1,4 +1,4 @@ -//======- GVNExpression.h - GVN Expression classes -------*- C++ -*-==-------=// +//======- GVNExpression.h - GVN Expression classes --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,18 +17,22 @@ #define LLVM_TRANSFORMS_SCALAR_GVNEXPRESSION_H #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Analysis/MemorySSA.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Value.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ArrayRecycler.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/MemorySSA.h" #include <algorithm> +#include <cassert> +#include <iterator> +#include <utility> namespace llvm { -class MemoryAccess; namespace GVNExpression { @@ -39,11 +43,13 @@ enum ExpressionType { ET_Unknown, ET_BasicStart, ET_Basic, - ET_Call, ET_AggregateValue, ET_Phi, + ET_MemoryStart, + ET_Call, ET_Load, ET_Store, + ET_MemoryEnd, ET_BasicEnd }; @@ -53,23 +59,22 @@ private: unsigned Opcode; public: - Expression(const Expression &) = delete; Expression(ExpressionType ET = ET_Base, unsigned O = ~2U) : EType(ET), Opcode(O) {} - void operator=(const Expression &) = delete; + Expression(const Expression &) = delete; + Expression &operator=(const Expression &) = delete; virtual ~Expression(); static unsigned getEmptyKey() { return ~0U; } static unsigned getTombstoneKey() { return ~1U; } - + bool operator!=(const Expression &Other) const { return !(*this == Other); } bool operator==(const Expression &Other) const { if (getOpcode() != Other.getOpcode()) return false; if (getOpcode() == getEmptyKey() || getOpcode() == getTombstoneKey()) return true; // Compare the expression type for anything but load and store. - // For load and store we set the opcode to zero. - // This is needed for load coercion. + // For load and store we set the opcode to zero to make them equal. if (getExpressionType() != ET_Load && getExpressionType() != ET_Store && getExpressionType() != Other.getExpressionType()) return false; @@ -83,9 +88,8 @@ public: void setOpcode(unsigned opcode) { Opcode = opcode; } ExpressionType getExpressionType() const { return EType; } - virtual hash_code getHashValue() const { - return hash_combine(getExpressionType(), getOpcode()); - } + // We deliberately leave the expression type out of the hash value. + virtual hash_code getHashValue() const { return getOpcode(); } // // Debugging support @@ -101,7 +105,11 @@ public: printInternal(OS, true); OS << "}"; } - void dump() const { print(dbgs()); } + + LLVM_DUMP_METHOD void dump() const { + print(dbgs()); + dbgs() << "\n"; + } }; inline raw_ostream &operator<<(raw_ostream &OS, const Expression &E) { @@ -119,20 +127,20 @@ private: Type *ValueType; public: - static bool classof(const Expression *EB) { - ExpressionType ET = EB->getExpressionType(); - return ET > ET_BasicStart && ET < ET_BasicEnd; - } - BasicExpression(unsigned NumOperands) : BasicExpression(NumOperands, ET_Basic) {} BasicExpression(unsigned NumOperands, ExpressionType ET) : Expression(ET), Operands(nullptr), MaxOperands(NumOperands), NumOperands(0), ValueType(nullptr) {} - virtual ~BasicExpression() override; - void operator=(const BasicExpression &) = delete; - BasicExpression(const BasicExpression &) = delete; BasicExpression() = delete; + BasicExpression(const BasicExpression &) = delete; + BasicExpression &operator=(const BasicExpression &) = delete; + ~BasicExpression() override; + + static bool classof(const Expression *EB) { + ExpressionType ET = EB->getExpressionType(); + return ET > ET_BasicStart && ET < ET_BasicEnd; + } /// \brief Swap two operands. Used during GVN to put commutative operands in /// order. @@ -185,7 +193,7 @@ public: void setType(Type *T) { ValueType = T; } Type *getType() const { return ValueType; } - virtual bool equals(const Expression &Other) const override { + bool equals(const Expression &Other) const override { if (getOpcode() != Other.getOpcode()) return false; @@ -194,15 +202,15 @@ public: std::equal(op_begin(), op_end(), OE.op_begin()); } - virtual hash_code getHashValue() const override { - return hash_combine(getExpressionType(), getOpcode(), ValueType, + hash_code getHashValue() const override { + return hash_combine(this->Expression::getHashValue(), ValueType, hash_combine_range(op_begin(), op_end())); } // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeBasic, "; @@ -216,6 +224,7 @@ public: OS << "} "; } }; + class op_inserter : public std::iterator<std::output_iterator_tag, void, void, void, void> { private: @@ -235,131 +244,143 @@ public: op_inserter &operator++(int) { return *this; } }; -class CallExpression final : public BasicExpression { +class MemoryExpression : public BasicExpression { private: - CallInst *Call; - MemoryAccess *DefiningAccess; + const MemoryAccess *MemoryLeader; public: + MemoryExpression(unsigned NumOperands, enum ExpressionType EType, + const MemoryAccess *MemoryLeader) + : BasicExpression(NumOperands, EType), MemoryLeader(MemoryLeader){}; + + MemoryExpression() = delete; + MemoryExpression(const MemoryExpression &) = delete; + MemoryExpression &operator=(const MemoryExpression &) = delete; static bool classof(const Expression *EB) { - return EB->getExpressionType() == ET_Call; + return EB->getExpressionType() > ET_MemoryStart && + EB->getExpressionType() < ET_MemoryEnd; + } + hash_code getHashValue() const override { + return hash_combine(this->BasicExpression::getHashValue(), MemoryLeader); } - CallExpression(unsigned NumOperands, CallInst *C, MemoryAccess *DA) - : BasicExpression(NumOperands, ET_Call), Call(C), DefiningAccess(DA) {} - void operator=(const CallExpression &) = delete; - CallExpression(const CallExpression &) = delete; - CallExpression() = delete; - virtual ~CallExpression() override; - - virtual bool equals(const Expression &Other) const override { + bool equals(const Expression &Other) const override { if (!this->BasicExpression::equals(Other)) return false; - const auto &OE = cast<CallExpression>(Other); - return DefiningAccess == OE.DefiningAccess; + const MemoryExpression &OtherMCE = cast<MemoryExpression>(Other); + + return MemoryLeader == OtherMCE.MemoryLeader; } - virtual hash_code getHashValue() const override { - return hash_combine(this->BasicExpression::getHashValue(), DefiningAccess); + const MemoryAccess *getMemoryLeader() const { return MemoryLeader; } + void setMemoryLeader(const MemoryAccess *ML) { MemoryLeader = ML; } +}; + +class CallExpression final : public MemoryExpression { +private: + CallInst *Call; + +public: + CallExpression(unsigned NumOperands, CallInst *C, + const MemoryAccess *MemoryLeader) + : MemoryExpression(NumOperands, ET_Call, MemoryLeader), Call(C) {} + CallExpression() = delete; + CallExpression(const CallExpression &) = delete; + CallExpression &operator=(const CallExpression &) = delete; + ~CallExpression() override; + + static bool classof(const Expression *EB) { + return EB->getExpressionType() == ET_Call; } // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeCall, "; this->BasicExpression::printInternal(OS, false); - OS << " represents call at " << Call; + OS << " represents call at "; + Call->printAsOperand(OS); } }; -class LoadExpression final : public BasicExpression { +class LoadExpression final : public MemoryExpression { private: LoadInst *Load; - MemoryAccess *DefiningAccess; unsigned Alignment; public: - static bool classof(const Expression *EB) { - return EB->getExpressionType() == ET_Load; - } - - LoadExpression(unsigned NumOperands, LoadInst *L, MemoryAccess *DA) - : LoadExpression(ET_Load, NumOperands, L, DA) {} + LoadExpression(unsigned NumOperands, LoadInst *L, + const MemoryAccess *MemoryLeader) + : LoadExpression(ET_Load, NumOperands, L, MemoryLeader) {} LoadExpression(enum ExpressionType EType, unsigned NumOperands, LoadInst *L, - MemoryAccess *DA) - : BasicExpression(NumOperands, EType), Load(L), DefiningAccess(DA) { + const MemoryAccess *MemoryLeader) + : MemoryExpression(NumOperands, EType, MemoryLeader), Load(L) { Alignment = L ? L->getAlignment() : 0; } - void operator=(const LoadExpression &) = delete; - LoadExpression(const LoadExpression &) = delete; LoadExpression() = delete; - virtual ~LoadExpression() override; + LoadExpression(const LoadExpression &) = delete; + LoadExpression &operator=(const LoadExpression &) = delete; + ~LoadExpression() override; + + static bool classof(const Expression *EB) { + return EB->getExpressionType() == ET_Load; + } LoadInst *getLoadInst() const { return Load; } void setLoadInst(LoadInst *L) { Load = L; } - MemoryAccess *getDefiningAccess() const { return DefiningAccess; } - void setDefiningAccess(MemoryAccess *MA) { DefiningAccess = MA; } unsigned getAlignment() const { return Alignment; } void setAlignment(unsigned Align) { Alignment = Align; } - virtual bool equals(const Expression &Other) const override; - - virtual hash_code getHashValue() const override { - return hash_combine(getOpcode(), getType(), DefiningAccess, - hash_combine_range(op_begin(), op_end())); - } + bool equals(const Expression &Other) const override; // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeLoad, "; this->BasicExpression::printInternal(OS, false); - OS << " represents Load at " << Load; - OS << " with DefiningAccess " << *DefiningAccess; + OS << " represents Load at "; + Load->printAsOperand(OS); + OS << " with MemoryLeader " << *getMemoryLeader(); } }; -class StoreExpression final : public BasicExpression { +class StoreExpression final : public MemoryExpression { private: StoreInst *Store; - MemoryAccess *DefiningAccess; + Value *StoredValue; public: + StoreExpression(unsigned NumOperands, StoreInst *S, Value *StoredValue, + const MemoryAccess *MemoryLeader) + : MemoryExpression(NumOperands, ET_Store, MemoryLeader), Store(S), + StoredValue(StoredValue) {} + StoreExpression() = delete; + StoreExpression(const StoreExpression &) = delete; + StoreExpression &operator=(const StoreExpression &) = delete; + ~StoreExpression() override; + static bool classof(const Expression *EB) { return EB->getExpressionType() == ET_Store; } - StoreExpression(unsigned NumOperands, StoreInst *S, MemoryAccess *DA) - : BasicExpression(NumOperands, ET_Store), Store(S), DefiningAccess(DA) {} - void operator=(const StoreExpression &) = delete; - StoreExpression(const StoreExpression &) = delete; - StoreExpression() = delete; - virtual ~StoreExpression() override; - StoreInst *getStoreInst() const { return Store; } - MemoryAccess *getDefiningAccess() const { return DefiningAccess; } + Value *getStoredValue() const { return StoredValue; } - virtual bool equals(const Expression &Other) const override; + bool equals(const Expression &Other) const override; - virtual hash_code getHashValue() const override { - return hash_combine(getOpcode(), getType(), DefiningAccess, - hash_combine_range(op_begin(), op_end())); - } - - // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeStore, "; this->BasicExpression::printInternal(OS, false); - OS << " represents Store at " << Store; - OS << " with DefiningAccess " << *DefiningAccess; + OS << " represents Store " << *Store; + OS << " with MemoryLeader " << *getMemoryLeader(); } }; @@ -370,19 +391,19 @@ private: unsigned *IntOperands; public: - static bool classof(const Expression *EB) { - return EB->getExpressionType() == ET_AggregateValue; - } - AggregateValueExpression(unsigned NumOperands, unsigned NumIntOperands) : BasicExpression(NumOperands, ET_AggregateValue), MaxIntOperands(NumIntOperands), NumIntOperands(0), IntOperands(nullptr) {} - - void operator=(const AggregateValueExpression &) = delete; - AggregateValueExpression(const AggregateValueExpression &) = delete; AggregateValueExpression() = delete; - virtual ~AggregateValueExpression() override; + AggregateValueExpression(const AggregateValueExpression &) = delete; + AggregateValueExpression & + operator=(const AggregateValueExpression &) = delete; + ~AggregateValueExpression() override; + + static bool classof(const Expression *EB) { + return EB->getExpressionType() == ET_AggregateValue; + } typedef unsigned *int_arg_iterator; typedef const unsigned *const_int_arg_iterator; @@ -407,7 +428,7 @@ public: IntOperands = Allocator.Allocate<unsigned>(MaxIntOperands); } - virtual bool equals(const Expression &Other) const override { + bool equals(const Expression &Other) const override { if (!this->BasicExpression::equals(Other)) return false; const AggregateValueExpression &OE = cast<AggregateValueExpression>(Other); @@ -415,7 +436,7 @@ public: std::equal(int_op_begin(), int_op_end(), OE.int_op_begin()); } - virtual hash_code getHashValue() const override { + hash_code getHashValue() const override { return hash_combine(this->BasicExpression::getHashValue(), hash_combine_range(int_op_begin(), int_op_end())); } @@ -423,7 +444,7 @@ public: // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeAggregateValue, "; this->BasicExpression::printInternal(OS, false); @@ -434,6 +455,7 @@ public: OS << "}"; } }; + class int_op_inserter : public std::iterator<std::output_iterator_tag, void, void, void, void> { private: @@ -443,6 +465,7 @@ private: public: explicit int_op_inserter(AggregateValueExpression &E) : AVE(&E) {} explicit int_op_inserter(AggregateValueExpression *E) : AVE(E) {} + int_op_inserter &operator=(unsigned int val) { AVE->int_op_push_back(val); return *this; @@ -457,32 +480,32 @@ private: BasicBlock *BB; public: - static bool classof(const Expression *EB) { - return EB->getExpressionType() == ET_Phi; - } - PHIExpression(unsigned NumOperands, BasicBlock *B) : BasicExpression(NumOperands, ET_Phi), BB(B) {} - void operator=(const PHIExpression &) = delete; - PHIExpression(const PHIExpression &) = delete; PHIExpression() = delete; - virtual ~PHIExpression() override; + PHIExpression(const PHIExpression &) = delete; + PHIExpression &operator=(const PHIExpression &) = delete; + ~PHIExpression() override; - virtual bool equals(const Expression &Other) const override { + static bool classof(const Expression *EB) { + return EB->getExpressionType() == ET_Phi; + } + + bool equals(const Expression &Other) const override { if (!this->BasicExpression::equals(Other)) return false; const PHIExpression &OE = cast<PHIExpression>(Other); return BB == OE.BB; } - virtual hash_code getHashValue() const override { + hash_code getHashValue() const override { return hash_combine(this->BasicExpression::getHashValue(), BB); } // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypePhi, "; this->BasicExpression::printInternal(OS, false); @@ -495,31 +518,32 @@ private: Value *VariableValue; public: + VariableExpression(Value *V) : Expression(ET_Variable), VariableValue(V) {} + VariableExpression() = delete; + VariableExpression(const VariableExpression &) = delete; + VariableExpression &operator=(const VariableExpression &) = delete; + static bool classof(const Expression *EB) { return EB->getExpressionType() == ET_Variable; } - VariableExpression(Value *V) : Expression(ET_Variable), VariableValue(V) {} - void operator=(const VariableExpression &) = delete; - VariableExpression(const VariableExpression &) = delete; - VariableExpression() = delete; - Value *getVariableValue() const { return VariableValue; } void setVariableValue(Value *V) { VariableValue = V; } - virtual bool equals(const Expression &Other) const override { + + bool equals(const Expression &Other) const override { const VariableExpression &OC = cast<VariableExpression>(Other); return VariableValue == OC.VariableValue; } - virtual hash_code getHashValue() const override { - return hash_combine(getExpressionType(), VariableValue->getType(), - VariableValue); + hash_code getHashValue() const override { + return hash_combine(this->Expression::getHashValue(), + VariableValue->getType(), VariableValue); } // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeVariable, "; this->Expression::printInternal(OS, false); @@ -529,36 +553,36 @@ public: class ConstantExpression final : public Expression { private: - Constant *ConstantValue; + Constant *ConstantValue = nullptr; public: - static bool classof(const Expression *EB) { - return EB->getExpressionType() == ET_Constant; - } - - ConstantExpression() : Expression(ET_Constant), ConstantValue(NULL) {} + ConstantExpression() : Expression(ET_Constant) {} ConstantExpression(Constant *constantValue) : Expression(ET_Constant), ConstantValue(constantValue) {} - void operator=(const ConstantExpression &) = delete; ConstantExpression(const ConstantExpression &) = delete; + ConstantExpression &operator=(const ConstantExpression &) = delete; + + static bool classof(const Expression *EB) { + return EB->getExpressionType() == ET_Constant; + } Constant *getConstantValue() const { return ConstantValue; } void setConstantValue(Constant *V) { ConstantValue = V; } - virtual bool equals(const Expression &Other) const override { + bool equals(const Expression &Other) const override { const ConstantExpression &OC = cast<ConstantExpression>(Other); return ConstantValue == OC.ConstantValue; } - virtual hash_code getHashValue() const override { - return hash_combine(getExpressionType(), ConstantValue->getType(), - ConstantValue); + hash_code getHashValue() const override { + return hash_combine(this->Expression::getHashValue(), + ConstantValue->getType(), ConstantValue); } // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeConstant, "; this->Expression::printInternal(OS, false); @@ -571,35 +595,40 @@ private: Instruction *Inst; public: + UnknownExpression(Instruction *I) : Expression(ET_Unknown), Inst(I) {} + UnknownExpression() = delete; + UnknownExpression(const UnknownExpression &) = delete; + UnknownExpression &operator=(const UnknownExpression &) = delete; + static bool classof(const Expression *EB) { return EB->getExpressionType() == ET_Unknown; } - UnknownExpression(Instruction *I) : Expression(ET_Unknown), Inst(I) {} - void operator=(const UnknownExpression &) = delete; - UnknownExpression(const UnknownExpression &) = delete; - UnknownExpression() = delete; - Instruction *getInstruction() const { return Inst; } void setInstruction(Instruction *I) { Inst = I; } - virtual bool equals(const Expression &Other) const override { + + bool equals(const Expression &Other) const override { const auto &OU = cast<UnknownExpression>(Other); return Inst == OU.Inst; } - virtual hash_code getHashValue() const override { - return hash_combine(getExpressionType(), Inst); + + hash_code getHashValue() const override { + return hash_combine(this->Expression::getHashValue(), Inst); } + // // Debugging support // - virtual void printInternal(raw_ostream &OS, bool PrintEType) const override { + void printInternal(raw_ostream &OS, bool PrintEType) const override { if (PrintEType) OS << "ExpressionTypeUnknown, "; this->Expression::printInternal(OS, false); OS << " inst = " << *Inst; } }; -} -} -#endif +} // end namespace GVNExpression + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_GVNEXPRESSION_H diff --git a/include/llvm/Transforms/Scalar/JumpThreading.h b/include/llvm/Transforms/Scalar/JumpThreading.h index f96741c0127d..1da86132591b 100644 --- a/include/llvm/Transforms/Scalar/JumpThreading.h +++ b/include/llvm/Transforms/Scalar/JumpThreading.h @@ -17,12 +17,14 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/AliasAnalysis.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/IntrinsicInst.h" #include "llvm/IR/ValueHandle.h" namespace llvm { @@ -59,9 +61,11 @@ enum ConstantPreference { WantInteger, WantBlockAddress }; class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> { TargetLibraryInfo *TLI; LazyValueInfo *LVI; + AliasAnalysis *AA; std::unique_ptr<BlockFrequencyInfo> BFI; std::unique_ptr<BranchProbabilityInfo> BPI; bool HasProfileData = false; + bool HasGuards = false; #ifdef NDEBUG SmallPtrSet<const BasicBlock *, 16> LoopHeaders; #else @@ -88,7 +92,8 @@ public: // Glue for old PM. bool runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_, - bool HasProfileData_, std::unique_ptr<BlockFrequencyInfo> BFI_, + AliasAnalysis *AA_, bool HasProfileData_, + std::unique_ptr<BlockFrequencyInfo> BFI_, std::unique_ptr<BranchProbabilityInfo> BPI_); PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); @@ -122,6 +127,9 @@ public: bool TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB); bool TryToUnfoldSelectInCurrBB(BasicBlock *BB); + bool ProcessGuards(BasicBlock *BB); + bool ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard, BranchInst *BI); + private: BasicBlock *SplitBlockPreds(BasicBlock *BB, ArrayRef<BasicBlock *> Preds, const char *Suffix); diff --git a/include/llvm/Transforms/Scalar/LoopDataPrefetch.h b/include/llvm/Transforms/Scalar/LoopDataPrefetch.h index 114d1bad17a5..12c7a030ff8b 100644 --- a/include/llvm/Transforms/Scalar/LoopDataPrefetch.h +++ b/include/llvm/Transforms/Scalar/LoopDataPrefetch.h @@ -22,10 +22,12 @@ namespace llvm { /// An optimization pass inserting data prefetches in loops. class LoopDataPrefetchPass : public PassInfoMixin<LoopDataPrefetchPass> { public: - LoopDataPrefetchPass() {} + LoopDataPrefetchPass() = default; + /// \brief Run the pass over the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -} -#endif +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPDATAPREFETCH_H diff --git a/include/llvm/Transforms/Scalar/LoopDeletion.h b/include/llvm/Transforms/Scalar/LoopDeletion.h index b44f823a82ca..7b8cb1e115c9 100644 --- a/include/llvm/Transforms/Scalar/LoopDeletion.h +++ b/include/llvm/Transforms/Scalar/LoopDeletion.h @@ -1,4 +1,4 @@ -//===- LoopDeletion.h - Loop Deletion -------------------------------------===// +//===- LoopDeletion.h - Loop Deletion ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,6 +14,7 @@ #ifndef LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H #define LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H +#include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/IR/PassManager.h" @@ -23,18 +24,12 @@ namespace llvm { class LoopDeletionPass : public PassInfoMixin<LoopDeletionPass> { public: - LoopDeletionPass() {} + LoopDeletionPass() = default; + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); - 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); }; -} + +} // end namespace llvm #endif // LLVM_TRANSFORMS_SCALAR_LOOPDELETION_H diff --git a/include/llvm/Transforms/Scalar/LoopLoadElimination.h b/include/llvm/Transforms/Scalar/LoopLoadElimination.h new file mode 100644 index 000000000000..7a007a7e822d --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopLoadElimination.h @@ -0,0 +1,30 @@ +//===---- LoopLoadElimination.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 header defines the LoopLoadEliminationPass object. This pass forwards +/// loaded values around loop backedges to allow their use in subsequent +/// iterations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPLOADELIMINATION_H +#define LLVM_TRANSFORMS_SCALAR_LOOPLOADELIMINATION_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Pass to forward loads in a loop around the backedge to subsequent +/// iterations. +struct LoopLoadEliminationPass : public PassInfoMixin<LoopLoadEliminationPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPLOADELIMINATION_H diff --git a/include/llvm/Transforms/Scalar/LoopPassManager.h b/include/llvm/Transforms/Scalar/LoopPassManager.h index b0e6dd6f4c08..715b11d3d974 100644 --- a/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -51,6 +51,8 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Utils/LCSSA.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" namespace llvm { @@ -248,19 +250,25 @@ template <typename LoopPassT> class FunctionToLoopPassAdaptor : public PassInfoMixin<FunctionToLoopPassAdaptor<LoopPassT>> { public: - explicit FunctionToLoopPassAdaptor(LoopPassT Pass) : Pass(std::move(Pass)) {} + explicit FunctionToLoopPassAdaptor(LoopPassT Pass) : Pass(std::move(Pass)) { + LoopCanonicalizationFPM.addPass(LoopSimplifyPass()); + LoopCanonicalizationFPM.addPass(LCSSAPass()); + } /// \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(); + // Before we even compute any loop analyses, first run a miniature function + // pass pipeline to put loops into their canonical form. Note that we can + // directly build up function analyses after this as the function pass + // manager handles all the invalidation at that layer. + PreservedAnalyses PA = LoopCanonicalizationFPM.run(F, AM); + // Get the loop structure for this function LoopInfo &LI = AM.getResult<LoopAnalysis>(F); // If there are no loops, there is nothing to do here. if (LI.empty()) - return PreservedAnalyses::all(); + return PA; // Get the analysis results needed by loop passes. LoopStandardAnalysisResults LAR = {AM.getResult<AAManager>(F), @@ -271,7 +279,13 @@ public: AM.getResult<TargetLibraryAnalysis>(F), AM.getResult<TargetIRAnalysis>(F)}; - PreservedAnalyses PA = PreservedAnalyses::all(); + // Setup the loop analysis manager from its proxy. It is important that + // this is only done when there are loops to process and we have built the + // LoopStandardAnalysisResults object. The loop analyses cached in this + // manager have access to those analysis results and so it must invalidate + // itself when they go away. + LoopAnalysisManager &LAM = + AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager(); // A postorder worklist of loops to process. SmallPriorityWorklist<Loop *, 4> Worklist; @@ -294,8 +308,15 @@ public: // Reset the update structure for this loop. Updater.CurrentL = L; Updater.SkipCurrentLoop = false; + #ifndef NDEBUG + // Save a parent loop pointer for asserts. Updater.ParentL = L->getParentLoop(); + + // Verify the loop structure and LCSSA form before visiting the loop. + L->verifyLoop(); + assert(L->isRecursivelyLCSSAForm(LAR.DT, LI) && + "Loops must remain in LCSSA form!"); #endif PreservedAnalyses PassPA = Pass.run(*L, LAM, LAR, Updater); @@ -321,7 +342,6 @@ public: PA.preserveSet<AllAnalysesOn<Loop>>(); PA.preserve<LoopAnalysisManagerFunctionProxy>(); // We also preserve the set of standard analyses. - PA.preserve<AssumptionAnalysis>(); PA.preserve<DominatorTreeAnalysis>(); PA.preserve<LoopAnalysis>(); PA.preserve<ScalarEvolutionAnalysis>(); @@ -336,6 +356,8 @@ public: private: LoopPassT Pass; + + FunctionPassManager LoopCanonicalizationFPM; }; /// \brief A function to deduce a loop pass type and wrap it in the templated diff --git a/include/llvm/Transforms/Scalar/LoopPredication.h b/include/llvm/Transforms/Scalar/LoopPredication.h new file mode 100644 index 000000000000..57398bdb6bd1 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopPredication.h @@ -0,0 +1,32 @@ +//===- LoopPredication.h - Guard based loop predication 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 tries to convert loop variant range checks to loop invariant by +// widening checks across loop iterations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPPREDICATION_H +#define LLVM_TRANSFORMS_SCALAR_LOOPPREDICATION_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" + +namespace llvm { + +/// Performs Loop Predication Pass. +class LoopPredicationPass : public PassInfoMixin<LoopPredicationPass> { +public: + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, LPMUpdater &U); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPPREDICATION_H diff --git a/include/llvm/Transforms/Scalar/LoopSink.h b/include/llvm/Transforms/Scalar/LoopSink.h new file mode 100644 index 000000000000..371a7c8d2c44 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopSink.h @@ -0,0 +1,40 @@ +//===- LoopSink.h - Loop Sink 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 provides the interface for the Loop Sink pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPSINK_H +#define LLVM_TRANSFORMS_SCALAR_LOOPSINK_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" + +namespace llvm { + +/// A pass that does profile-guided sinking of instructions into loops. +/// +/// This is a function pass as it shouldn't be composed into any kind of +/// unified loop pass pipeline. The goal of it is to sink code into loops that +/// is loop invariant but only required within the loop body when doing so +/// reduces the global expected dynamic frequency with which it executes. +/// A classic example is an extremely cold branch within a loop body. +/// +/// We do this as a separate pass so that during normal optimization all +/// invariant operations can be held outside the loop body to simplify +/// fundamental analyses and transforms of the loop. +class LoopSinkPass : public PassInfoMixin<LoopSinkPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPSINK_H diff --git a/include/llvm/Transforms/Scalar/LoopUnrollPass.h b/include/llvm/Transforms/Scalar/LoopUnrollPass.h index 9da95ef81fad..7253bd09766e 100644 --- a/include/llvm/Transforms/Scalar/LoopUnrollPass.h +++ b/include/llvm/Transforms/Scalar/LoopUnrollPass.h @@ -16,12 +16,30 @@ namespace llvm { -struct LoopUnrollPass : public PassInfoMixin<LoopUnrollPass> { - Optional<unsigned> ProvidedCount; - Optional<unsigned> ProvidedThreshold; - Optional<bool> ProvidedAllowPartial; - Optional<bool> ProvidedRuntime; - Optional<bool> ProvidedUpperBound; +class LoopUnrollPass : public PassInfoMixin<LoopUnrollPass> { + const bool AllowPartialUnrolling; + const int OptLevel; + + explicit LoopUnrollPass(bool AllowPartialUnrolling, int OptLevel) + : AllowPartialUnrolling(AllowPartialUnrolling), OptLevel(OptLevel) {} + +public: + /// Create an instance of the loop unroll pass that will support both full + /// and partial unrolling. + /// + /// This uses the target information (or flags) to control the thresholds for + /// different unrolling stategies but supports all of them. + static LoopUnrollPass create(int OptLevel = 2) { + return LoopUnrollPass(/*AllowPartialUnrolling*/ true, OptLevel); + } + + /// Create an instance of the loop unroll pass that only does full loop + /// unrolling. + /// + /// This will disable any runtime or partial unrolling. + static LoopUnrollPass createFull(int OptLevel = 2) { + return LoopUnrollPass(/*AllowPartialUnrolling*/ false, OptLevel); + } PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); diff --git a/include/llvm/Transforms/Scalar/MemCpyOptimizer.h b/include/llvm/Transforms/Scalar/MemCpyOptimizer.h index 4308e44e7c4b..f52872dd2ea7 100644 --- a/include/llvm/Transforms/Scalar/MemCpyOptimizer.h +++ b/include/llvm/Transforms/Scalar/MemCpyOptimizer.h @@ -15,17 +15,18 @@ #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/BasicBlock.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" +#include <cstdint> +#include <functional> namespace llvm { @@ -37,7 +38,8 @@ class MemCpyOptPass : public PassInfoMixin<MemCpyOptPass> { std::function<DominatorTree &()> LookupDomTree; public: - MemCpyOptPass() {} + MemCpyOptPass() = default; + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); // Glue for the old PM. bool runImpl(Function &F, MemoryDependenceResults *MD_, @@ -63,6 +65,7 @@ private: bool iterateOnFunction(Function &F); }; -} + +} // end namespace llvm #endif // LLVM_TRANSFORMS_SCALAR_MEMCPYOPTIMIZER_H diff --git a/include/llvm/Transforms/Scalar/SROA.h b/include/llvm/Transforms/Scalar/SROA.h index 3e93f46dd4e5..3080b75ba894 100644 --- a/include/llvm/Transforms/Scalar/SROA.h +++ b/include/llvm/Transforms/Scalar/SROA.h @@ -21,17 +21,21 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" +#include "llvm/Support/Compiler.h" +#include <vector> 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 LLVM_LIBRARY_VISIBILITY { + class AllocaSliceRewriter; class AllocaSlices; class Partition; class SROALegacyPass; -} + +} // end namespace sroa /// \brief An optimization pass providing Scalar Replacement of Aggregates. /// @@ -52,9 +56,9 @@ class SROALegacyPass; /// this form. By doing so, it will enable promotion of vector aggregates to /// SSA vector values. class SROA : public PassInfoMixin<SROA> { - LLVMContext *C; - DominatorTree *DT; - AssumptionCache *AC; + LLVMContext *C = nullptr; + DominatorTree *DT = nullptr; + AssumptionCache *AC = nullptr; /// \brief Worklist of alloca instructions to simplify. /// @@ -99,7 +103,7 @@ class SROA : public PassInfoMixin<SROA> { SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects; public: - SROA() : C(nullptr), DT(nullptr), AC(nullptr) {} + SROA() = default; /// \brief Run the pass over the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); @@ -122,6 +126,6 @@ private: bool promoteAllocas(Function &F); }; -} +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_SCALAR_SROA_H diff --git a/include/llvm/Transforms/Scalar/SimplifyCFG.h b/include/llvm/Transforms/Scalar/SimplifyCFG.h index 96e1658c00b0..54b51c405ad4 100644 --- a/include/llvm/Transforms/Scalar/SimplifyCFG.h +++ b/include/llvm/Transforms/Scalar/SimplifyCFG.h @@ -27,13 +27,16 @@ namespace llvm { /// by the rest of the mid-level optimizer. class SimplifyCFGPass : public PassInfoMixin<SimplifyCFGPass> { int BonusInstThreshold; + bool LateSimplifyCFG; public: - /// \brief Construct a pass with the default thresholds. + /// \brief Construct a pass with the default thresholds + /// and switch optimizations. SimplifyCFGPass(); - /// \brief Construct a pass with a specific bonus threshold. - SimplifyCFGPass(int BonusInstThreshold); + /// \brief Construct a pass with a specific bonus threshold + /// and optional switch optimizations. + SimplifyCFGPass(int BonusInstThreshold, bool LateSimplifyCFG); /// \brief Run the pass over the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); diff --git a/include/llvm/Transforms/Utils/BasicBlockUtils.h b/include/llvm/Transforms/Utils/BasicBlockUtils.h index 3d41dbe2b954..85bb053135a6 100644 --- a/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -78,14 +78,13 @@ void ReplaceInstWithInst(Instruction *From, Instruction *To); struct CriticalEdgeSplittingOptions { DominatorTree *DT; LoopInfo *LI; - bool MergeIdenticalEdges; - bool DontDeleteUselessPHIs; - bool PreserveLCSSA; + bool MergeIdenticalEdges = false; + bool DontDeleteUselessPHIs = false; + bool PreserveLCSSA = false; CriticalEdgeSplittingOptions(DominatorTree *DT = nullptr, LoopInfo *LI = nullptr) - : DT(DT), LI(LI), MergeIdenticalEdges(false), - DontDeleteUselessPHIs(false), PreserveLCSSA(false) {} + : DT(DT), LI(LI) {} CriticalEdgeSplittingOptions &setMergeIdenticalEdges() { MergeIdenticalEdges = true; diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index 2d2a85905d0e..a067a685b837 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -84,14 +84,14 @@ namespace llvm { /// 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); + const AttributeList &Attrs); /// 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); + IRBuilder<> &B, const AttributeList &Attrs); /// Emit a call to the putchar function. This assumes that Char is an integer. Value *emitPutChar(Value *Char, IRBuilder<> &B, const TargetLibraryInfo *TLI); diff --git a/include/llvm/Transforms/Utils/Cloning.h b/include/llvm/Transforms/Utils/Cloning.h index 5eeb8cf30695..337305a0a82c 100644 --- a/include/llvm/Transforms/Utils/Cloning.h +++ b/include/llvm/Transforms/Utils/Cloning.h @@ -22,32 +22,28 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/ValueHandle.h" -#include "llvm/IR/ValueMap.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include <functional> +#include <memory> +#include <vector> namespace llvm { -class Module; -class Function; -class Instruction; -class Pass; -class LPPassManager; +class AllocaInst; class BasicBlock; -class Value; +class BlockFrequencyInfo; class CallInst; -class InvokeInst; -class ReturnInst; -class CallSite; -class Trace; class CallGraph; -class DataLayout; +class DominatorTree; +class Function; +class Instruction; +class InvokeInst; class Loop; class LoopInfo; -class AllocaInst; -class AssumptionCacheTracker; -class DominatorTree; +class Module; +class ReturnInst; /// Return an exact copy of the specified module /// @@ -67,20 +63,20 @@ CloneModule(const Module *M, ValueToValueMapTy &VMap, struct ClonedCodeInfo { /// ContainsCalls - This is set to true if the cloned code contains a normal /// call instruction. - bool ContainsCalls; + bool ContainsCalls = false; /// ContainsDynamicAllocas - This is set to true if the cloned code contains /// a 'dynamic' alloca. Dynamic allocas are allocas that are either not in /// the entry block or they are in the entry block but are not a constant /// size. - bool ContainsDynamicAllocas; + bool ContainsDynamicAllocas = false; /// All cloned call sites that have operand bundles attached are appended to /// this vector. This vector may contain nulls or undefs if some of the /// originally inserted callsites were DCE'ed after they were cloned. std::vector<WeakVH> OperandBundleCallSites; - ClonedCodeInfo() : ContainsCalls(false), ContainsDynamicAllocas(false) {} + ClonedCodeInfo() = default; }; /// CloneBasicBlock - Return a copy of the specified basic block, but without @@ -178,13 +174,17 @@ class InlineFunctionInfo { public: explicit InlineFunctionInfo(CallGraph *cg = nullptr, std::function<AssumptionCache &(Function &)> - *GetAssumptionCache = nullptr) - : CG(cg), GetAssumptionCache(GetAssumptionCache) {} + *GetAssumptionCache = nullptr, + BlockFrequencyInfo *CallerBFI = nullptr, + BlockFrequencyInfo *CalleeBFI = nullptr) + : CG(cg), GetAssumptionCache(GetAssumptionCache), CallerBFI(CallerBFI), + CalleeBFI(CalleeBFI) {} /// CG - If non-null, InlineFunction will update the callgraph to reflect the /// changes it makes. CallGraph *CG; std::function<AssumptionCache &(Function &)> *GetAssumptionCache; + BlockFrequencyInfo *CallerBFI, *CalleeBFI; /// StaticAllocas - InlineFunction fills this in with all static allocas that /// get copied into the caller. @@ -245,6 +245,16 @@ Loop *cloneLoopWithPreheader(BasicBlock *Before, BasicBlock *LoopDomBB, void remapInstructionsInBlocks(const SmallVectorImpl<BasicBlock *> &Blocks, ValueToValueMapTy &VMap); -} // End llvm namespace +/// Split edge between BB and PredBB and duplicate all non-Phi instructions +/// from BB between its beginning and the StopAt instruction into the split +/// block. Phi nodes are not duplicated, but their uses are handled correctly: +/// we replace them with the uses of corresponding Phi inputs. ValueMapping +/// is used to map the original instructions from BB to their newly-created +/// copies. Returns the split block. +BasicBlock * +DuplicateInstructionsInSplitBetween(BasicBlock *BB, BasicBlock *PredBB, + Instruction *StopAt, + ValueToValueMapTy &ValueMapping); +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_UTILS_CLONING_H diff --git a/include/llvm/Transforms/Utils/FunctionComparator.h b/include/llvm/Transforms/Utils/FunctionComparator.h index a613fc31a5e3..ee58d1d138f7 100644 --- a/include/llvm/Transforms/Utils/FunctionComparator.h +++ b/include/llvm/Transforms/Utils/FunctionComparator.h @@ -314,7 +314,7 @@ protected: private: int cmpOrderings(AtomicOrdering L, AtomicOrdering R) const; int cmpInlineAsm(const InlineAsm *L, const InlineAsm *R) const; - int cmpAttrs(const AttributeSet L, const AttributeSet R) const; + int cmpAttrs(const AttributeList L, const AttributeList R) const; int cmpRangeMetadata(const MDNode *L, const MDNode *R) const; int cmpOperandBundlesSchema(const Instruction *L, const Instruction *R) const; diff --git a/include/llvm/Transforms/Utils/FunctionImportUtils.h b/include/llvm/Transforms/Utils/FunctionImportUtils.h index f18cd92310b4..b9fbef04cdc3 100644 --- a/include/llvm/Transforms/Utils/FunctionImportUtils.h +++ b/include/llvm/Transforms/Utils/FunctionImportUtils.h @@ -32,7 +32,7 @@ class FunctionImportGlobalProcessing { /// Globals to import from this module, all other functions will be /// imported as declarations instead of definitions. - DenseSet<const GlobalValue *> *GlobalsToImport; + SetVector<GlobalValue *> *GlobalsToImport; /// Set to true if the given ModuleSummaryIndex contains any functions /// from this source module, in which case we must conservatively assume @@ -85,7 +85,7 @@ class FunctionImportGlobalProcessing { public: FunctionImportGlobalProcessing( Module &M, const ModuleSummaryIndex &Index, - DenseSet<const GlobalValue *> *GlobalsToImport = nullptr) + SetVector<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 @@ -104,16 +104,15 @@ public: bool run(); - static bool - doImportAsDefinition(const GlobalValue *SGV, - DenseSet<const GlobalValue *> *GlobalsToImport); + static bool doImportAsDefinition(const GlobalValue *SGV, + SetVector<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); + SetVector<GlobalValue *> *GlobalsToImport = nullptr); } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/GlobalStatus.h b/include/llvm/Transforms/Utils/GlobalStatus.h index c36609508808..8cc265bdf81d 100644 --- a/include/llvm/Transforms/Utils/GlobalStatus.h +++ b/include/llvm/Transforms/Utils/GlobalStatus.h @@ -10,11 +10,13 @@ #ifndef LLVM_TRANSFORMS_UTILS_GLOBALSTATUS_H #define LLVM_TRANSFORMS_UTILS_GLOBALSTATUS_H -#include "llvm/IR/Instructions.h" +#include "llvm/Support/AtomicOrdering.h" namespace llvm { -class Value; + +class Constant; class Function; +class Value; /// It is safe to destroy a constant iff it is only used by constants itself. /// Note that constants cannot be cyclic, so this test is pretty easy to @@ -27,11 +29,11 @@ bool isSafeToDestroyConstant(const Constant *C); /// accurate. struct GlobalStatus { /// True if the global's address is used in a comparison. - bool IsCompared; + bool IsCompared = false; /// True if the global is ever loaded. If the global isn't ever loaded it /// can be deleted. - bool IsLoaded; + bool IsLoaded = false; /// Keep track of what stores to the global look like. enum StoredType { @@ -51,32 +53,33 @@ struct GlobalStatus { /// This global is stored to by multiple values or something else that we /// cannot track. Stored - } StoredType; + } StoredType = NotStored; /// If only one value (besides the initializer constant) is ever stored to /// this global, keep track of what value it is. - Value *StoredOnceValue; + Value *StoredOnceValue = nullptr; /// These start out null/false. When the first accessing function is noticed, /// it is recorded. When a second different accessing function is noticed, /// HasMultipleAccessingFunctions is set to true. - const Function *AccessingFunction; - bool HasMultipleAccessingFunctions; + const Function *AccessingFunction = nullptr; + bool HasMultipleAccessingFunctions = false; /// Set to true if this global has a user that is not an instruction (e.g. a /// constant expr or GV initializer). - bool HasNonInstructionUser; + bool HasNonInstructionUser = false; /// Set to the strongest atomic ordering requirement. - AtomicOrdering Ordering; + AtomicOrdering Ordering = AtomicOrdering::NotAtomic; + + GlobalStatus(); /// Look at all uses of the global and fill in the GlobalStatus structure. If /// the global has its address taken, return true to indicate we can't do /// anything with it. static bool analyzeGlobal(const Value *V, GlobalStatus &GS); - - GlobalStatus(); }; -} -#endif +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_GLOBALSTATUS_H diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index 490a765c3fab..4933712fb8ad 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -49,8 +49,6 @@ class LazyValueInfo; template<typename T> class SmallVectorImpl; -typedef SmallVector<DbgValueInst *, 1> DbgValueList; - //===----------------------------------------------------------------------===// // Local constant propagation. // @@ -74,6 +72,12 @@ bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false, bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI = nullptr); +/// Return true if the result produced by the instruction would have no side +/// effects if it was not used. This is equivalent to checking whether +/// isInstructionTriviallyDead would be true if the use count was 0. +bool wouldInstructionBeTriviallyDead(Instruction *I, + const TargetLibraryInfo *TLI = nullptr); + /// 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. @@ -138,7 +142,8 @@ bool EliminateDuplicatePHINodes(BasicBlock *BB); /// eliminate. bool SimplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, unsigned BonusInstThreshold, AssumptionCache *AC = nullptr, - SmallPtrSetImpl<BasicBlock *> *LoopHeaders = nullptr); + SmallPtrSetImpl<BasicBlock *> *LoopHeaders = nullptr, + bool LateSimplifyCFG = false); /// 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 @@ -278,8 +283,11 @@ bool LowerDbgDeclare(Function &F); /// Finds the llvm.dbg.declare intrinsic corresponding to an alloca, if any. DbgDeclareInst *FindAllocaDbgDeclare(Value *V); -/// Finds the llvm.dbg.value intrinsics corresponding to an alloca, if any. -void FindAllocaDbgValues(DbgValueList &DbgValues, Value *V); +/// Finds the llvm.dbg.value intrinsics describing a value. +void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V); + +/// Constants for \p replaceDbgDeclare and friends. +enum { NoDeref = false, WithDeref = true }; /// 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 @@ -306,6 +314,11 @@ bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, int Offset = 0); +/// Assuming the instruction \p I is going to be deleted, attempt to salvage any +/// dbg.value intrinsics referring to \p I by rewriting its effect into a +/// DIExpression. +void salvageDebugInfo(Instruction &I); + /// Remove all instructions from a basic block other than it's terminator /// and any present EH pad instructions. unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB); diff --git a/include/llvm/Transforms/Utils/LoopUtils.h b/include/llvm/Transforms/Utils/LoopUtils.h index 27b45c4fa941..a1cf41d6f931 100644 --- a/include/llvm/Transforms/Utils/LoopUtils.h +++ b/include/llvm/Transforms/Utils/LoopUtils.h @@ -1,4 +1,4 @@ -//===- llvm/Transforms/Utils/LoopUtils.h - Loop utilities -*- C++ -*-=========// +//===- llvm/Transforms/Utils/LoopUtils.h - Loop utilities -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,23 +14,29 @@ #ifndef LLVM_TRANSFORMS_UTILS_LOOPUTILS_H #define LLVM_TRANSFORMS_UTILS_LOOPUTILS_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Support/Casting.h" namespace llvm { + class AliasSet; class AliasSetTracker; -class AssumptionCache; class BasicBlock; class DataLayout; -class DominatorTree; class Loop; class LoopInfo; class OptimizationRemarkEmitter; -class Pass; class PredicatedScalarEvolution; class PredIteratorCache; class ScalarEvolution; @@ -40,12 +46,13 @@ class TargetLibraryInfo; /// \brief Captures loop safety information. /// It keep information for loop & its header may throw exception. struct LoopSafetyInfo { - bool MayThrow; // The current loop contains an instruction which - // may throw. - bool HeaderMayThrow; // Same as previous, but specific to loop header + bool MayThrow = false; // The current loop contains an instruction which + // may throw. + bool HeaderMayThrow = false; // Same as previous, but specific to loop header // Used to update funclet bundle operands. DenseMap<BasicBlock *, ColorVector> BlockColors; - LoopSafetyInfo() : MayThrow(false), HeaderMayThrow(false) {} + + LoopSafetyInfo() = default; }; /// The RecurrenceDescriptor is used to identify recurrences variables in a @@ -61,7 +68,6 @@ struct LoopSafetyInfo { /// This struct holds information about recurrence variables. class RecurrenceDescriptor { - public: /// This enum represents the kinds of recurrences that we support. enum RecurrenceKind { @@ -88,10 +94,7 @@ public: MRK_FloatMax }; - RecurrenceDescriptor() - : StartValue(nullptr), LoopExitInstr(nullptr), Kind(RK_NoRecurrence), - MinMaxKind(MRK_Invalid), UnsafeAlgebraInst(nullptr), - RecurrenceType(nullptr), IsSigned(false) {} + RecurrenceDescriptor() = default; RecurrenceDescriptor(Value *Start, Instruction *Exit, RecurrenceKind K, MinMaxRecurrenceKind MK, Instruction *UAI, Type *RT, @@ -103,7 +106,6 @@ public: /// This POD struct holds information about a potential recurrence operation. class InstDesc { - public: InstDesc(bool IsRecur, Instruction *I, Instruction *UAI = nullptr) : IsRecurrence(IsRecur), PatternLastInst(I), MinMaxKind(MRK_Invalid), @@ -242,17 +244,17 @@ private: // It does not have to be zero! TrackingVH<Value> StartValue; // The instruction who's value is used outside the loop. - Instruction *LoopExitInstr; + Instruction *LoopExitInstr = nullptr; // The kind of the recurrence. - RecurrenceKind Kind; + RecurrenceKind Kind = RK_NoRecurrence; // If this a min/max recurrence the kind of recurrence. - MinMaxRecurrenceKind MinMaxKind; + MinMaxRecurrenceKind MinMaxKind = MRK_Invalid; // First occurrence of unasfe algebra in the PHI's use-chain. - Instruction *UnsafeAlgebraInst; + Instruction *UnsafeAlgebraInst = nullptr; // The type of the recurrence. - Type *RecurrenceType; + Type *RecurrenceType = nullptr; // True if all source operands of the recurrence are SExtInsts. - bool IsSigned; + bool IsSigned = false; // Instructions used for type-promoting the recurrence. SmallPtrSet<Instruction *, 8> CastInsts; }; @@ -270,9 +272,7 @@ public: public: /// Default constructor - creates an invalid induction. - InductionDescriptor() - : StartValue(nullptr), IK(IK_NoInduction), Step(nullptr), - InductionBinOp(nullptr) {} + InductionDescriptor() = default; /// Get the consecutive direction. Returns: /// 0 - unknown or non-consecutive. @@ -350,11 +350,11 @@ private: /// Start value. TrackingVH<Value> StartValue; /// Induction kind. - InductionKind IK; + InductionKind IK = IK_NoInduction; /// Step value. - const SCEV *Step; + const SCEV *Step = nullptr; // Instruction that advances induction variable. - BinaryOperator *InductionBinOp; + BinaryOperator *InductionBinOp = nullptr; }; BasicBlock *InsertPreheaderForLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, @@ -488,6 +488,7 @@ bool canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, Loop *CurLoop, AliasSetTracker *CurAST, LoopSafetyInfo *SafetyInfo, OptimizationRemarkEmitter *ORE = nullptr); -} -#endif +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_LOOPUTILS_H diff --git a/include/llvm/Transforms/Utils/LowerMemIntrinsics.h b/include/llvm/Transforms/Utils/LowerMemIntrinsics.h new file mode 100644 index 000000000000..e4906b709e4b --- /dev/null +++ b/include/llvm/Transforms/Utils/LowerMemIntrinsics.h @@ -0,0 +1,44 @@ +//===- llvm/Transforms/Utils/LowerMemintrinsics.h ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Lower memset, memcpy, memmov intrinsics to loops (e.g. for targets without +// library support). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_LOWERMEMINTRINSICS_H +#define LLVM_TRANSFORMS_UTILS_LOWERMEMINTRINSICS_H + +namespace llvm { + +class Instruction; +class MemCpyInst; +class MemMoveInst; +class MemSetInst; +class Value; + +/// Emit a loop implementing the semantics of llvm.memcpy with the equivalent +/// arguments at \p InsertBefore. +void createMemCpyLoop(Instruction *InsertBefore, + Value *SrcAddr, Value *DstAddr, Value *CopyLen, + unsigned SrcAlign, unsigned DestAlign, + bool SrcIsVolatile, bool DstIsVolatile); + +/// Expand \p MemCpy as a loop. \p MemCpy is not deleted. +void expandMemCpyAsLoop(MemCpyInst *MemCpy); + +/// Expand \p MemMove as a loop. \p MemMove is not deleted. +void expandMemMoveAsLoop(MemMoveInst *MemMove); + +/// Expand \p MemSet as a loop. \p MemSet is not deleted. +void expandMemSetAsLoop(MemSetInst *MemSet); + +} // End llvm namespace + +#endif diff --git a/include/llvm/Transforms/Utils/ModuleUtils.h b/include/llvm/Transforms/Utils/ModuleUtils.h index 27508799f8e0..f5e843e2e8b5 100644 --- a/include/llvm/Transforms/Utils/ModuleUtils.h +++ b/include/llvm/Transforms/Utils/ModuleUtils.h @@ -46,6 +46,9 @@ void appendToGlobalDtors(Module &M, Function *F, int Priority, // getOrInsertFunction returns a bitcast. Function *checkSanitizerInterfaceFunction(Constant *FuncOrBitcast); +Function *declareSanitizerInitFunction(Module &M, StringRef InitName, + ArrayRef<Type *> InitArgTypes); + /// \brief Creates sanitizer constructor function, and calls sanitizer's init /// function from it. /// \return Returns pair of pointers to constructor, and init functions diff --git a/include/llvm/Transforms/Utils/NameAnonGlobals.h b/include/llvm/Transforms/Utils/NameAnonGlobals.h index 4bec361674bb..17fc902eebf8 100644 --- a/include/llvm/Transforms/Utils/NameAnonGlobals.h +++ b/include/llvm/Transforms/Utils/NameAnonGlobals.h @@ -1,4 +1,4 @@ -//===-- NameAnonGlobals.h - Anonymous Global Naming Pass ----*- C++ -*-=======// +//===-- NameAnonGlobals.h - Anonymous Global Naming Pass --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,9 +23,11 @@ namespace llvm { /// Simple pass that provides a name to every anonymous globals. class NameAnonGlobalPass : public PassInfoMixin<NameAnonGlobalPass> { public: - NameAnonGlobalPass() {} + NameAnonGlobalPass() = default; + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; -} + +} // end namespace llvm #endif // LLVM_TRANSFORMS_UTILS_NAMEANONGLOBALS_H diff --git a/include/llvm/Transforms/Utils/PredicateInfo.h b/include/llvm/Transforms/Utils/PredicateInfo.h new file mode 100644 index 000000000000..1322c686eb90 --- /dev/null +++ b/include/llvm/Transforms/Utils/PredicateInfo.h @@ -0,0 +1,295 @@ +//===- PredicateInfo.h - Build PredicateInfo ----------------------*-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 implements the PredicateInfo analysis, which creates an Extended +/// SSA form for operations used in branch comparisons and llvm.assume +/// comparisons. +/// +/// Copies of these operations are inserted into the true/false edge (and after +/// assumes), and information attached to the copies. All uses of the original +/// operation in blocks dominated by the true/false edge (and assume), are +/// replaced with uses of the copies. This enables passes to easily and sparsely +/// propagate condition based info into the operations that may be affected. +/// +/// Example: +/// %cmp = icmp eq i32 %x, 50 +/// br i1 %cmp, label %true, label %false +/// true: +/// ret i32 %x +/// false: +/// ret i32 1 +/// +/// will become +/// +/// %cmp = icmp eq i32, %x, 50 +/// br i1 %cmp, label %true, label %false +/// true: +/// %x.0 = call @llvm.ssa_copy.i32(i32 %x) +/// ret i32 %x.0 +/// false: +/// ret i32 1 +/// +/// Using getPredicateInfoFor on x.0 will give you the comparison it is +/// dominated by (the icmp), and that you are located in the true edge of that +/// comparison, which tells you x.0 is 50. +/// +/// In order to reduce the number of copies inserted, predicateinfo is only +/// inserted where it would actually be live. This means if there are no uses of +/// an operation dominated by the branch edges, or by an assume, the associated +/// predicate info is never inserted. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H +#define LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.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/AssumptionCache.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.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; +class OrderedBasicBlock; + +enum PredicateType { PT_Branch, PT_Assume, PT_Switch }; + +// Base class for all predicate information we provide. +// All of our predicate information has at least a comparison. +class PredicateBase : public ilist_node<PredicateBase> { +public: + PredicateType Type; + // The original operand before we renamed it. + // This can be use by passes, when destroying predicateinfo, to know + // whether they can just drop the intrinsic, or have to merge metadata. + Value *OriginalOp; + PredicateBase(const PredicateBase &) = delete; + PredicateBase &operator=(const PredicateBase &) = delete; + PredicateBase() = delete; + virtual ~PredicateBase() = default; + +protected: + PredicateBase(PredicateType PT, Value *Op) : Type(PT), OriginalOp(Op) {} +}; + +class PredicateWithCondition : public PredicateBase { +public: + Value *Condition; + static inline bool classof(const PredicateBase *PB) { + return PB->Type == PT_Assume || PB->Type == PT_Branch || PB->Type == PT_Switch; + } + +protected: + PredicateWithCondition(PredicateType PT, Value *Op, Value *Condition) + : PredicateBase(PT, Op), Condition(Condition) {} +}; + +// Provides predicate information for assumes. Since assumes are always true, +// we simply provide the assume instruction, so you can tell your relative +// position to it. +class PredicateAssume : public PredicateWithCondition { +public: + IntrinsicInst *AssumeInst; + PredicateAssume(Value *Op, IntrinsicInst *AssumeInst, Value *Condition) + : PredicateWithCondition(PT_Assume, Op, Condition), + AssumeInst(AssumeInst) {} + PredicateAssume() = delete; + static inline bool classof(const PredicateBase *PB) { + return PB->Type == PT_Assume; + } +}; + +// Mixin class for edge predicates. The FROM block is the block where the +// predicate originates, and the TO block is the block where the predicate is +// valid. +class PredicateWithEdge : public PredicateWithCondition { +public: + BasicBlock *From; + BasicBlock *To; + PredicateWithEdge() = delete; + static inline bool classof(const PredicateBase *PB) { + return PB->Type == PT_Branch || PB->Type == PT_Switch; + } + +protected: + PredicateWithEdge(PredicateType PType, Value *Op, BasicBlock *From, + BasicBlock *To, Value *Cond) + : PredicateWithCondition(PType, Op, Cond), From(From), To(To) {} +}; + +// Provides predicate information for branches. +class PredicateBranch : public PredicateWithEdge { +public: + // If true, SplitBB is the true successor, otherwise it's the false successor. + bool TrueEdge; + PredicateBranch(Value *Op, BasicBlock *BranchBB, BasicBlock *SplitBB, + Value *Condition, bool TakenEdge) + : PredicateWithEdge(PT_Branch, Op, BranchBB, SplitBB, Condition), + TrueEdge(TakenEdge) {} + PredicateBranch() = delete; + static inline bool classof(const PredicateBase *PB) { + return PB->Type == PT_Branch; + } +}; + +class PredicateSwitch : public PredicateWithEdge { +public: + Value *CaseValue; + // This is the switch instruction. + SwitchInst *Switch; + PredicateSwitch(Value *Op, BasicBlock *SwitchBB, BasicBlock *TargetBB, + Value *CaseValue, SwitchInst *SI) + : PredicateWithEdge(PT_Switch, Op, SwitchBB, TargetBB, + SI->getCondition()), + CaseValue(CaseValue), Switch(SI) {} + PredicateSwitch() = delete; + static inline bool classof(const PredicateBase *PB) { + return PB->Type == PT_Switch; + } +}; + +// This name is used in a few places, so kick it into their own namespace +namespace PredicateInfoClasses { +struct ValueDFS; +} + +/// \brief Encapsulates PredicateInfo, including all data associated with memory +/// accesses. +class PredicateInfo { +private: + // Used to store information about each value we might rename. + struct ValueInfo { + // Information about each possible copy. During processing, this is each + // inserted info. After processing, we move the uninserted ones to the + // uninserted vector. + SmallVector<PredicateBase *, 4> Infos; + SmallVector<PredicateBase *, 4> UninsertedInfos; + }; + // This owns the all the predicate infos in the function, placed or not. + iplist<PredicateBase> AllInfos; + +public: + PredicateInfo(Function &, DominatorTree &, AssumptionCache &); + ~PredicateInfo(); + + void verifyPredicateInfo() const; + + void dump() const; + void print(raw_ostream &) const; + + const PredicateBase *getPredicateInfoFor(const Value *V) const { + return PredicateMap.lookup(V); + } + +protected: + // Used by PredicateInfo annotater, dumpers, and wrapper pass. + friend class PredicateInfoAnnotatedWriter; + friend class PredicateInfoPrinterLegacyPass; + +private: + void buildPredicateInfo(); + void processAssume(IntrinsicInst *, BasicBlock *, SmallPtrSetImpl<Value *> &); + void processBranch(BranchInst *, BasicBlock *, SmallPtrSetImpl<Value *> &); + void processSwitch(SwitchInst *, BasicBlock *, SmallPtrSetImpl<Value *> &); + void renameUses(SmallPtrSetImpl<Value *> &); + using ValueDFS = PredicateInfoClasses::ValueDFS; + typedef SmallVectorImpl<ValueDFS> ValueDFSStack; + void convertUsesToDFSOrdered(Value *, SmallVectorImpl<ValueDFS> &); + Value *materializeStack(unsigned int &, ValueDFSStack &, Value *); + bool stackIsInScope(const ValueDFSStack &, const ValueDFS &) const; + void popStackUntilDFSScope(ValueDFSStack &, const ValueDFS &); + ValueInfo &getOrCreateValueInfo(Value *); + void addInfoFor(SmallPtrSetImpl<Value *> &OpsToRename, Value *Op, + PredicateBase *PB); + const ValueInfo &getValueInfo(Value *) const; + Function &F; + DominatorTree &DT; + AssumptionCache &AC; + // This maps from copy operands to Predicate Info. Note that it does not own + // the Predicate Info, they belong to the ValueInfo structs in the ValueInfos + // vector. + DenseMap<const Value *, const PredicateBase *> PredicateMap; + // This stores info about each operand or comparison result we make copies + // of. The real ValueInfos start at index 1, index 0 is unused so that we can + // more easily detect invalid indexing. + SmallVector<ValueInfo, 32> ValueInfos; + // This gives the index into the ValueInfos array for a given Value. Because + // 0 is not a valid Value Info index, you can use DenseMap::lookup and tell + // whether it returned a valid result. + DenseMap<Value *, unsigned int> ValueInfoNums; + // OrderedBasicBlocks used during sorting uses + DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBlock>> OBBMap; + // The set of edges along which we can only handle phi uses, due to critical + // edges. + DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeUsesOnly; +}; + +// This pass does eager building and then printing of PredicateInfo. It is used +// by +// the tests to be able to build, dump, and verify PredicateInfo. +class PredicateInfoPrinterLegacyPass : public FunctionPass { +public: + PredicateInfoPrinterLegacyPass(); + + static char ID; + bool runOnFunction(Function &) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +/// \brief Printer pass for \c PredicateInfo. +class PredicateInfoPrinterPass + : public PassInfoMixin<PredicateInfoPrinterPass> { + raw_ostream &OS; + +public: + explicit PredicateInfoPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +/// \brief Verifier pass for \c PredicateInfo. +struct PredicateInfoVerifierPass : PassInfoMixin<PredicateInfoVerifierPass> { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H diff --git a/include/llvm/Transforms/Utils/PromoteMemToReg.h b/include/llvm/Transforms/Utils/PromoteMemToReg.h index b548072c413e..bb8a61a474f2 100644 --- a/include/llvm/Transforms/Utils/PromoteMemToReg.h +++ b/include/llvm/Transforms/Utils/PromoteMemToReg.h @@ -38,10 +38,7 @@ bool isAllocaPromotable(const AllocaInst *AI); /// does not modify the CFG of the function at all. All allocas must be from /// the same function. /// -/// If AST is specified, the specified tracker is updated to reflect changes -/// made to the IR. void PromoteMemToReg(ArrayRef<AllocaInst *> Allocas, DominatorTree &DT, - AliasSetTracker *AST = nullptr, AssumptionCache *AC = nullptr); } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/SSAUpdater.h b/include/llvm/Transforms/Utils/SSAUpdater.h index 9f98bac22dc9..8cbcdf47156e 100644 --- a/include/llvm/Transforms/Utils/SSAUpdater.h +++ b/include/llvm/Transforms/Utils/SSAUpdater.h @@ -15,19 +15,20 @@ #define LLVM_TRANSFORMS_UTILS_SSAUPDATER_H #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" +#include <string> namespace llvm { - class BasicBlock; - class Instruction; - class LoadInst; - template <typename T> class ArrayRef; - template <typename T> class SmallVectorImpl; - template <typename T> class SSAUpdaterTraits; - class PHINode; - class Type; - class Use; - class Value; + +class BasicBlock; +class Instruction; +class LoadInst; +template <typename T> class ArrayRef; +template <typename T> class SmallVectorImpl; +template <typename T> class SSAUpdaterTraits; +class PHINode; +class Type; +class Use; +class Value; /// \brief Helper class for SSA formation on a set of values defined in /// multiple blocks. @@ -42,10 +43,10 @@ private: /// This keeps track of which value to use on a per-block basis. When we /// insert PHI nodes, we keep track of them here. //typedef DenseMap<BasicBlock*, Value*> AvailableValsTy; - void *AV; + void *AV = nullptr; /// ProtoType holds the type of the values being rewritten. - Type *ProtoType; + Type *ProtoType = nullptr; /// PHI nodes are given a name based on ProtoName. std::string ProtoName; @@ -58,6 +59,8 @@ public: /// If InsertedPHIs is specified, it will be filled /// in with all PHI Nodes created by rewriting. explicit SSAUpdater(SmallVectorImpl<PHINode*> *InsertedPHIs = nullptr); + SSAUpdater(const SSAUpdater &) = delete; + SSAUpdater &operator=(const SSAUpdater &) = delete; ~SSAUpdater(); /// \brief Reset this object to get ready for a new set of SSA updates with @@ -118,9 +121,6 @@ public: private: Value *GetValueAtEndOfBlockInternal(BasicBlock *BB); - - void operator=(const SSAUpdater&) = delete; - SSAUpdater(const SSAUpdater&) = delete; }; /// \brief Helper class for promoting a collection of loads and stores into SSA @@ -138,7 +138,7 @@ protected: public: LoadAndStorePromoter(ArrayRef<const Instruction*> Insts, SSAUpdater &S, StringRef Name = StringRef()); - virtual ~LoadAndStorePromoter() {} + virtual ~LoadAndStorePromoter() = default; /// \brief This does the promotion. /// @@ -173,6 +173,6 @@ public: } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_UTILS_SSAUPDATER_H diff --git a/include/llvm/Transforms/Utils/SimplifyIndVar.h b/include/llvm/Transforms/Utils/SimplifyIndVar.h index 90438ee699fe..6cdeeeb60a65 100644 --- a/include/llvm/Transforms/Utils/SimplifyIndVar.h +++ b/include/llvm/Transforms/Utils/SimplifyIndVar.h @@ -22,7 +22,6 @@ namespace llvm { class CastInst; class DominatorTree; -class IVUsers; class Loop; class LoopInfo; class PHINode; @@ -32,13 +31,13 @@ class ScalarEvolution; /// simplified by this utility. class IVVisitor { protected: - const DominatorTree *DT; + const DominatorTree *DT = nullptr; virtual void anchor(); public: - IVVisitor() : DT(nullptr) {} - virtual ~IVVisitor() {} + IVVisitor() = default; + virtual ~IVVisitor() = default; const DominatorTree *getDomTree() const { return DT; } virtual void visitCast(CastInst *Cast) = 0; @@ -55,6 +54,6 @@ bool simplifyUsersOfIV(PHINode *CurrIV, ScalarEvolution *SE, DominatorTree *DT, bool simplifyLoopIVs(Loop *L, ScalarEvolution *SE, DominatorTree *DT, LoopInfo *LI, SmallVectorImpl<WeakVH> &Dead); -} // namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_UTILS_SIMPLIFYINDVAR_H diff --git a/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 5e217adf1987..665dd6f4b257 100644 --- a/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -56,8 +56,8 @@ private: Value *optimizeMemSetChk(CallInst *CI, IRBuilder<> &B); // Str/Stp cpy are similar enough to be handled in the same functions. - Value *optimizeStrpCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc::Func Func); - Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc::Func Func); + Value *optimizeStrpCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); + Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); /// \brief Checks whether the call \p CI to a fortified libcall is foldable /// to the non-fortified version. @@ -128,7 +128,6 @@ private: Value *optimizeCos(CallInst *CI, IRBuilder<> &B); Value *optimizePow(CallInst *CI, IRBuilder<> &B); Value *optimizeExp2(CallInst *CI, IRBuilder<> &B); - Value *optimizeFabs(CallInst *CI, IRBuilder<> &B); Value *optimizeFMinFMax(CallInst *CI, IRBuilder<> &B); Value *optimizeLog(CallInst *CI, IRBuilder<> &B); Value *optimizeSqrt(CallInst *CI, IRBuilder<> &B); diff --git a/include/llvm/Transforms/Utils/SymbolRewriter.h b/include/llvm/Transforms/Utils/SymbolRewriter.h index ff995173e126..93658989fba5 100644 --- a/include/llvm/Transforms/Utils/SymbolRewriter.h +++ b/include/llvm/Transforms/Utils/SymbolRewriter.h @@ -36,18 +36,24 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include <list> +#include <memory> +#include <string> namespace llvm { + class MemoryBuffer; namespace yaml { + class KeyValueNode; class MappingNode; class ScalarNode; class Stream; -} + +} // end namespace yaml namespace SymbolRewriter { + /// The basic entity representing a rewrite operation. It serves as the base /// class for any rewrite descriptor. It has a certain set of specializations /// which describe a particular rewrite. @@ -60,11 +66,6 @@ namespace SymbolRewriter { /// select the symbols to rewrite. This descriptor list is passed to the /// SymbolRewriter pass. class RewriteDescriptor { - RewriteDescriptor(const RewriteDescriptor &) = delete; - - const RewriteDescriptor & - operator=(const RewriteDescriptor &) = delete; - public: enum class Type { Invalid, /// invalid @@ -73,7 +74,9 @@ public: NamedAlias, /// named alias - descriptor rewrites a global alias }; - virtual ~RewriteDescriptor() {} + RewriteDescriptor(const RewriteDescriptor &) = delete; + RewriteDescriptor &operator=(const RewriteDescriptor &) = delete; + virtual ~RewriteDescriptor() = default; Type getType() const { return Kind; } @@ -108,7 +111,8 @@ private: yaml::MappingNode *V, RewriteDescriptorList *DL); }; -} + +} // end namespace SymbolRewriter ModulePass *createRewriteSymbolsPass(); ModulePass *createRewriteSymbolsPass(SymbolRewriter::RewriteDescriptorList &); @@ -130,6 +134,7 @@ private: SymbolRewriter::RewriteDescriptorList Descriptors; }; -} + +} // end namespace llvm #endif //LLVM_TRANSFORMS_UTILS_SYMBOLREWRITER_H diff --git a/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h b/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h index 550292f6b7a3..222c601ad608 100644 --- a/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h +++ b/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h @@ -19,16 +19,18 @@ #define LLVM_TRANSFORMS_UTILS_UNIFYFUNCTIONEXITNODES_H #include "llvm/Pass.h" +#include "llvm/PassRegistry.h" namespace llvm { struct UnifyFunctionExitNodes : public FunctionPass { - BasicBlock *ReturnBlock, *UnwindBlock, *UnreachableBlock; + BasicBlock *ReturnBlock = nullptr; + BasicBlock *UnwindBlock = nullptr; + BasicBlock *UnreachableBlock; public: static char ID; // Pass identification, replacement for typeid - UnifyFunctionExitNodes() : FunctionPass(ID), - ReturnBlock(nullptr), UnwindBlock(nullptr) { + UnifyFunctionExitNodes() : FunctionPass(ID) { initializeUnifyFunctionExitNodesPass(*PassRegistry::getPassRegistry()); } @@ -47,6 +49,6 @@ public: Pass *createUnifyFunctionExitNodesPass(); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_UTILS_UNIFYFUNCTIONEXITNODES_H diff --git a/include/llvm/Transforms/Utils/UnrollLoop.h b/include/llvm/Transforms/Utils/UnrollLoop.h index f322bea7aa2e..a3115ad16914 100644 --- a/include/llvm/Transforms/Utils/UnrollLoop.h +++ b/include/llvm/Transforms/Utils/UnrollLoop.h @@ -53,10 +53,11 @@ bool UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, bool PreserveLCSSA); void computePeelCount(Loop *L, unsigned LoopSize, - TargetTransformInfo::UnrollingPreferences &UP); + TargetTransformInfo::UnrollingPreferences &UP, + unsigned &TripCount); bool peelLoop(Loop *L, unsigned PeelCount, LoopInfo *LI, ScalarEvolution *SE, - DominatorTree *DT, bool PreserveLCSSA); + DominatorTree *DT, AssumptionCache *AC, bool PreserveLCSSA); MDNode *GetUnrollMetadata(MDNode *LoopID, StringRef Name); } diff --git a/include/llvm/Transforms/Utils/VNCoercion.h b/include/llvm/Transforms/Utils/VNCoercion.h new file mode 100644 index 000000000000..1baa9b66e491 --- /dev/null +++ b/include/llvm/Transforms/Utils/VNCoercion.h @@ -0,0 +1,108 @@ +//===- VNCoercion.h - Value Numbering Coercion Utilities --------*- 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 routines used by LLVM's value numbering passes to +/// perform various forms of value extraction from memory when the types are not +/// identical. For example, given +/// +/// store i32 8, i32 *%foo +/// %a = bitcast i32 *%foo to i16 +/// %val = load i16, i16 *%a +/// +/// It possible to extract the value of the load of %a from the store to %foo. +/// These routines know how to tell whether they can do that (the analyze* +/// routines), and can also insert the necessary IR to do it (the get* +/// routines). + +#ifndef LLVM_TRANSFORMS_UTILS_VNCOERCION_H +#define LLVM_TRANSFORMS_UTILS_VNCOERCION_H +#include "llvm/IR/IRBuilder.h" + +namespace llvm { +class Function; +class StoreInst; +class LoadInst; +class MemIntrinsic; +class Instruction; +class Value; +class Type; +class DataLayout; +namespace VNCoercion { +/// Return true if CoerceAvailableValueToLoadType would succeed if it was +/// called. +bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, + const DataLayout &DL); + +/// If we saw a store of a value to memory, and then a load from a must-aliased +/// pointer of a different type, try to coerce the stored value to the loaded +/// type. LoadedTy is the type of the load we want to replace. IRB is +/// IRBuilder used to insert new instructions. +/// +/// If we can't do it, return null. +Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + IRBuilder<> &IRB, const DataLayout &DL); + +/// This function determines whether a value for the pointer LoadPtr can be +/// extracted from the store at DepSI. +/// +/// On success, it returns the offset into DepSI that extraction would start. +/// On failure, it returns -1. +int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, + StoreInst *DepSI, const DataLayout &DL); + +/// This function determines whether a value for the pointer LoadPtr can be +/// extracted from the load at DepLI. +/// +/// On success, it returns the offset into DepLI that extraction would start. +/// On failure, it returns -1. +int analyzeLoadFromClobberingLoad(Type *LoadTy, Value *LoadPtr, LoadInst *DepLI, + const DataLayout &DL); + +/// This function determines whether a value for the pointer LoadPtr can be +/// extracted from the memory intrinsic at DepMI. +/// +/// On success, it returns the offset into DepMI that extraction would start. +/// On failure, it returns -1. +int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, + MemIntrinsic *DepMI, const DataLayout &DL); + +/// If analyzeLoadFromClobberingStore returned an offset, this function can be +/// used to actually perform the extraction of the bits from the store. It +/// inserts instructions to do so at InsertPt, and returns the extracted value. +Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, + Instruction *InsertPt, const DataLayout &DL); +// This is the same as getStoreValueForLoad, except it performs no insertion +// It only allows constant inputs. +Constant *getConstantStoreValueForLoad(Constant *SrcVal, unsigned Offset, + Type *LoadTy, const DataLayout &DL); + +/// If analyzeLoadFromClobberingLoad returned an offset, this function can be +/// used to actually perform the extraction of the bits from the load, including +/// any necessary load widening. It inserts instructions to do so at InsertPt, +/// and returns the extracted value. +Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, + Instruction *InsertPt, const DataLayout &DL); +// This is the same as getLoadValueForLoad, except it is given the load value as +// a constant. It returns nullptr if it would require widening the load. +Constant *getConstantLoadValueForLoad(Constant *SrcVal, unsigned Offset, + Type *LoadTy, const DataLayout &DL); + +/// If analyzeLoadFromClobberingMemInst returned an offset, this function can be +/// used to actually perform the extraction of the bits from the memory +/// intrinsic. It inserts instructions to do so at InsertPt, and returns the +/// extracted value. +Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, + Type *LoadTy, Instruction *InsertPt, + const DataLayout &DL); +// This is the same as getStoreValueForLoad, except it performs no insertion. +// It returns nullptr if it cannot produce a constant. +Constant *getConstantMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, + Type *LoadTy, const DataLayout &DL); +} +} +#endif diff --git a/include/llvm/Transforms/Utils/ValueMapper.h b/include/llvm/Transforms/Utils/ValueMapper.h index de649009612c..950ad92afcd7 100644 --- a/include/llvm/Transforms/Utils/ValueMapper.h +++ b/include/llvm/Transforms/Utils/ValueMapper.h @@ -15,7 +15,9 @@ #ifndef LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H #define LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/IR/ValueMap.h" +#include "llvm/IR/ValueHandle.h" namespace llvm { @@ -27,8 +29,9 @@ typedef ValueMap<const Value *, WeakVH> ValueToValueMapTy; /// cloning constants and instructions. class ValueMapTypeRemapper { virtual void anchor(); // Out of line method. + public: - virtual ~ValueMapTypeRemapper() {} + virtual ~ValueMapTypeRemapper() = default; /// The client should implement this method if they want to remap types while /// mapping values. @@ -92,8 +95,6 @@ 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 @@ -133,15 +134,14 @@ class ValueMapperImpl; 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(ValueMapper &&) = delete; + ValueMapper(const ValueMapper &) = delete; + ValueMapper &operator=(ValueMapper &&) = delete; + ValueMapper &operator=(const ValueMapper &) = delete; ~ValueMapper(); /// Register an alternate mapping context. @@ -268,6 +268,6 @@ inline Constant *MapValue(const Constant *V, ValueToValueMapTy &VM, return ValueMapper(VM, Flags, TypeMapper, Materializer).mapConstant(*V); } -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H diff --git a/include/llvm/Transforms/Vectorize/SLPVectorizer.h b/include/llvm/Transforms/Vectorize/SLPVectorizer.h index 4886700774ca..d669a8e5b615 100644 --- a/include/llvm/Transforms/Vectorize/SLPVectorizer.h +++ b/include/llvm/Transforms/Vectorize/SLPVectorizer.h @@ -92,6 +92,12 @@ private: /// collected in GEPs. bool vectorizeGEPIndices(BasicBlock *BB, slpvectorizer::BoUpSLP &R); + /// Try to find horizontal reduction or otherwise vectorize a chain of binary + /// operators. + bool vectorizeRootInstruction(PHINode *P, Value *V, BasicBlock *BB, + slpvectorizer::BoUpSLP &R, + TargetTransformInfo *TTI); + /// \brief Scan the basic block and look for patterns that are likely to start /// a vectorization chain. bool vectorizeChainsInBlock(BasicBlock *BB, slpvectorizer::BoUpSLP &R); diff --git a/include/llvm/XRay/Graph.h b/include/llvm/XRay/Graph.h new file mode 100644 index 000000000000..a4d34a8a4be3 --- /dev/null +++ b/include/llvm/XRay/Graph.h @@ -0,0 +1,494 @@ +//===-- Graph.h - XRay Graph Class ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A Graph Datatype for XRay. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_XRAY_GRAPH_T_H +#define LLVM_XRAY_GRAPH_T_H + +#include <initializer_list> +#include <stdint.h> +#include <type_traits> +#include <utility> + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace xray { + +/// A Graph object represents a Directed Graph and is used in XRay to compute +/// and store function call graphs and associated statistical information. +/// +/// The graph takes in four template parameters, these are: +/// - VertexAttribute, this is a structure which is stored for each vertex. +/// Must be DefaultConstructible, CopyConstructible, CopyAssignable and +/// Destructible. +/// - EdgeAttribute, this is a structure which is stored for each edge +/// Must be DefaultConstructible, CopyConstructible, CopyAssignable and +/// Destructible. +/// - EdgeAttribute, this is a structure which is stored for each variable +/// - VI, this is a type over which DenseMapInfo is defined and is the type +/// used look up strings, available as VertexIdentifier. +/// - If the built in DenseMapInfo is not defined, provide a specialization +/// class type here. +/// +/// Graph is CopyConstructible, CopyAssignable, MoveConstructible and +/// MoveAssignable but is not EqualityComparible or LessThanComparible. +/// +/// Usage Example Graph with weighted edges and vertices: +/// Graph<int, int, int> G; +/// +/// G[1] = 0; +/// G[2] = 2; +/// G[{1,2}] = 1; +/// G[{2,1}] = -1; +/// for(const auto &v : G.vertices()){ +/// // Do something with the vertices in the graph; +/// } +/// for(const auto &e : G.edges()){ +/// // Do something with the edges in the graph; +/// } +/// +/// Usage Example with StrRef keys. +/// Graph<int, double, StrRef> StrG; +/// char va[] = "Vertex A"; +/// char vaa[] = "Vertex A"; +/// char vb[] = "Vertex B"; // Vertices are referenced by String Refs. +/// G[va] = 0; +/// G[vb] = 1; +/// G[{va, vb}] = 1.0; +/// cout() << G[vaa] << " " << G[{vaa, vb}]; //prints "0 1.0". +/// +template <typename VertexAttribute, typename EdgeAttribute, + typename VI = int32_t> +class Graph { +public: + /// These objects are used to name edges and vertices in the graph. + typedef VI VertexIdentifier; + typedef std::pair<VI, VI> EdgeIdentifier; + + /// This type is the value_type of all iterators which range over vertices, + /// Determined by the Vertices DenseMap + using VertexValueType = + detail::DenseMapPair<VertexIdentifier, VertexAttribute>; + + /// This type is the value_type of all iterators which range over edges, + /// Determined by the Edges DenseMap. + using EdgeValueType = detail::DenseMapPair<EdgeIdentifier, EdgeAttribute>; + + using size_type = std::size_t; + +private: + /// The type used for storing the EdgeAttribute for each edge in the graph + using EdgeMapT = DenseMap<EdgeIdentifier, EdgeAttribute>; + + /// The type used for storing the VertexAttribute for each vertex in + /// the graph. + using VertexMapT = DenseMap<VertexIdentifier, VertexAttribute>; + + /// The type used for storing the edges entering a vertex. Indexed by + /// the VertexIdentifier of the start of the edge. Only used to determine + /// where the incoming edges are, the EdgeIdentifiers are stored in an + /// InnerEdgeMapT. + using NeighborSetT = DenseSet<VertexIdentifier>; + + /// The type storing the InnerInvGraphT corresponding to each vertex in + /// the graph (When a vertex has an incoming edge incident to it) + using NeighborLookupT = DenseMap<VertexIdentifier, NeighborSetT>; + +private: + /// Stores the map from the start and end vertex of an edge to it's + /// EdgeAttribute + EdgeMapT Edges; + + /// Stores the map from VertexIdentifier to VertexAttribute + VertexMapT Vertices; + + /// Allows fast lookup for the incoming edge set of any given vertex. + NeighborLookupT InNeighbors; + + /// Allows fast lookup for the outgoing edge set of any given vertex. + NeighborLookupT OutNeighbors; + + /// An Iterator adapter using an InnerInvGraphT::iterator as a base iterator, + /// and storing the VertexIdentifier the iterator range comes from. The + /// dereference operator is then performed using a pointer to the graph's edge + /// set. + template <bool IsConst, bool IsOut, + typename BaseIt = typename NeighborSetT::const_iterator, + typename T = typename std::conditional<IsConst, const EdgeValueType, + EdgeValueType>::type> + class NeighborEdgeIteratorT + : public iterator_adaptor_base< + NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt, + typename std::iterator_traits<BaseIt>::iterator_category, T> { + using InternalEdgeMapT = + typename std::conditional<IsConst, const EdgeMapT, EdgeMapT>::type; + + friend class NeighborEdgeIteratorT<false, IsOut, BaseIt, EdgeValueType>; + friend class NeighborEdgeIteratorT<true, IsOut, BaseIt, + const EdgeValueType>; + + InternalEdgeMapT *MP; + VertexIdentifier SI; + + public: + template <bool IsConstDest, + typename = typename std::enable_if<IsConstDest && !IsConst>::type> + operator NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt, + const EdgeValueType>() const { + return NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt, + const EdgeValueType>(this->I, MP, SI); + } + + NeighborEdgeIteratorT() = default; + NeighborEdgeIteratorT(BaseIt _I, InternalEdgeMapT *_MP, + VertexIdentifier _SI) + : iterator_adaptor_base< + NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt, + typename std::iterator_traits<BaseIt>::iterator_category, T>(_I), + MP(_MP), SI(_SI) {} + + T &operator*() const { + if (!IsOut) + return *(MP->find({*(this->I), SI})); + else + return *(MP->find({SI, *(this->I)})); + } + }; + +public: + /// A const iterator type for iterating through the set of edges entering a + /// vertex. + /// + /// Has a const EdgeValueType as its value_type + using ConstInEdgeIterator = NeighborEdgeIteratorT<true, false>; + + /// An iterator type for iterating through the set of edges leaving a vertex. + /// + /// Has an EdgeValueType as its value_type + using InEdgeIterator = NeighborEdgeIteratorT<false, false>; + + /// A const iterator type for iterating through the set of edges entering a + /// vertex. + /// + /// Has a const EdgeValueType as its value_type + using ConstOutEdgeIterator = NeighborEdgeIteratorT<true, true>; + + /// An iterator type for iterating through the set of edges leaving a vertex. + /// + /// Has an EdgeValueType as its value_type + using OutEdgeIterator = NeighborEdgeIteratorT<false, true>; + + /// A class for ranging over the incoming edges incident to a vertex. + /// + /// Like all views in this class it provides methods to get the beginning and + /// past the range iterators for the range, as well as methods to determine + /// the number of elements in the range and whether the range is empty. + template <bool isConst, bool isOut> class InOutEdgeView { + public: + using iterator = NeighborEdgeIteratorT<isConst, isOut>; + using const_iterator = NeighborEdgeIteratorT<true, isOut>; + using GraphT = typename std::conditional<isConst, const Graph, Graph>::type; + using InternalEdgeMapT = + typename std::conditional<isConst, const EdgeMapT, EdgeMapT>::type; + + private: + InternalEdgeMapT &M; + const VertexIdentifier A; + const NeighborLookupT &NL; + + public: + iterator begin() { + auto It = NL.find(A); + if (It == NL.end()) + return iterator(); + return iterator(It->second.begin(), &M, A); + } + + const_iterator cbegin() const { + auto It = NL.find(A); + if (It == NL.end()) + return const_iterator(); + return const_iterator(It->second.begin(), &M, A); + } + + const_iterator begin() const { return cbegin(); } + + iterator end() { + auto It = NL.find(A); + if (It == NL.end()) + return iterator(); + return iterator(It->second.end(), &M, A); + } + const_iterator cend() const { + auto It = NL.find(A); + if (It == NL.end()) + return const_iterator(); + return const_iterator(It->second.end(), &M, A); + } + + const_iterator end() const { return cend(); } + + size_type size() const { + auto I = NL.find(A); + if (I == NL.end()) + return 0; + else + return I->second.size(); + } + + bool empty() const { return NL.count(A) == 0; }; + + InOutEdgeView(GraphT &G, VertexIdentifier A) + : M(G.Edges), A(A), NL(isOut ? G.OutNeighbors : G.InNeighbors) {} + }; + + /// A const iterator type for iterating through the whole vertex set of the + /// graph. + /// + /// Has a const VertexValueType as its value_type + using ConstVertexIterator = typename VertexMapT::const_iterator; + + /// An iterator type for iterating through the whole vertex set of the graph. + /// + /// Has a VertexValueType as its value_type + using VertexIterator = typename VertexMapT::iterator; + + /// A class for ranging over the vertices in the graph. + /// + /// Like all views in this class it provides methods to get the beginning and + /// past the range iterators for the range, as well as methods to determine + /// the number of elements in the range and whether the range is empty. + template <bool isConst> class VertexView { + public: + using iterator = typename std::conditional<isConst, ConstVertexIterator, + VertexIterator>::type; + using const_iterator = ConstVertexIterator; + using GraphT = typename std::conditional<isConst, const Graph, Graph>::type; + + private: + GraphT &G; + + public: + iterator begin() { return G.Vertices.begin(); } + iterator end() { return G.Vertices.end(); } + const_iterator cbegin() const { return G.Vertices.cbegin(); } + const_iterator cend() const { return G.Vertices.cend(); } + const_iterator begin() const { return G.Vertices.begin(); } + const_iterator end() const { return G.Vertices.end(); } + size_type size() const { return G.Vertices.size(); } + bool empty() const { return G.Vertices.empty(); } + VertexView(GraphT &_G) : G(_G) {} + }; + + /// A const iterator for iterating through the entire edge set of the graph. + /// + /// Has a const EdgeValueType as its value_type + using ConstEdgeIterator = typename EdgeMapT::const_iterator; + + /// An iterator for iterating through the entire edge set of the graph. + /// + /// Has an EdgeValueType as its value_type + using EdgeIterator = typename EdgeMapT::iterator; + + /// A class for ranging over all the edges in the graph. + /// + /// Like all views in this class it provides methods to get the beginning and + /// past the range iterators for the range, as well as methods to determine + /// the number of elements in the range and whether the range is empty. + template <bool isConst> class EdgeView { + public: + using iterator = typename std::conditional<isConst, ConstEdgeIterator, + EdgeIterator>::type; + using const_iterator = ConstEdgeIterator; + using GraphT = typename std::conditional<isConst, const Graph, Graph>::type; + + private: + GraphT &G; + + public: + iterator begin() { return G.Edges.begin(); } + iterator end() { return G.Edges.end(); } + const_iterator cbegin() const { return G.Edges.cbegin(); } + const_iterator cend() const { return G.Edges.cend(); } + const_iterator begin() const { return G.Edges.begin(); } + const_iterator end() const { return G.Edges.end(); } + size_type size() const { return G.Edges.size(); } + bool empty() const { return G.Edges.empty(); } + EdgeView(GraphT &_G) : G(_G) {} + }; + +public: + // TODO: implement constructor to enable Graph Initialisation.\ + // Something like: + // Graph<int, int, int> G( + // {1, 2, 3, 4, 5}, + // {{1, 2}, {2, 3}, {3, 4}}); + + /// Empty the Graph + void clear() { + Edges.clear(); + Vertices.clear(); + InNeighbors.clear(); + OutNeighbors.clear(); + } + + /// Returns a view object allowing iteration over the vertices of the graph. + /// also allows access to the size of the vertex set. + VertexView<false> vertices() { return VertexView<false>(*this); } + + VertexView<true> vertices() const { return VertexView<true>(*this); } + + /// Returns a view object allowing iteration over the edges of the graph. + /// also allows access to the size of the edge set. + EdgeView<false> edges() { return EdgeView<false>(*this); } + + EdgeView<true> edges() const { return EdgeView<true>(*this); } + + /// Returns a view object allowing iteration over the edges which start at + /// a vertex I. + InOutEdgeView<false, true> outEdges(const VertexIdentifier I) { + return InOutEdgeView<false, true>(*this, I); + } + + InOutEdgeView<true, true> outEdges(const VertexIdentifier I) const { + return InOutEdgeView<true, true>(*this, I); + } + + /// Returns a view object allowing iteration over the edges which point to + /// a vertex I. + InOutEdgeView<false, false> inEdges(const VertexIdentifier I) { + return InOutEdgeView<false, false>(*this, I); + } + + InOutEdgeView<true, false> inEdges(const VertexIdentifier I) const { + return InOutEdgeView<true, false>(*this, I); + } + + /// Looks up the vertex with identifier I, if it does not exist it default + /// constructs it. + VertexAttribute &operator[](const VertexIdentifier &I) { + return Vertices.FindAndConstruct(I).second; + } + + /// Looks up the edge with identifier I, if it does not exist it default + /// constructs it, if it's endpoints do not exist it also default constructs + /// them. + EdgeAttribute &operator[](const EdgeIdentifier &I) { + auto &P = Edges.FindAndConstruct(I); + Vertices.FindAndConstruct(I.first); + Vertices.FindAndConstruct(I.second); + InNeighbors[I.second].insert(I.first); + OutNeighbors[I.first].insert(I.second); + return P.second; + } + + /// Looks up a vertex with Identifier I, or an error if it does not exist. + Expected<VertexAttribute &> at(const VertexIdentifier &I) { + auto It = Vertices.find(I); + if (It == Vertices.end()) + return make_error<StringError>( + "Vertex Identifier Does Not Exist", + std::make_error_code(std::errc::invalid_argument)); + return It->second; + } + + Expected<const VertexAttribute &> at(const VertexIdentifier &I) const { + auto It = Vertices.find(I); + if (It == Vertices.end()) + return make_error<StringError>( + "Vertex Identifier Does Not Exist", + std::make_error_code(std::errc::invalid_argument)); + return It->second; + } + + /// Looks up an edge with Identifier I, or an error if it does not exist. + Expected<EdgeAttribute &> at(const EdgeIdentifier &I) { + auto It = Edges.find(I); + if (It == Edges.end()) + return make_error<StringError>( + "Edge Identifier Does Not Exist", + std::make_error_code(std::errc::invalid_argument)); + return It->second; + } + + Expected<const EdgeAttribute &> at(const EdgeIdentifier &I) const { + auto It = Edges.find(I); + if (It == Edges.end()) + return make_error<StringError>( + "Edge Identifier Does Not Exist", + std::make_error_code(std::errc::invalid_argument)); + return It->second; + } + + /// Looks for a vertex with identifier I, returns 1 if one exists, and + /// 0 otherwise + size_type count(const VertexIdentifier &I) const { + return Vertices.count(I); + } + + /// Looks for an edge with Identifier I, returns 1 if one exists and 0 + /// otherwise + size_type count(const EdgeIdentifier &I) const { return Edges.count(I); } + + /// Inserts a vertex into the graph with Identifier Val.first, and + /// Attribute Val.second. + std::pair<VertexIterator, bool> + insert(const std::pair<VertexIdentifier, VertexAttribute> &Val) { + return Vertices.insert(Val); + } + + std::pair<VertexIterator, bool> + insert(std::pair<VertexIdentifier, VertexAttribute> &&Val) { + return Vertices.insert(std::move(Val)); + } + + /// Inserts an edge into the graph with Identifier Val.first, and + /// Attribute Val.second. If the key is already in the map, it returns false + /// and doesn't update the value. + std::pair<EdgeIterator, bool> + insert(const std::pair<EdgeIdentifier, EdgeAttribute> &Val) { + const auto &p = Edges.insert(Val); + if (p.second) { + const auto &EI = Val.first; + Vertices.FindAndConstruct(EI.first); + Vertices.FindAndConstruct(EI.second); + InNeighbors[EI.second].insert(EI.first); + OutNeighbors[EI.first].insert(EI.second); + }; + + return p; + } + + /// Inserts an edge into the graph with Identifier Val.first, and + /// Attribute Val.second. If the key is already in the map, it returns false + /// and doesn't update the value. + std::pair<EdgeIterator, bool> + insert(std::pair<EdgeIdentifier, EdgeAttribute> &&Val) { + auto EI = Val.first; + const auto &p = Edges.insert(std::move(Val)); + if (p.second) { + Vertices.FindAndConstruct(EI.first); + Vertices.FindAndConstruct(EI.second); + InNeighbors[EI.second].insert(EI.first); + OutNeighbors[EI.first].insert(EI.second); + }; + + return p; + } +}; +} +} +#endif diff --git a/include/llvm/XRay/InstrumentationMap.h b/include/llvm/XRay/InstrumentationMap.h new file mode 100644 index 000000000000..f7286c52ff42 --- /dev/null +++ b/include/llvm/XRay/InstrumentationMap.h @@ -0,0 +1,129 @@ +//===- InstrumentationMap.h - XRay Instrumentation Map ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the interface for extracting the instrumentation map from an +// XRay-instrumented binary. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_XRAY_INSTRUMENTATION_MAP_H +#define LLVM_XRAY_INSTRUMENTATION_MAP_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/YAMLTraits.h" +#include <cstdint> +#include <unordered_map> +#include <vector> + +namespace llvm { + +namespace xray { + +// Forward declare to make a friend. +class InstrumentationMap; + +/// Loads the instrumentation map from |Filename|. This auto-deduces the type of +/// the instrumentation map. +Expected<InstrumentationMap> loadInstrumentationMap(StringRef Filename); + +/// Represents an XRay instrumentation sled entry from an object file. +struct SledEntry { + /// Each entry here represents the kinds of supported instrumentation map + /// entries. + enum class FunctionKinds { ENTRY, EXIT, TAIL }; + + /// The address of the sled. + uint64_t Address; + + /// The address of the function. + uint64_t Function; + + /// The kind of sled. + FunctionKinds Kind; + + /// Whether the sled was annotated to always be instrumented. + bool AlwaysInstrument; +}; + +struct YAMLXRaySledEntry { + int32_t FuncId; + yaml::Hex64 Address; + yaml::Hex64 Function; + SledEntry::FunctionKinds Kind; + bool AlwaysInstrument; +}; + +/// The InstrumentationMap represents the computed function id's and indicated +/// function addresses from an object file (or a YAML file). This provides an +/// interface to just the mapping between the function id, and the function +/// address. +/// +/// We also provide raw access to the actual instrumentation map entries we find +/// associated with a particular object file. +/// +class InstrumentationMap { +public: + using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>; + using FunctionAddressReverseMap = std::unordered_map<uint64_t, int32_t>; + using SledContainer = std::vector<SledEntry>; + +private: + SledContainer Sleds; + FunctionAddressMap FunctionAddresses; + FunctionAddressReverseMap FunctionIds; + + friend Expected<InstrumentationMap> loadInstrumentationMap(StringRef); + +public: + /// Provides a raw accessor to the unordered map of function addresses. + const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; } + + /// Returns an XRay computed function id, provided a function address. + Optional<int32_t> getFunctionId(uint64_t Addr) const; + + /// Returns the function address for a function id. + Optional<uint64_t> getFunctionAddr(int32_t FuncId) const; + + /// Provide read-only access to the entries of the instrumentation map. + const SledContainer &sleds() const { return Sleds; }; +}; + +} // end namespace xray + +namespace yaml { + +template <> struct ScalarEnumerationTraits<xray::SledEntry::FunctionKinds> { + static void enumeration(IO &IO, xray::SledEntry::FunctionKinds &Kind) { + IO.enumCase(Kind, "function-enter", xray::SledEntry::FunctionKinds::ENTRY); + IO.enumCase(Kind, "function-exit", xray::SledEntry::FunctionKinds::EXIT); + IO.enumCase(Kind, "tail-exit", xray::SledEntry::FunctionKinds::TAIL); + } +}; + +template <> struct MappingTraits<xray::YAMLXRaySledEntry> { + static void mapping(IO &IO, xray::YAMLXRaySledEntry &Entry) { + IO.mapRequired("id", Entry.FuncId); + IO.mapRequired("address", Entry.Address); + IO.mapRequired("function", Entry.Function); + IO.mapRequired("kind", Entry.Kind); + IO.mapRequired("always-instrument", Entry.AlwaysInstrument); + } + + static constexpr bool flow = true; +}; + +} // end namespace yaml + +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(xray::YAMLXRaySledEntry) + +#endif // LLVM_XRAY_INSTRUMENTATION_MAP_H diff --git a/include/llvm/XRay/XRayRecord.h b/include/llvm/XRay/XRayRecord.h index a96846136ec3..68c91a40fed1 100644 --- a/include/llvm/XRay/XRayRecord.h +++ b/include/llvm/XRay/XRayRecord.h @@ -42,6 +42,11 @@ struct XRayFileHeader { /// counter (TSC) values. Useful for estimating the amount of time that /// elapsed between two TSCs on some platforms. uint64_t CycleFrequency = 0; + + // This is different depending on the type of xray record. The naive format + // stores a Wallclock timespec. FDR logging stores the size of a thread + // buffer. + char FreeFormData[16]; }; /// Determines the supported types of records that could be seen in XRay traces. @@ -54,8 +59,8 @@ struct XRayRecord { /// The type of record. uint16_t RecordType; - /// The CPU where the thread is running. We assume number of CPUs <= 256. - uint8_t CPU; + /// The CPU where the thread is running. We assume number of CPUs <= 65536. + uint16_t CPU; /// Identifies the type of record. RecordTypes Type; diff --git a/include/llvm/XRay/YAMLXRayRecord.h b/include/llvm/XRay/YAMLXRayRecord.h index f5836b392242..7e1a4112818e 100644 --- a/include/llvm/XRay/YAMLXRayRecord.h +++ b/include/llvm/XRay/YAMLXRayRecord.h @@ -31,7 +31,7 @@ struct YAMLXRayFileHeader { struct YAMLXRayRecord { uint16_t RecordType; - uint8_t CPU; + uint16_t CPU; RecordTypes Type; int32_t FuncId; std::string Function; diff --git a/include/llvm/module.modulemap b/include/llvm/module.modulemap index 29e6d66b27ff..59b1f1621039 100644 --- a/include/llvm/module.modulemap +++ b/include/llvm/module.modulemap @@ -276,6 +276,7 @@ module LLVM_Utils { textual header "Support/ELFRelocs/SystemZ.def" textual header "Support/ELFRelocs/x86_64.def" textual header "Support/ELFRelocs/WebAssembly.def" + textual header "Support/WasmRelocs/WebAssembly.def" } // This part of the module is usable from both C and C++ code. @@ -283,12 +284,12 @@ module LLVM_Utils { header "Support/ConvertUTF.h" export * } -} -module LLVM_CodeGen_MachineValueType { - requires cplusplus - header "CodeGen/MachineValueType.h" - export * + module LLVM_CodeGen_MachineValueType { + requires cplusplus + header "CodeGen/MachineValueType.h" + export * + } } // This is used for a $src == $build compilation. Otherwise we use |