diff options
Diffstat (limited to 'third_party/llvm-project/include/llvm/ADT')
41 files changed, 18863 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/ADT/APFloat.h b/third_party/llvm-project/include/llvm/ADT/APFloat.h new file mode 100644 index 000000000..1c4969733 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/APFloat.h @@ -0,0 +1,1290 @@ +//===- llvm/ADT/APFloat.h - Arbitrary Precision Floating Point ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief +/// This file declares a class to represent arbitrary precision floating point +/// values and provide a variety of arithmetic operations on them. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_APFLOAT_H +#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; +class APSInt; +class StringRef; +class APFloat; +class raw_ostream; + +template <typename T> class SmallVectorImpl; + +/// Enum that represents what fraction of the LSB truncated bits of an fp number +/// represent. +/// +/// This essentially combines the roles of guard and sticky bits. +enum lostFraction { // Example of truncated bits: + lfExactlyZero, // 000000 + lfLessThanHalf, // 0xxxxx x's not all zero + lfExactlyHalf, // 100000 + lfMoreThanHalf // 1xxxxx x's not all zero +}; + +/// A self-contained host- and target-independent arbitrary-precision +/// floating-point software implementation. +/// +/// APFloat uses bignum integer arithmetic as provided by static functions in +/// the APInt class. The library will work with bignum integers whose parts are +/// any unsigned type at least 16 bits wide, but 64 bits is recommended. +/// +/// Written for clarity rather than speed, in particular with a view to use in +/// the front-end of a cross compiler so that target arithmetic can be correctly +/// performed on the host. Performance should nonetheless be reasonable, +/// particularly for its intended use. It may be useful as a base +/// implementation for a run-time library during development of a faster +/// target-specific one. +/// +/// All 5 rounding modes in the IEEE-754R draft are handled correctly for all +/// implemented operations. Currently implemented operations are add, subtract, +/// multiply, divide, fused-multiply-add, conversion-to-float, +/// conversion-to-integer and conversion-from-integer. New rounding modes +/// (e.g. away from zero) can be added with three or four lines of code. +/// +/// Four formats are built-in: IEEE single precision, double precision, +/// quadruple precision, and x87 80-bit extended double (when operating with +/// full extended precision). Adding a new format that obeys IEEE semantics +/// only requires adding two lines of code: a declaration and definition of the +/// format. +/// +/// All operations return the status of that operation as an exception bit-mask, +/// so multiple operations can be done consecutively with their results or-ed +/// together. The returned status can be useful for compiler diagnostics; e.g., +/// inexact, underflow and overflow can be easily diagnosed on constant folding, +/// and compiler optimizers can determine what exceptions would be raised by +/// folding operations and optimize, or perhaps not optimize, accordingly. +/// +/// At present, underflow tininess is detected after rounding; it should be +/// straight forward to add support for the before-rounding case too. +/// +/// The library reads hexadecimal floating point numbers as per C99, and +/// correctly rounds if necessary according to the specified rounding mode. +/// Syntax is required to have been validated by the caller. It also converts +/// floating point numbers to hexadecimal text as per the C99 %a and %A +/// conversions. The output precision (or alternatively the natural minimal +/// precision) can be specified; if the requested precision is less than the +/// natural precision the output is correctly rounded for the specified rounding +/// mode. +/// +/// It also reads decimal floating point numbers and correctly rounds according +/// to the specified rounding mode. +/// +/// Conversion to decimal text is not currently implemented. +/// +/// Non-zero finite numbers are represented internally as a sign bit, a 16-bit +/// signed exponent, and the significand as an array of integer parts. After +/// normalization of a number of precision P the exponent is within the range of +/// the format, and if the number is not denormal the P-th bit of the +/// significand is set as an explicit integer bit. For denormals the most +/// significant bit is shifted right so that the exponent is maintained at the +/// format's minimum, so that the smallest denormal has just the least +/// significant bit of the significand set. The sign of zeroes and infinities +/// is significant; the exponent and significand of such numbers is not stored, +/// but has a known implicit (deterministic) value: 0 for the significands, 0 +/// for zero exponent, all 1 bits for infinity exponent. For NaNs the sign and +/// significand are deterministic, although not really meaningful, and preserved +/// in non-conversion operations. The exponent is implicitly all 1 bits. +/// +/// APFloat does not provide any exception handling beyond default exception +/// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause +/// by encoding Signaling NaNs with the first bit of its trailing significand as +/// 0. +/// +/// TODO +/// ==== +/// +/// Some features that may or may not be worth adding: +/// +/// Binary to decimal conversion (hard). +/// +/// Optional ability to detect underflow tininess before rounding. +/// +/// New formats: x87 in single and double precision mode (IEEE apart from +/// extended exponent range) (hard). +/// +/// New operations: sqrt, IEEE remainder, C90 fmod, nexttoward. +/// + +// This is the common type definitions shared by APFloat and its internal +// implementation classes. This struct should not define any non-static data +// members. +struct APFloatBase { + typedef APInt::WordType integerPart; + static const unsigned integerPartWidth = APInt::APINT_BITS_PER_WORD; + + /// A signed type to represent a floating point numbers unbiased exponent. + typedef signed short ExponentType; + + /// \name Floating Point Semantics. + /// @{ + enum Semantics { + S_IEEEhalf, + S_IEEEsingle, + S_IEEEdouble, + S_x87DoubleExtended, + S_IEEEquad, + S_PPCDoubleDouble + }; + + static const llvm::fltSemantics &EnumToSemantics(Semantics S); + static Semantics SemanticsToEnum(const llvm::fltSemantics &Sem); + + 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() LLVM_READNONE; + + /// @} + + /// IEEE-754R 5.11: Floating Point Comparison Relations. + enum cmpResult { + cmpLessThan, + cmpEqual, + cmpGreaterThan, + cmpUnordered + }; + + /// IEEE-754R 4.3: Rounding-direction attributes. + enum roundingMode { + rmNearestTiesToEven, + rmTowardPositive, + rmTowardNegative, + rmTowardZero, + rmNearestTiesToAway + }; + + /// IEEE-754R 7: Default exception handling. + /// + /// opUnderflow or opOverflow are always returned or-ed with opInexact. + /// + /// APFloat models this behavior specified by IEEE-754: + /// "For operations producing results in floating-point format, the default + /// result of an operation that signals the invalid operation exception + /// shall be a quiet NaN." + enum opStatus { + opOK = 0x00, + opInvalidOp = 0x01, + opDivByZero = 0x02, + opOverflow = 0x04, + opUnderflow = 0x08, + opInexact = 0x10 + }; + + /// Category of internally-represented number. + enum fltCategory { + fcInfinity, + fcNaN, + fcNormal, + fcZero + }; + + /// Convenience enum used to construct an uninitialized APFloat. + enum uninitializedTag { + uninitialized + }; + + /// Enumeration of \c ilogb error results. + enum IlogbErrorKinds { + IEK_Zero = INT_MIN + 1, + IEK_NaN = INT_MIN, + IEK_Inf = INT_MAX + }; + + static unsigned int semanticsPrecision(const fltSemantics &); + static ExponentType semanticsMinExponent(const fltSemantics &); + static ExponentType semanticsMaxExponent(const fltSemantics &); + static unsigned int semanticsSizeInBits(const fltSemantics &); + + /// Returns the size of the floating point number (in bits) in the given + /// semantics. + static unsigned getSizeInBits(const fltSemantics &Sem); +}; + +namespace detail { + +class IEEEFloat final : public APFloatBase { +public: + /// \name Constructors + /// @{ + + IEEEFloat(const fltSemantics &); // Default construct to 0.0 + IEEEFloat(const fltSemantics &, integerPart); + IEEEFloat(const fltSemantics &, uninitializedTag); + IEEEFloat(const fltSemantics &, const APInt &); + explicit IEEEFloat(double d); + explicit IEEEFloat(float f); + IEEEFloat(const IEEEFloat &); + IEEEFloat(IEEEFloat &&); + ~IEEEFloat(); + + /// @} + + /// Returns whether this instance allocated memory. + bool needsCleanup() const { return partCount() > 1; } + + /// \name Convenience "constructors" + /// @{ + + /// @} + + /// \name Arithmetic + /// @{ + + opStatus add(const IEEEFloat &, roundingMode); + opStatus subtract(const IEEEFloat &, roundingMode); + opStatus multiply(const IEEEFloat &, roundingMode); + opStatus divide(const IEEEFloat &, roundingMode); + /// IEEE remainder. + opStatus remainder(const IEEEFloat &); + /// C fmod, or llvm frem. + opStatus mod(const IEEEFloat &); + opStatus fusedMultiplyAdd(const IEEEFloat &, const IEEEFloat &, roundingMode); + opStatus roundToIntegral(roundingMode); + /// IEEE-754R 5.3.1: nextUp/nextDown. + opStatus next(bool nextDown); + + /// @} + + /// \name Sign operations. + /// @{ + + void changeSign(); + + /// @} + + /// \name Conversions + /// @{ + + opStatus convert(const fltSemantics &, roundingMode, bool *); + opStatus convertToInteger(MutableArrayRef<integerPart>, unsigned int, bool, + roundingMode, bool *) const; + opStatus convertFromAPInt(const APInt &, bool, roundingMode); + opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int, + bool, roundingMode); + opStatus convertFromZeroExtendedInteger(const integerPart *, unsigned int, + bool, roundingMode); + opStatus convertFromString(StringRef, roundingMode); + APInt bitcastToAPInt() const; + double convertToDouble() const; + float convertToFloat() const; + + /// @} + + /// The definition of equality is not straightforward for floating point, so + /// we won't use operator==. Use one of the following, or write whatever it + /// is you really mean. + bool operator==(const IEEEFloat &) const = delete; + + /// IEEE comparison with another floating point number (NaNs compare + /// unordered, 0==-0). + cmpResult compare(const IEEEFloat &) const; + + /// Bitwise comparison for equality (QNaNs compare equal, 0!=-0). + bool bitwiseIsEqual(const IEEEFloat &) const; + + /// Write out a hexadecimal representation of the floating point value to DST, + /// which must be of sufficient size, in the C99 form [-]0xh.hhhhp[+-]d. + /// Return the number of characters written, excluding the terminating NUL. + unsigned int convertToHexString(char *dst, unsigned int hexDigits, + bool upperCase, roundingMode) const; + + /// \name IEEE-754R 5.7.2 General operations. + /// @{ + + /// IEEE-754R isSignMinus: Returns true if and only if the current value is + /// negative. + /// + /// This applies to zeros and NaNs as well. + bool isNegative() const { return sign; } + + /// IEEE-754R isNormal: Returns true if and only if the current value is normal. + /// + /// This implies that the current value of the float is not zero, subnormal, + /// infinite, or NaN following the definition of normality from IEEE-754R. + bool isNormal() const { return !isDenormal() && isFiniteNonZero(); } + + /// Returns true if and only if the current value is zero, subnormal, or + /// normal. + /// + /// This means that the value is not infinite or NaN. + bool isFinite() const { return !isNaN() && !isInfinity(); } + + /// Returns true if and only if the float is plus or minus zero. + bool isZero() const { return category == fcZero; } + + /// IEEE-754R isSubnormal(): Returns true if and only if the float is a + /// denormal. + bool isDenormal() const; + + /// IEEE-754R isInfinite(): Returns true if and only if the float is infinity. + bool isInfinity() const { return category == fcInfinity; } + + /// Returns true if and only if the float is a quiet or signaling NaN. + bool isNaN() const { return category == fcNaN; } + + /// Returns true if and only if the float is a signaling NaN. + bool isSignaling() const; + + /// @} + + /// \name Simple Queries + /// @{ + + fltCategory getCategory() const { return category; } + const fltSemantics &getSemantics() const { return *semantics; } + bool isNonZero() const { return category != fcZero; } + bool isFiniteNonZero() const { return isFinite() && !isZero(); } + bool isPosZero() const { return isZero() && !isNegative(); } + bool isNegZero() const { return isZero() && isNegative(); } + + /// Returns true if and only if the number has the smallest possible non-zero + /// magnitude in the current semantics. + bool isSmallest() const; + + /// 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; + + /// @} + + IEEEFloat &operator=(const IEEEFloat &); + IEEEFloat &operator=(IEEEFloat &&); + + /// 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 + /// example, should negative and positive zero hash to different codes? Are + /// they equal or not? This hash value implementation specifically + /// emphasizes producing different codes for different inputs in order to + /// be used in canonicalization and memoization. As such, equality is + /// bitwiseIsEqual, and 0 != -0. + friend hash_code hash_value(const IEEEFloat &Arg); + + /// Converts this value into a decimal string. + /// + /// \param FormatPrecision The maximum number of digits of + /// precision to output. If there are fewer digits available, + /// zero padding will not be used unless the value is + /// integral and small enough to be expressed in + /// FormatPrecision digits. 0 means to use the natural + /// precision of the number. + /// \param FormatMaxPadding The maximum number of zeros to + /// consider inserting before falling back to scientific + /// notation. 0 means to always use scientific notation. + /// + /// \param TruncateZero Indicate whether to remove the trailing zero in + /// fraction part or not. Also setting this parameter to false forcing + /// producing of output more similar to default printf behavior. + /// Specifically the lower e is used as exponent delimiter and exponent + /// always contains no less than two digits. + /// + /// Number Precision MaxPadding Result + /// ------ --------- ---------- ------ + /// 1.01E+4 5 2 10100 + /// 1.01E+4 4 2 1.01E+4 + /// 1.01E+4 5 1 1.01E+4 + /// 1.01E-2 5 2 0.0101 + /// 1.01E-2 4 2 0.0101 + /// 1.01E-2 4 1 1.01E-2 + void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0, + unsigned FormatMaxPadding = 3, bool TruncateZero = true) const; + + /// If this value has an exact multiplicative inverse, store it in inv and + /// return true. + bool getExactInverse(APFloat *inv) const; + + /// 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: + /// + /// NaN -> \c IEK_NaN + /// 0 -> \c IEK_Zero + /// Inf -> \c IEK_Inf + /// + friend int ilogb(const IEEEFloat &Arg); + + /// Returns: X * 2^Exp for integral exponents. + friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode); + + friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode); + + /// \name Special value setters. + /// @{ + + void makeLargest(bool Neg = false); + void makeSmallest(bool Neg = false); + void makeNaN(bool SNaN = false, bool Neg = false, + const APInt *fill = nullptr); + void makeInf(bool Neg = false); + void makeZero(bool Neg = false); + void makeQuiet(); + + /// Returns the smallest (by magnitude) normalized finite number in the given + /// semantics. + /// + /// \param Negative - True iff the number should be negative + void makeSmallestNormalized(bool Negative = false); + + /// @} + + cmpResult compareAbsoluteValue(const IEEEFloat &) const; + +private: + /// \name Simple Queries + /// @{ + + integerPart *significandParts(); + const integerPart *significandParts() const; + unsigned int partCount() const; + + /// @} + + /// \name Significand operations. + /// @{ + + integerPart addSignificand(const IEEEFloat &); + integerPart subtractSignificand(const IEEEFloat &, integerPart); + lostFraction addOrSubtractSignificand(const IEEEFloat &, bool subtract); + lostFraction multiplySignificand(const IEEEFloat &, const IEEEFloat *); + lostFraction divideSignificand(const IEEEFloat &); + void incrementSignificand(); + void initialize(const fltSemantics *); + void shiftSignificandLeft(unsigned int); + lostFraction shiftSignificandRight(unsigned int); + unsigned int significandLSB() const; + unsigned int significandMSB() const; + void zeroSignificand(); + /// Return true if the significand excluding the integral bit is all ones. + bool isSignificandAllOnes() const; + /// Return true if the significand excluding the integral bit is all zeros. + bool isSignificandAllZeros() const; + + /// @} + + /// \name Arithmetic on special values. + /// @{ + + opStatus addOrSubtractSpecials(const IEEEFloat &, bool subtract); + opStatus divideSpecials(const IEEEFloat &); + opStatus multiplySpecials(const IEEEFloat &); + opStatus modSpecials(const IEEEFloat &); + + /// @} + + /// \name Miscellany + /// @{ + + bool convertFromStringSpecials(StringRef str); + opStatus normalize(roundingMode, lostFraction); + opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract); + opStatus handleOverflow(roundingMode); + bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const; + opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart>, + unsigned int, bool, roundingMode, + bool *) const; + opStatus convertFromUnsignedParts(const integerPart *, unsigned int, + roundingMode); + opStatus convertFromHexadecimalString(StringRef, roundingMode); + opStatus convertFromDecimalString(StringRef, roundingMode); + char *convertNormalToHexString(char *, unsigned int, bool, + roundingMode) const; + opStatus roundSignificandWithExponent(const integerPart *, unsigned int, int, + roundingMode); + + /// @} + + APInt convertHalfAPFloatToAPInt() const; + APInt convertFloatAPFloatToAPInt() const; + APInt convertDoubleAPFloatToAPInt() const; + APInt convertQuadrupleAPFloatToAPInt() const; + APInt convertF80LongDoubleAPFloatToAPInt() const; + APInt convertPPCDoubleDoubleAPFloatToAPInt() const; + void initFromAPInt(const fltSemantics *Sem, const APInt &api); + void initFromHalfAPInt(const APInt &api); + void initFromFloatAPInt(const APInt &api); + void initFromDoubleAPInt(const APInt &api); + void initFromQuadrupleAPInt(const APInt &api); + void initFromF80LongDoubleAPInt(const APInt &api); + void initFromPPCDoubleDoubleAPInt(const APInt &api); + + void assign(const IEEEFloat &); + void copySignificand(const IEEEFloat &); + void freeSignificand(); + + /// Note: this must be the first data member. + /// The semantics that this value obeys. + const fltSemantics *semantics; + + /// A binary fraction with an explicit integer bit. + /// + /// The significand must be at least one bit wider than the target precision. + union Significand { + integerPart part; + integerPart *parts; + } significand; + + /// The signed unbiased exponent of the value. + ExponentType exponent; + + /// What kind of floating point number this is. + /// + /// Only 2 bits are required, but VisualStudio incorrectly sign extends it. + /// Using the extra bit keeps it from failing under VisualStudio. + fltCategory category : 3; + + /// Sign bit of the number. + unsigned int sign : 1; +}; + +hash_code hash_value(const IEEEFloat &Arg); +int ilogb(const IEEEFloat &Arg); +IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode); +IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM); + +// This mode implements more precise float in terms of two APFloats. +// The interface and layout is designed for arbitray underlying semantics, +// though currently only PPCDoubleDouble semantics are supported, whose +// corresponding underlying semantics are IEEEdouble. +class DoubleAPFloat final : public APFloatBase { + // Note: this must be the first data member. + const fltSemantics *Semantics; + std::unique_ptr<APFloat[]> Floats; + + opStatus addImpl(const APFloat &a, const APFloat &aa, const APFloat &c, + const APFloat &cc, roundingMode RM); + + opStatus addWithSpecial(const DoubleAPFloat &LHS, const DoubleAPFloat &RHS, + DoubleAPFloat &Out, roundingMode RM); + +public: + DoubleAPFloat(const fltSemantics &S); + DoubleAPFloat(const fltSemantics &S, uninitializedTag); + DoubleAPFloat(const fltSemantics &S, integerPart); + DoubleAPFloat(const fltSemantics &S, const APInt &I); + DoubleAPFloat(const fltSemantics &S, APFloat &&First, APFloat &&Second); + DoubleAPFloat(const DoubleAPFloat &RHS); + DoubleAPFloat(DoubleAPFloat &&RHS); + + DoubleAPFloat &operator=(const DoubleAPFloat &RHS); + + DoubleAPFloat &operator=(DoubleAPFloat &&RHS) { + if (this != &RHS) { + this->~DoubleAPFloat(); + new (this) DoubleAPFloat(std::move(RHS)); + } + return *this; + } + + bool needsCleanup() const { return Floats != nullptr; } + + APFloat &getFirst() { return Floats[0]; } + const APFloat &getFirst() const { return Floats[0]; } + APFloat &getSecond() { return Floats[1]; } + const APFloat &getSecond() const { return Floats[1]; } + + 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; + + fltCategory getCategory() const; + 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, bool TruncateZero = true) 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 +// detail::IEEEFloat. +class APFloat : public APFloatBase { + typedef detail::IEEEFloat IEEEFloat; + typedef detail::DoubleAPFloat DoubleAPFloat; + + static_assert(std::is_standard_layout<IEEEFloat>::value, ""); + + union Storage { + const fltSemantics *semantics; + IEEEFloat IEEE; + DoubleAPFloat Double; + + explicit Storage(IEEEFloat F, const fltSemantics &S); + explicit Storage(DoubleAPFloat F, const fltSemantics &S) + : Double(std::move(F)) { + assert(&S == &PPCDoubleDouble()); + } + + template <typename... ArgTypes> + Storage(const fltSemantics &Semantics, ArgTypes &&... Args) { + if (usesLayout<IEEEFloat>(Semantics)) { + new (&IEEE) IEEEFloat(Semantics, std::forward<ArgTypes>(Args)...); + return; + } + if (usesLayout<DoubleAPFloat>(Semantics)) { + new (&Double) DoubleAPFloat(Semantics, std::forward<ArgTypes>(Args)...); + return; + } + llvm_unreachable("Unexpected semantics"); + } + + ~Storage() { + if (usesLayout<IEEEFloat>(*semantics)) { + IEEE.~IEEEFloat(); + return; + } + if (usesLayout<DoubleAPFloat>(*semantics)) { + Double.~DoubleAPFloat(); + return; + } + llvm_unreachable("Unexpected semantics"); + } + + Storage(const Storage &RHS) { + if (usesLayout<IEEEFloat>(*RHS.semantics)) { + new (this) IEEEFloat(RHS.IEEE); + return; + } + if (usesLayout<DoubleAPFloat>(*RHS.semantics)) { + new (this) DoubleAPFloat(RHS.Double); + return; + } + llvm_unreachable("Unexpected semantics"); + } + + Storage(Storage &&RHS) { + if (usesLayout<IEEEFloat>(*RHS.semantics)) { + new (this) IEEEFloat(std::move(RHS.IEEE)); + return; + } + if (usesLayout<DoubleAPFloat>(*RHS.semantics)) { + new (this) DoubleAPFloat(std::move(RHS.Double)); + return; + } + llvm_unreachable("Unexpected semantics"); + } + + Storage &operator=(const Storage &RHS) { + if (usesLayout<IEEEFloat>(*semantics) && + usesLayout<IEEEFloat>(*RHS.semantics)) { + IEEE = RHS.IEEE; + } else if (usesLayout<DoubleAPFloat>(*semantics) && + usesLayout<DoubleAPFloat>(*RHS.semantics)) { + Double = RHS.Double; + } else if (this != &RHS) { + this->~Storage(); + new (this) Storage(RHS); + } + return *this; + } + + Storage &operator=(Storage &&RHS) { + if (usesLayout<IEEEFloat>(*semantics) && + usesLayout<IEEEFloat>(*RHS.semantics)) { + IEEE = std::move(RHS.IEEE); + } else if (usesLayout<DoubleAPFloat>(*semantics) && + usesLayout<DoubleAPFloat>(*RHS.semantics)) { + Double = std::move(RHS.Double); + } else if (this != &RHS) { + this->~Storage(); + new (this) Storage(std::move(RHS)); + } + return *this; + } + } U; + + template <typename T> static bool usesLayout(const fltSemantics &Semantics) { + static_assert(std::is_same<T, IEEEFloat>::value || + std::is_same<T, DoubleAPFloat>::value, ""); + if (std::is_same<T, DoubleAPFloat>::value) { + return &Semantics == &PPCDoubleDouble(); + } + return &Semantics != &PPCDoubleDouble(); + } + + IEEEFloat &getIEEE() { + if (usesLayout<IEEEFloat>(*U.semantics)) + return U.IEEE; + if (usesLayout<DoubleAPFloat>(*U.semantics)) + return U.Double.getFirst().U.IEEE; + llvm_unreachable("Unexpected semantics"); + } + + const IEEEFloat &getIEEE() const { + if (usesLayout<IEEEFloat>(*U.semantics)) + return U.IEEE; + if (usesLayout<DoubleAPFloat>(*U.semantics)) + return U.Double.getFirst().U.IEEE; + llvm_unreachable("Unexpected semantics"); + } + + void makeZero(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeZero(Neg)); } + + void makeInf(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeInf(Neg)); } + + void makeNaN(bool SNaN, bool Neg, const APInt *fill) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeNaN(SNaN, Neg, fill)); + } + + void makeLargest(bool Neg) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeLargest(Neg)); + } + + void makeSmallest(bool Neg) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallest(Neg)); + } + + void makeSmallestNormalized(bool Neg) { + APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallestNormalized(Neg)); + } + + // FIXME: This is due to clang 3.3 (or older version) always checks for the + // default constructor in an array aggregate initialization, even if no + // elements in the array is default initialized. + APFloat() : U(IEEEdouble()) { + llvm_unreachable("This is a workaround for old clang."); + } + + explicit APFloat(IEEEFloat F, const fltSemantics &S) : U(std::move(F), S) {} + explicit APFloat(DoubleAPFloat F, const fltSemantics &S) + : U(std::move(F), S) {} + + cmpResult compareAbsoluteValue(const APFloat &RHS) const { + 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())) + return U.Double.compareAbsoluteValue(RHS.U.Double); + llvm_unreachable("Unexpected semantics"); + } + +public: + APFloat(const fltSemantics &Semantics) : U(Semantics) {} + APFloat(const fltSemantics &Semantics, StringRef S); + APFloat(const fltSemantics &Semantics, integerPart I) : U(Semantics, I) {} + // TODO: Remove this constructor. This isn't faster than the first one. + APFloat(const fltSemantics &Semantics, uninitializedTag) + : U(Semantics, uninitialized) {} + APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {} + explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {} + explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {} + APFloat(const APFloat &RHS) = default; + APFloat(APFloat &&RHS) = default; + + ~APFloat() = default; + + bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); } + + /// Factory for Positive and Negative Zero. + /// + /// \param Negative True iff the number should be negative. + static APFloat getZero(const fltSemantics &Sem, bool Negative = false) { + APFloat Val(Sem, uninitialized); + Val.makeZero(Negative); + return Val; + } + + /// Factory for Positive and Negative Infinity. + /// + /// \param Negative True iff the number should be negative. + static APFloat getInf(const fltSemantics &Sem, bool Negative = false) { + APFloat Val(Sem, uninitialized); + Val.makeInf(Negative); + return Val; + } + + /// Factory for NaN values. + /// + /// \param Negative - True iff the NaN generated should be negative. + /// \param payload - The unspecified fill bits for creating the NaN, 0 by + /// default. The value is truncated as necessary. + static APFloat getNaN(const fltSemantics &Sem, bool Negative = false, + uint64_t payload = 0) { + if (payload) { + APInt intPayload(64, payload); + return getQNaN(Sem, Negative, &intPayload); + } else { + return getQNaN(Sem, Negative, nullptr); + } + } + + /// Factory for QNaN values. + static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false, + const APInt *payload = nullptr) { + APFloat Val(Sem, uninitialized); + Val.makeNaN(false, Negative, payload); + return Val; + } + + /// Factory for SNaN values. + static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false, + const APInt *payload = nullptr) { + APFloat Val(Sem, uninitialized); + Val.makeNaN(true, Negative, payload); + return Val; + } + + /// Returns the largest finite number in the given semantics. + /// + /// \param Negative - True iff the number should be negative + static APFloat getLargest(const fltSemantics &Sem, bool Negative = false) { + APFloat Val(Sem, uninitialized); + Val.makeLargest(Negative); + return Val; + } + + /// Returns the smallest (by magnitude) finite number in the given semantics. + /// Might be denormalized, which implies a relative loss of precision. + /// + /// \param Negative - True iff the number should be negative + static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false) { + APFloat Val(Sem, uninitialized); + Val.makeSmallest(Negative); + return Val; + } + + /// Returns the smallest (by magnitude) normalized finite number in the given + /// semantics. + /// + /// \param Negative - True iff the number should be negative + static APFloat getSmallestNormalized(const fltSemantics &Sem, + bool Negative = false) { + APFloat Val(Sem, uninitialized); + Val.makeSmallestNormalized(Negative); + return Val; + } + + /// Returns a float which is bitcasted from an all one value int. + /// + /// \param BitWidth - Select float type + /// \param isIEEE - If 128 bit number, select between PPC and IEEE + static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false); + + /// 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())) + return U.Double.add(RHS.U.Double, RM); + 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())) + return U.Double.subtract(RHS.U.Double, RM); + llvm_unreachable("Unexpected semantics"); + } + opStatus multiply(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.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) { + 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) { + 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 fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, + roundingMode 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) { + 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)); + } + + /// Add two APFloats, rounding ties to the nearest even. + /// No error checking. + APFloat operator+(const APFloat &RHS) const { + 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 { + 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 { + 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 { + APFloat Result(*this); + (void)Result.divide(RHS, rmNearestTiesToEven); + return Result; + } + + 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) { + Value.copySign(Sign); + return Value; + } + + opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, + bool *losesInfo); + opStatus convertToInteger(MutableArrayRef<integerPart> Input, + unsigned int Width, bool IsSigned, roundingMode RM, + bool *IsExact) const { + APFLOAT_DISPATCH_ON_SEMANTICS( + convertToInteger(Input, Width, IsSigned, RM, IsExact)); + } + opStatus convertToInteger(APSInt &Result, roundingMode RM, + bool *IsExact) const; + opStatus convertFromAPInt(const APInt &Input, bool IsSigned, + roundingMode RM) { + APFLOAT_DISPATCH_ON_SEMANTICS(convertFromAPInt(Input, IsSigned, RM)); + } + opStatus convertFromSignExtendedInteger(const integerPart *Input, + unsigned int InputSize, bool IsSigned, + roundingMode RM) { + APFLOAT_DISPATCH_ON_SEMANTICS( + convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM)); + } + opStatus convertFromZeroExtendedInteger(const integerPart *Input, + unsigned int InputSize, bool IsSigned, + roundingMode RM) { + APFLOAT_DISPATCH_ON_SEMANTICS( + convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM)); + } + opStatus convertFromString(StringRef, roundingMode); + 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 { + 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 { + 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"); + } + + /// We don't rely on operator== working on double values, as + /// it returns true for things that are clearly not equal, like -0.0 and 0.0. + /// As such, this method can be used to do an exact bit-for-bit comparison of + /// two floating point values. + /// + /// We leave the version with the double argument here because it's just so + /// convenient to write "2.0" and the like. Without this function we'd + /// have to duplicate its logic everywhere it's called. + bool isExactlyValue(double V) const { + bool ignored; + APFloat Tmp(V); + Tmp.convert(getSemantics(), APFloat::rmNearestTiesToEven, &ignored); + return bitwiseIsEqual(Tmp); + } + + unsigned int convertToHexString(char *DST, unsigned int HexDigits, + bool UpperCase, roundingMode RM) const { + APFLOAT_DISPATCH_ON_SEMANTICS( + convertToHexString(DST, HexDigits, UpperCase, RM)); + } + + bool isZero() const { return getCategory() == fcZero; } + bool isInfinity() const { return getCategory() == fcInfinity; } + bool isNaN() const { return getCategory() == fcNaN; } + + bool isNegative() const { return getIEEE().isNegative(); } + bool isDenormal() const { APFLOAT_DISPATCH_ON_SEMANTICS(isDenormal()); } + bool isSignaling() const { return getIEEE().isSignaling(); } + + bool isNormal() const { return !isDenormal() && isFiniteNonZero(); } + bool isFinite() const { return !isNaN() && !isInfinity(); } + + fltCategory getCategory() const { return getIEEE().getCategory(); } + const fltSemantics &getSemantics() const { return *U.semantics; } + bool isNonZero() const { return !isZero(); } + bool isFiniteNonZero() const { return isFinite() && !isZero(); } + bool isPosZero() const { return isZero() && !isNegative(); } + bool isNegZero() const { return isZero() && isNegative(); } + 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, bool TruncateZero = true) const { + APFLOAT_DISPATCH_ON_SEMANTICS( + toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero)); + } + + void print(raw_ostream &) const; + void dump() const; + + bool getExactInverse(APFloat *inv) const { + APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv)); + } + + friend hash_code hash_value(const APFloat &Arg); + friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); } + friend APFloat scalbn(APFloat X, int Exp, roundingMode RM); + friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM); + friend IEEEFloat; + friend DoubleAPFloat; +}; + +/// See friend declarations above. +/// +/// These additional declarations are required in order to compile LLVM with IBM +/// xlC compiler. +hash_code hash_value(const APFloat &Arg); +inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) { + 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"); +} + +/// 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) { + 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"); +} +/// Returns the absolute value of the argument. +inline APFloat abs(APFloat X) { + X.clearSign(); + return X; +} + +/// 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 +inline APFloat minnum(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return B; + if (B.isNaN()) + return A; + return (B.compare(A) == APFloat::cmpLessThan) ? B : A; +} + +/// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if +/// both are not NaN. If either argument is a NaN, returns the other argument. +LLVM_READONLY +inline APFloat maxnum(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return B; + if (B.isNaN()) + return A; + return (A.compare(B) == APFloat::cmpLessThan) ? B : A; +} + +/// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2 +/// arguments, propagating NaNs and treating -0 as less than +0. +LLVM_READONLY +inline APFloat minimum(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return A; + if (B.isNaN()) + return B; + if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative())) + return A.isNegative() ? A : B; + return (B.compare(A) == APFloat::cmpLessThan) ? B : A; +} + +/// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2 +/// arguments, propagating NaNs and treating -0 as less than +0. +LLVM_READONLY +inline APFloat maximum(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return A; + if (B.isNaN()) + return B; + if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative())) + return A.isNegative() ? B : A; + return (A.compare(B) == APFloat::cmpLessThan) ? B : A; +} + +} // namespace llvm + +#undef APFLOAT_DISPATCH_ON_SEMANTICS +#endif // LLVM_ADT_APFLOAT_H diff --git a/third_party/llvm-project/include/llvm/ADT/APInt.h b/third_party/llvm-project/include/llvm/ADT/APInt.h new file mode 100644 index 000000000..60a0db7e9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/APInt.h @@ -0,0 +1,2258 @@ +//===-- llvm/ADT/APInt.h - For Arbitrary Precision Integer -----*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a class to represent arbitrary precision +/// integral constant values and operations on them. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_APINT_H +#define LLVM_ADT_APINT_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include <cassert> +#include <climits> +#include <cstring> +#include <string> + +namespace llvm { +class FoldingSetNodeID; +class StringRef; +class hash_code; +class raw_ostream; + +template <typename T> class SmallVectorImpl; +template <typename T> class ArrayRef; +template <typename T> class Optional; + +class APInt; + +inline APInt operator-(APInt); + +//===----------------------------------------------------------------------===// +// APInt Class +//===----------------------------------------------------------------------===// + +/// Class for arbitrary precision integers. +/// +/// APInt is a functional replacement for common case unsigned integer type like +/// "unsigned", "unsigned long" or "uint64_t", but also allows non-byte-width +/// integer sizes and large integer value types such as 3-bits, 15-bits, or more +/// than 64-bits of precision. APInt provides a variety of arithmetic operators +/// and methods to manipulate integer values of any bit-width. It supports both +/// the typical integer arithmetic and comparison operations as well as bitwise +/// manipulation. +/// +/// The class has several invariants worth noting: +/// * All bit, byte, and word positions are zero-based. +/// * Once the bit width is set, it doesn't change except by the Truncate, +/// SignExtend, or ZeroExtend operations. +/// * All binary operators must be on APInt instances of the same bit width. +/// Attempting to use these operators on instances with different bit +/// widths will yield an assertion. +/// * The value is stored canonically as an unsigned value. For operations +/// where it makes a difference, there are both signed and unsigned variants +/// of the operation. For example, sdiv and udiv. However, because the bit +/// widths must be the same, operations such as Mul and Add produce the same +/// results regardless of whether the values are interpreted as signed or +/// not. +/// * In general, the class tries to follow the style of computation that LLVM +/// uses in its IR. This simplifies its use for LLVM. +/// +class LLVM_NODISCARD 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 + }; + + enum class Rounding { + DOWN, + TOWARD_ZERO, + UP, + }; + + static const WordType WORDTYPE_MAX = ~WordType(0); + +private: + /// This union is used to store the integer value. When the + /// integer bit-width <= 64, it uses VAL, otherwise it uses pVal. + union { + uint64_t VAL; ///< Used to store the <= 64 bits integer value. + uint64_t *pVal; ///< Used to store the >64 bits integer value. + } U; + + unsigned BitWidth; ///< The number of bits in this APInt. + + friend struct DenseMapAPIntKeyInfo; + + friend class APSInt; + + /// Fast internal constructor + /// + /// 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) { + U.pVal = val; + } + + /// Determine if this APInt just has one word to store value. + /// + /// \returns true if the number of bits <= 64, false otherwise. + bool isSingleWord() const { return BitWidth <= APINT_BITS_PER_WORD; } + + /// Determine which word a bit is in. + /// + /// \returns the word position for the specified bit position. + static unsigned whichWord(unsigned bitPosition) { + return bitPosition / APINT_BITS_PER_WORD; + } + + /// Determine which bit in a word a bit is in. + /// + /// \returns the bit position in a word for the specified bit position + /// in the APInt. + static unsigned whichBit(unsigned bitPosition) { + return bitPosition % APINT_BITS_PER_WORD; + } + + /// Get a single bit mask. + /// + /// \returns a uint64_t with only bit at "whichBit(bitPosition)" set + /// This method generates and returns a uint64_t (word) mask for a single + /// bit at a specific bit position. This is used to mask the bit in the + /// corresponding word. + static uint64_t maskBit(unsigned bitPosition) { + return 1ULL << whichBit(bitPosition); + } + + /// Clear unused high order bits + /// + /// This method is used internally to clear the top "N" bits in the high order + /// word that are not used by the APInt. This is needed after the most + /// significant word is assigned a value to ensure that those bits are + /// zero'd out. + APInt &clearUnusedBits() { + // Compute how many bits are used in the final word + unsigned WordBits = ((BitWidth-1) % APINT_BITS_PER_WORD) + 1; + + // Mask out the high bits. + uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - WordBits); + if (isSingleWord()) + U.VAL &= mask; + else + U.pVal[getNumWords() - 1] &= mask; + return *this; + } + + /// Get the word corresponding to a bit position + /// \returns the corresponding word for the specified bit position. + uint64_t getWord(unsigned bitPosition) const { + return isSingleWord() ? U.VAL : U.pVal[whichWord(bitPosition)]; + } + + /// Utility method to change the bit width of this APInt to new bit width, + /// allocating and/or deallocating as necessary. There is no guarantee on the + /// value of any bits upon return. Caller should populate the bits after. + void reallocate(unsigned NewBitWidth); + + /// Convert a char array into an APInt + /// + /// \param radix 2, 8, 10, 16, or 36 + /// Converts a string into a number. The string must be non-empty + /// and well-formed as a number of the given base. The bit-width + /// must be sufficient to hold the result. + /// + /// This is used by the constructors that take string arguments. + /// + /// StringRef::getAsInteger is superficially similar but (1) does + /// not assume that the string is well-formed and (2) grows the + /// result to hold the input. + void fromString(unsigned numBits, StringRef str, uint8_t radix); + + /// An internal division function for dividing APInts. + /// + /// This is used by the toString method to divide by the radix. It simply + /// provides a more convenient form of divide for internal use since KnuthDiv + /// has specific constraints on its inputs. If those constraints are not met + /// then it provides a simpler form of divide. + static void divide(const WordType *LHS, unsigned lhsWords, + const WordType *RHS, unsigned rhsWords, WordType *Quotient, + WordType *Remainder); + + /// out-of-line slow case for inline constructor + void initSlowCase(uint64_t val, bool isSigned); + + /// shared code between two array constructors + void initFromArray(ArrayRef<uint64_t> array); + + /// out-of-line slow case for inline copy constructor + void initSlowCase(const APInt &that); + + /// out-of-line slow case for shl + void shlSlowCase(unsigned ShiftAmt); + + /// out-of-line slow case for lshr. + void lshrSlowCase(unsigned ShiftAmt); + + /// out-of-line slow case for ashr. + void ashrSlowCase(unsigned ShiftAmt); + + /// out-of-line slow case for operator= + void AssignSlowCase(const APInt &RHS); + + /// out-of-line slow case for operator== + bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY; + + /// out-of-line slow case for countLeadingZeros + unsigned countLeadingZerosSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for countLeadingOnes. + unsigned countLeadingOnesSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for countTrailingZeros. + unsigned countTrailingZerosSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for countTrailingOnes + unsigned countTrailingOnesSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for countPopulation + unsigned countPopulationSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for intersects. + bool intersectsSlowCase(const APInt &RHS) const LLVM_READONLY; + + /// out-of-line slow case for isSubsetOf. + bool isSubsetOfSlowCase(const APInt &RHS) 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&=. + void AndAssignSlowCase(const APInt& RHS); + + /// out-of-line slow case for operator|=. + void OrAssignSlowCase(const APInt& RHS); + + /// out-of-line slow case for operator^=. + void XorAssignSlowCase(const APInt& RHS); + + /// Unsigned comparison. Returns -1, 0, or 1 if this APInt is less than, equal + /// to, or greater than RHS. + int compare(const APInt &RHS) const LLVM_READONLY; + + /// Signed comparison. Returns -1, 0, or 1 if this APInt is less than, equal + /// to, or greater than RHS. + int compareSigned(const APInt &RHS) const LLVM_READONLY; + +public: + /// \name Constructors + /// @{ + + /// Create a new APInt of numBits width, initialized as val. + /// + /// If isSigned is true then val is treated as if it were a signed value + /// (i.e. as an int64_t) and the appropriate sign extension to the bit width + /// will be done. Otherwise, no sign extension occurs (high order bits beyond + /// the range of val are zero filled). + /// + /// \param numBits the bit width of the constructed APInt + /// \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) { + assert(BitWidth && "bitwidth too small"); + if (isSingleWord()) { + U.VAL = val; + clearUnusedBits(); + } else { + initSlowCase(val, isSigned); + } + } + + /// Construct an APInt of numBits width, initialized as bigVal[]. + /// + /// Note that bigVal.size() can be smaller or larger than the corresponding + /// bit width but any extraneous bits will be dropped. + /// + /// \param numBits the bit width of the constructed APInt + /// \param bigVal a sequence of words to form the initial value of the APInt + APInt(unsigned numBits, ArrayRef<uint64_t> bigVal); + + /// Equivalent to APInt(numBits, ArrayRef<uint64_t>(bigVal, numWords)), but + /// deprecated because this constructor is prone to ambiguity with the + /// APInt(unsigned, uint64_t, bool) constructor. + /// + /// If this overload is ever deleted, care should be taken to prevent calls + /// from being incorrectly captured by the APInt(unsigned, uint64_t, bool) + /// constructor. + APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[]); + + /// Construct an APInt from a string representation. + /// + /// This constructor interprets the string \p str in the given radix. The + /// interpretation stops when the first character that is not suitable for the + /// radix is encountered, or the end of the string. Acceptable radix values + /// are 2, 8, 10, 16, and 36. It is an error for the value implied by the + /// string to require more bits than numBits. + /// + /// \param numBits the bit width of the constructed APInt + /// \param str the string to be interpreted + /// \param radix the radix to use for the conversion + APInt(unsigned numBits, StringRef str, uint8_t radix); + + /// Simply makes *this a copy of that. + /// Copy Constructor. + APInt(const APInt &that) : BitWidth(that.BitWidth) { + if (isSingleWord()) + U.VAL = that.U.VAL; + else + initSlowCase(that); + } + + /// Move Constructor. + APInt(APInt &&that) : BitWidth(that.BitWidth) { + memcpy(&U, &that.U, sizeof(U)); + that.BitWidth = 0; + } + + /// Destructor. + ~APInt() { + if (needsCleanup()) + delete[] U.pVal; + } + + /// Default constructor that creates an uninteresting APInt + /// representing a 1-bit zero value. + /// + /// This is useful for object deserialization (pair this with the static + /// method Read). + explicit APInt() : BitWidth(1) { U.VAL = 0; } + + /// Returns whether this instance allocated memory. + bool needsCleanup() const { return !isSingleWord(); } + + /// Used to insert APInt objects, or objects that contain APInt objects, into + /// FoldingSets. + void Profile(FoldingSetNodeID &id) const; + + /// @} + /// \name Value Tests + /// @{ + + /// Determine sign of this APInt. + /// + /// This tests the high bit of this APInt to determine if it is set. + /// + /// \returns true if this APInt is negative, false otherwise + bool isNegative() const { return (*this)[BitWidth - 1]; } + + /// Determine if this APInt Value is non-negative (>= 0) + /// + /// This tests the high bit of the APInt to determine if it is unset. + bool isNonNegative() const { return !isNegative(); } + + /// Determine if sign bit of this APInt is set. + /// + /// This tests the high bit of this APInt to determine if it is set. + /// + /// \returns true if this APInt has its sign bit set, false otherwise. + bool isSignBitSet() const { return (*this)[BitWidth-1]; } + + /// Determine if sign bit of this APInt is clear. + /// + /// This tests the high bit of this APInt to determine if it is clear. + /// + /// \returns true if this APInt has its sign bit clear, false otherwise. + bool isSignBitClear() const { return !isSignBitSet(); } + + /// Determine if this APInt Value is positive. + /// + /// This tests if the value of this APInt is positive (> 0). Note + /// that 0 is not a positive value. + /// + /// \returns true if this APInt is positive. + bool isStrictlyPositive() const { return isNonNegative() && !isNullValue(); } + + /// Determine if all bits are set + /// + /// This checks to see if the value has all bits of the APInt are set or not. + bool isAllOnesValue() const { + if (isSingleWord()) + return U.VAL == WORDTYPE_MAX >> (APINT_BITS_PER_WORD - BitWidth); + return countTrailingOnesSlowCase() == BitWidth; + } + + /// Determine if all bits are clear + /// + /// This checks to see if the value has all bits of the APInt are clear or + /// not. + bool isNullValue() const { return !*this; } + + /// Determine if this is a value of 1. + /// + /// This checks to see if the value of this APInt is one. + bool isOneValue() const { + if (isSingleWord()) + return U.VAL == 1; + return countLeadingZerosSlowCase() == BitWidth - 1; + } + + /// Determine if this is the largest unsigned value. + /// + /// This checks to see if the value of this APInt is the maximum unsigned + /// value for the APInt's bit width. + bool isMaxValue() const { return isAllOnesValue(); } + + /// Determine if this is the largest signed value. + /// + /// This checks to see if the value of this APInt is the maximum signed + /// value for the APInt's bit width. + bool isMaxSignedValue() const { + if (isSingleWord()) + return U.VAL == ((WordType(1) << (BitWidth - 1)) - 1); + return !isNegative() && countTrailingOnesSlowCase() == BitWidth - 1; + } + + /// Determine if this is the smallest unsigned value. + /// + /// This checks to see if the value of this APInt is the minimum unsigned + /// value for the APInt's bit width. + bool isMinValue() const { return isNullValue(); } + + /// Determine if this is the smallest signed value. + /// + /// This checks to see if the value of this APInt is the minimum signed + /// value for the APInt's bit width. + bool isMinSignedValue() const { + if (isSingleWord()) + return U.VAL == (WordType(1) << (BitWidth - 1)); + return isNegative() && countTrailingZerosSlowCase() == BitWidth - 1; + } + + /// Check if this APInt has an N-bits unsigned integer value. + bool isIntN(unsigned N) const { + assert(N && "N == 0 ???"); + return getActiveBits() <= N; + } + + /// Check if this APInt has an N-bits signed integer value. + bool isSignedIntN(unsigned N) const { + assert(N && "N == 0 ???"); + return getMinSignedBits() <= N; + } + + /// Check if this APInt's value is a power of two greater than zero. + /// + /// \returns true if the argument APInt value is a power of two > 0. + bool isPowerOf2() const { + if (isSingleWord()) + return isPowerOf2_64(U.VAL); + return countPopulationSlowCase() == 1; + } + + /// Check if the APInt's value is returned by getSignMask. + /// + /// \returns true if this is the value returned by getSignMask. + bool isSignMask() const { return isMinSignedValue(); } + + /// Convert APInt to a boolean value. + /// + /// This converts the APInt to a boolean value as a test against zero. + bool getBoolValue() const { return !!*this; } + + /// 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 = UINT64_MAX) const { + return ugt(Limit) ? Limit : getZExtValue(); + } + + /// Check if the APInt consists of a repeated bit pattern. + /// + /// e.g. 0x01010101 satisfies isSplat(8). + /// \param SplatSizeInBits The size of the pattern in bits. Must divide bit + /// 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 U.VAL == (WORDTYPE_MAX >> (APINT_BITS_PER_WORD - numBits)); + unsigned Ones = countTrailingOnesSlowCase(); + return (numBits == Ones) && + ((Ones + countLeadingZerosSlowCase()) == 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(U.VAL); + unsigned Ones = countTrailingOnesSlowCase(); + return (Ones > 0) && ((Ones + countLeadingZerosSlowCase()) == BitWidth); + } + + /// Return true if this APInt value contains a sequence of ones with + /// the remainder zero. + bool isShiftedMask() const { + if (isSingleWord()) + return isShiftedMask_64(U.VAL); + unsigned Ones = countPopulationSlowCase(); + unsigned LeadZ = countLeadingZerosSlowCase(); + return (Ones + LeadZ + countTrailingZeros()) == BitWidth; + } + + /// @} + /// \name Value Generators + /// @{ + + /// Gets maximum unsigned value of APInt for specific bit width. + static APInt getMaxValue(unsigned numBits) { + return getAllOnesValue(numBits); + } + + /// Gets maximum signed value of APInt for a specific bit width. + static APInt getSignedMaxValue(unsigned numBits) { + APInt API = getAllOnesValue(numBits); + API.clearBit(numBits - 1); + return API; + } + + /// Gets minimum unsigned value of APInt for a specific bit width. + static APInt getMinValue(unsigned numBits) { return APInt(numBits, 0); } + + /// Gets minimum signed value of APInt for a specific bit width. + static APInt getSignedMinValue(unsigned numBits) { + APInt API(numBits, 0); + API.setBit(numBits - 1); + return API; + } + + /// Get the SignMask for a specific bit width. + /// + /// This is just a wrapper function of getSignedMinValue(), and it helps code + /// readability when we want to get a SignMask. + static APInt getSignMask(unsigned BitWidth) { + return getSignedMinValue(BitWidth); + } + + /// Get the all-ones value. + /// + /// \returns the all-ones value for an APInt of the specified bit-width. + static APInt getAllOnesValue(unsigned numBits) { + return APInt(numBits, WORDTYPE_MAX, true); + } + + /// Get the '0' value. + /// + /// \returns the '0' value for an APInt of the specified bit-width. + static APInt getNullValue(unsigned numBits) { return APInt(numBits, 0); } + + /// Compute an APInt containing numBits highbits from this APInt. + /// + /// Get an APInt with the same BitWidth as this APInt, just zero mask + /// the low bits and right shift to the least significant bit. + /// + /// \returns the high "numBits" bits of this APInt. + APInt getHiBits(unsigned numBits) const; + + /// Compute an APInt containing numBits lowbits from this APInt. + /// + /// Get an APInt with the same BitWidth as this APInt, just zero mask + /// the high bits. + /// + /// \returns the low "numBits" bits of this APInt. + APInt getLoBits(unsigned numBits) const; + + /// Return an APInt with exactly one bit set in the result. + static APInt getOneBitSet(unsigned numBits, unsigned BitNo) { + APInt Res(numBits, 0); + Res.setBit(BitNo); + return Res; + } + + /// Get a value with a block of bits set. + /// + /// Constructs an APInt value that has a contiguous range of bits set. The + /// bits from loBit (inclusive) to hiBit (exclusive) will be set. All other + /// bits will be zero. For example, with parameters(32, 0, 16) you would get + /// 0x0000FFFF. If hiBit is less than loBit then the set bits "wrap". For + /// example, with parameters (32, 28, 4), you would get 0xF000000F. + /// + /// \param numBits the intended bit width of the result + /// \param loBit the index of the lowest bit set. + /// \param hiBit the index of the highest bit set. + /// + /// \returns An APInt value with the requested bits set. + static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit) { + APInt Res(numBits, 0); + Res.setBits(loBit, hiBit); + return Res; + } + + /// 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; + } + + /// Get a value with high bits set + /// + /// Constructs an APInt value that has the top hiBitsSet bits set. + /// + /// \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) { + APInt Res(numBits, 0); + Res.setHighBits(hiBitsSet); + return Res; + } + + /// Get a value with low bits set + /// + /// Constructs an APInt value that has the bottom loBitsSet bits set. + /// + /// \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) { + APInt Res(numBits, 0); + Res.setLowBits(loBitsSet); + return Res; + } + + /// Return a value containing V broadcasted over NewLen bits. + static APInt getSplat(unsigned NewLen, const APInt &V); + + /// Determine if two APInts have the same value, after zero-extending + /// one of them (if needed!) to ensure that the bit-widths match. + static bool isSameValue(const APInt &I1, const APInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth()) + return I1 == I2; + + if (I1.getBitWidth() > I2.getBitWidth()) + return I1 == I2.zext(I1.getBitWidth()); + + return I1.zext(I2.getBitWidth()) == I2; + } + + /// Overload to compute a hash_code for an APInt value. + friend hash_code hash_value(const APInt &Arg); + + /// This function returns a pointer to the internal storage of the APInt. + /// This is useful for writing out the APInt in binary form without any + /// conversions. + const uint64_t *getRawData() const { + if (isSingleWord()) + return &U.VAL; + return &U.pVal[0]; + } + + /// @} + /// \name Unary Operators + /// @{ + + /// Postfix increment operator. + /// + /// Increments *this by 1. + /// + /// \returns a new APInt value representing the original value of *this. + const APInt operator++(int) { + APInt API(*this); + ++(*this); + return API; + } + + /// Prefix increment operator. + /// + /// \returns *this incremented by one + APInt &operator++(); + + /// Postfix decrement operator. + /// + /// Decrements *this by 1. + /// + /// \returns a new APInt value representing the original value of *this. + const APInt operator--(int) { + APInt API(*this); + --(*this); + return API; + } + + /// Prefix decrement operator. + /// + /// \returns *this decremented by one. + APInt &operator--(); + + /// Logical negation operator. + /// + /// Performs logical negation operation on this APInt. + /// + /// \returns true if *this is zero, false otherwise. + bool operator!() const { + if (isSingleWord()) + return U.VAL == 0; + return countLeadingZerosSlowCase() == BitWidth; + } + + /// @} + /// \name Assignment Operators + /// @{ + + /// Copy assignment operator. + /// + /// \returns *this after assignment of RHS. + APInt &operator=(const APInt &RHS) { + // If the bitwidths are the same, we can avoid mucking with memory + if (isSingleWord() && RHS.isSingleWord()) { + U.VAL = RHS.U.VAL; + BitWidth = RHS.BitWidth; + return clearUnusedBits(); + } + + AssignSlowCase(RHS); + return *this; + } + + /// Move assignment operator. + APInt &operator=(APInt &&that) { +#ifdef _MSC_VER + // The MSVC std::shuffle implementation still does self-assignment. + if (this == &that) + return *this; +#endif + assert(this != &that && "Self-move not supported"); + if (!isSingleWord()) + delete[] U.pVal; + + // Use memcpy so that type based alias analysis sees both VAL and pVal + // as modified. + memcpy(&U, &that.U, sizeof(U)); + + BitWidth = that.BitWidth; + that.BitWidth = 0; + + return *this; + } + + /// Assignment operator. + /// + /// The RHS value is assigned to *this. If the significant bits in RHS exceed + /// the bit width, the excess bits are truncated. If the bit width is larger + /// 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) { + if (isSingleWord()) { + U.VAL = RHS; + clearUnusedBits(); + } else { + U.pVal[0] = RHS; + memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); + } + return *this; + } + + /// Bitwise AND assignment operator. + /// + /// Performs a bitwise AND operation on this APInt and RHS. The result is + /// assigned to *this. + /// + /// \returns *this after ANDing with RHS. + APInt &operator&=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + U.VAL &= RHS.U.VAL; + else + AndAssignSlowCase(RHS); + return *this; + } + + /// 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()) { + U.VAL &= RHS; + return *this; + } + U.pVal[0] &= RHS; + memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); + return *this; + } + + /// Bitwise OR assignment operator. + /// + /// Performs a bitwise OR operation on this APInt and RHS. The result is + /// assigned *this; + /// + /// \returns *this after ORing with RHS. + APInt &operator|=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + U.VAL |= RHS.U.VAL; + else + OrAssignSlowCase(RHS); + return *this; + } + + /// Bitwise OR assignment operator. + /// + /// Performs a bitwise OR 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()) { + U.VAL |= RHS; + clearUnusedBits(); + } else { + U.pVal[0] |= RHS; + } + return *this; + } + + /// Bitwise XOR assignment operator. + /// + /// Performs a bitwise XOR operation on this APInt and RHS. The result is + /// assigned to *this. + /// + /// \returns *this after XORing with RHS. + APInt &operator^=(const APInt &RHS) { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + U.VAL ^= RHS.U.VAL; + else + XorAssignSlowCase(RHS); + return *this; + } + + /// 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()) { + U.VAL ^= RHS; + clearUnusedBits(); + } else { + U.pVal[0] ^= RHS; + } + return *this; + } + + /// Multiplication assignment operator. + /// + /// Multiplies this APInt by RHS and assigns the result to *this. + /// + /// \returns *this + APInt &operator*=(const APInt &RHS); + APInt &operator*=(uint64_t RHS); + + /// Addition assignment operator. + /// + /// Adds RHS to *this and assigns the result to *this. + /// + /// \returns *this + APInt &operator+=(const APInt &RHS); + APInt &operator+=(uint64_t RHS); + + /// Subtraction assignment operator. + /// + /// Subtracts RHS from *this and assigns the result to *this. + /// + /// \returns *this + APInt &operator-=(const APInt &RHS); + APInt &operator-=(uint64_t RHS); + + /// Left-shift assignment function. + /// + /// Shifts *this left by shiftAmt and assigns the result to *this. + /// + /// \returns *this after shifting left by ShiftAmt + APInt &operator<<=(unsigned ShiftAmt) { + assert(ShiftAmt <= BitWidth && "Invalid shift amount"); + if (isSingleWord()) { + if (ShiftAmt == BitWidth) + U.VAL = 0; + else + U.VAL <<= ShiftAmt; + return clearUnusedBits(); + } + shlSlowCase(ShiftAmt); + return *this; + } + + /// Left-shift assignment function. + /// + /// Shifts *this left by shiftAmt and assigns the result to *this. + /// + /// \returns *this after shifting left by ShiftAmt + APInt &operator<<=(const APInt &ShiftAmt); + + /// @} + /// \name Binary Operators + /// @{ + + /// Multiplication operator. + /// + /// Multiplies this APInt by RHS and returns the result. + APInt operator*(const APInt &RHS) const; + + /// Left logical shift operator. + /// + /// Shifts this APInt left by \p Bits and returns the result. + APInt operator<<(unsigned Bits) const { return shl(Bits); } + + /// Left logical shift operator. + /// + /// Shifts this APInt left by \p Bits and returns the result. + APInt operator<<(const APInt &Bits) const { return shl(Bits); } + + /// Arithmetic right-shift function. + /// + /// Arithmetic right-shift this APInt by shiftAmt. + APInt ashr(unsigned ShiftAmt) const { + APInt R(*this); + R.ashrInPlace(ShiftAmt); + return R; + } + + /// Arithmetic right-shift this APInt by ShiftAmt in place. + void ashrInPlace(unsigned ShiftAmt) { + assert(ShiftAmt <= BitWidth && "Invalid shift amount"); + if (isSingleWord()) { + int64_t SExtVAL = SignExtend64(U.VAL, BitWidth); + if (ShiftAmt == BitWidth) + U.VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit. + else + U.VAL = SExtVAL >> ShiftAmt; + clearUnusedBits(); + return; + } + ashrSlowCase(ShiftAmt); + } + + /// Logical right-shift function. + /// + /// Logical right-shift this APInt by shiftAmt. + 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) { + assert(ShiftAmt <= BitWidth && "Invalid shift amount"); + if (isSingleWord()) { + if (ShiftAmt == BitWidth) + U.VAL = 0; + else + U.VAL >>= ShiftAmt; + return; + } + lshrSlowCase(ShiftAmt); + } + + /// Left-shift function. + /// + /// Left-shift this APInt by shiftAmt. + APInt shl(unsigned shiftAmt) const { + APInt R(*this); + R <<= shiftAmt; + return R; + } + + /// Rotate left by rotateAmt. + APInt rotl(unsigned rotateAmt) const; + + /// Rotate right by rotateAmt. + APInt rotr(unsigned rotateAmt) const; + + /// Arithmetic right-shift function. + /// + /// Arithmetic right-shift this APInt by shiftAmt. + APInt ashr(const APInt &ShiftAmt) const { + APInt R(*this); + R.ashrInPlace(ShiftAmt); + return R; + } + + /// Arithmetic right-shift this APInt by shiftAmt in place. + void ashrInPlace(const APInt &shiftAmt); + + /// Logical right-shift function. + /// + /// Logical right-shift this APInt by shiftAmt. + APInt lshr(const APInt &ShiftAmt) const { + APInt R(*this); + R.lshrInPlace(ShiftAmt); + return R; + } + + /// Logical right-shift this APInt by ShiftAmt in place. + void lshrInPlace(const APInt &ShiftAmt); + + /// Left-shift function. + /// + /// Left-shift this APInt by shiftAmt. + APInt shl(const APInt &ShiftAmt) const { + APInt R(*this); + R <<= ShiftAmt; + return R; + } + + /// Rotate left by rotateAmt. + APInt rotl(const APInt &rotateAmt) const; + + /// Rotate right by rotateAmt. + APInt rotr(const APInt &rotateAmt) const; + + /// Unsigned division operation. + /// + /// Perform an unsigned divide operation on this APInt by RHS. Both this and + /// RHS are treated as unsigned quantities for purposes of this division. + /// + /// \returns a new APInt value containing the division result, rounded towards + /// zero. + APInt udiv(const APInt &RHS) const; + APInt udiv(uint64_t RHS) const; + + /// Signed division function for APInt. + /// + /// Signed divide this APInt by APInt RHS. + /// + /// The result is rounded towards zero. + APInt sdiv(const APInt &RHS) const; + APInt sdiv(int64_t RHS) const; + + /// Unsigned remainder operation. + /// + /// Perform an unsigned remainder operation on this APInt with RHS being the + /// divisor. Both this and RHS are treated as unsigned quantities for purposes + /// of this operation. Note that this is a true remainder operation and not a + /// modulo operation because the sign follows the sign of the dividend which + /// is *this. + /// + /// \returns a new APInt value containing the remainder result + APInt urem(const APInt &RHS) const; + uint64_t urem(uint64_t RHS) const; + + /// Function for signed remainder operation. + /// + /// Signed remainder operation on APInt. + APInt srem(const APInt &RHS) const; + int64_t srem(int64_t RHS) const; + + /// Dual division/remainder interface. + /// + /// Sometimes it is convenient to divide two APInt values and obtain both the + /// quotient and remainder. This function does both operations in the same + /// computation making it a little more efficient. The pair of input arguments + /// may overlap with the pair of output arguments. It is safe to call + /// udivrem(X, Y, X, Y), for example. + static void udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, + APInt &Remainder); + static void udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient, + uint64_t &Remainder); + + static void sdivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, + APInt &Remainder); + static void sdivrem(const APInt &LHS, int64_t RHS, APInt &Quotient, + int64_t &Remainder); + + // Operations that return overflow indicators. + APInt sadd_ov(const APInt &RHS, bool &Overflow) const; + APInt uadd_ov(const APInt &RHS, bool &Overflow) const; + APInt ssub_ov(const APInt &RHS, bool &Overflow) const; + APInt usub_ov(const APInt &RHS, bool &Overflow) const; + APInt sdiv_ov(const APInt &RHS, bool &Overflow) const; + APInt smul_ov(const APInt &RHS, bool &Overflow) const; + APInt umul_ov(const APInt &RHS, bool &Overflow) const; + APInt sshl_ov(const APInt &Amt, bool &Overflow) const; + APInt ushl_ov(const APInt &Amt, bool &Overflow) const; + + // Operations that saturate + APInt sadd_sat(const APInt &RHS) const; + APInt uadd_sat(const APInt &RHS) const; + APInt ssub_sat(const APInt &RHS) const; + APInt usub_sat(const APInt &RHS) const; + APInt smul_sat(const APInt &RHS) const; + APInt umul_sat(const APInt &RHS) const; + APInt sshl_sat(const APInt &RHS) const; + APInt ushl_sat(const APInt &RHS) const; + + /// Array-indexing support. + /// + /// \returns the bit value at bitPosition + bool operator[](unsigned bitPosition) const { + assert(bitPosition < getBitWidth() && "Bit position out of bounds!"); + return (maskBit(bitPosition) & getWord(bitPosition)) != 0; + } + + /// @} + /// \name Comparison Operators + /// @{ + + /// Equality operator. + /// + /// Compares this APInt with RHS for the validity of the equality + /// relationship. + bool operator==(const APInt &RHS) const { + assert(BitWidth == RHS.BitWidth && "Comparison requires equal bit widths"); + if (isSingleWord()) + return U.VAL == RHS.U.VAL; + return EqualSlowCase(RHS); + } + + /// Equality operator. + /// + /// Compares this APInt with a uint64_t for the validity of the equality + /// relationship. + /// + /// \returns true if *this == Val + bool operator==(uint64_t Val) const { + return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() == Val; + } + + /// Equality comparison. + /// + /// Compares this APInt with RHS for the validity of the equality + /// relationship. + /// + /// \returns true if *this == Val + bool eq(const APInt &RHS) const { return (*this) == RHS; } + + /// Inequality operator. + /// + /// Compares this APInt with RHS for the validity of the inequality + /// relationship. + /// + /// \returns true if *this != Val + bool operator!=(const APInt &RHS) const { return !((*this) == RHS); } + + /// Inequality operator. + /// + /// Compares this APInt with a uint64_t for the validity of the inequality + /// relationship. + /// + /// \returns true if *this != Val + bool operator!=(uint64_t Val) const { return !((*this) == Val); } + + /// Inequality comparison + /// + /// Compares this APInt with RHS for the validity of the inequality + /// relationship. + /// + /// \returns true if *this != Val + bool ne(const APInt &RHS) const { return !((*this) == RHS); } + + /// Unsigned less than comparison + /// + /// Regards both *this and RHS as unsigned quantities and compares them for + /// the validity of the less-than relationship. + /// + /// \returns true if *this < RHS when both are considered unsigned. + bool ult(const APInt &RHS) const { return compare(RHS) < 0; } + + /// Unsigned less than comparison + /// + /// Regards both *this as an unsigned quantity and compares it with RHS for + /// the validity of the less-than relationship. + /// + /// \returns true if *this < RHS when considered unsigned. + bool ult(uint64_t RHS) const { + // Only need to check active bits if not a single word. + return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() < RHS; + } + + /// Signed less than comparison + /// + /// Regards both *this and RHS as signed quantities and compares them for + /// validity of the less-than relationship. + /// + /// \returns true if *this < RHS when both are considered signed. + bool slt(const APInt &RHS) const { return compareSigned(RHS) < 0; } + + /// Signed less than comparison + /// + /// Regards both *this as a signed quantity and compares it with RHS for + /// the validity of the less-than relationship. + /// + /// \returns true if *this < RHS when considered signed. + bool slt(int64_t RHS) const { + return (!isSingleWord() && getMinSignedBits() > 64) ? isNegative() + : getSExtValue() < RHS; + } + + /// Unsigned less or equal comparison + /// + /// Regards both *this and RHS as unsigned quantities and compares them for + /// validity of the less-or-equal relationship. + /// + /// \returns true if *this <= RHS when both are considered unsigned. + bool ule(const APInt &RHS) const { return compare(RHS) <= 0; } + + /// Unsigned less or equal comparison + /// + /// Regards both *this as an unsigned quantity and compares it with RHS for + /// the validity of the less-or-equal relationship. + /// + /// \returns true if *this <= RHS when considered unsigned. + bool ule(uint64_t RHS) const { return !ugt(RHS); } + + /// Signed less or equal comparison + /// + /// Regards both *this and RHS as signed quantities and compares them for + /// validity of the less-or-equal relationship. + /// + /// \returns true if *this <= RHS when both are considered signed. + bool sle(const APInt &RHS) const { return compareSigned(RHS) <= 0; } + + /// Signed less or equal comparison + /// + /// Regards both *this as a signed quantity and compares it with RHS for the + /// validity of the less-or-equal relationship. + /// + /// \returns true if *this <= RHS when considered signed. + bool sle(uint64_t RHS) const { return !sgt(RHS); } + + /// Unsigned greater than comparison + /// + /// Regards both *this and RHS as unsigned quantities and compares them for + /// the validity of the greater-than relationship. + /// + /// \returns true if *this > RHS when both are considered unsigned. + bool ugt(const APInt &RHS) const { return !ule(RHS); } + + /// Unsigned greater than comparison + /// + /// Regards both *this as an unsigned quantity and compares it with RHS for + /// the validity of the greater-than relationship. + /// + /// \returns true if *this > RHS when considered unsigned. + bool ugt(uint64_t RHS) const { + // Only need to check active bits if not a single word. + return (!isSingleWord() && getActiveBits() > 64) || getZExtValue() > RHS; + } + + /// Signed greater than comparison + /// + /// Regards both *this and RHS as signed quantities and compares them for the + /// validity of the greater-than relationship. + /// + /// \returns true if *this > RHS when both are considered signed. + bool sgt(const APInt &RHS) const { return !sle(RHS); } + + /// Signed greater than comparison + /// + /// Regards both *this as a signed quantity and compares it with RHS for + /// the validity of the greater-than relationship. + /// + /// \returns true if *this > RHS when considered signed. + bool sgt(int64_t RHS) const { + return (!isSingleWord() && getMinSignedBits() > 64) ? !isNegative() + : getSExtValue() > RHS; + } + + /// Unsigned greater or equal comparison + /// + /// Regards both *this and RHS as unsigned quantities and compares them for + /// validity of the greater-or-equal relationship. + /// + /// \returns true if *this >= RHS when both are considered unsigned. + bool uge(const APInt &RHS) const { return !ult(RHS); } + + /// Unsigned greater or equal comparison + /// + /// Regards both *this as an unsigned quantity and compares it with RHS for + /// the validity of the greater-or-equal relationship. + /// + /// \returns true if *this >= RHS when considered unsigned. + bool uge(uint64_t RHS) const { return !ult(RHS); } + + /// Signed greater or equal comparison + /// + /// Regards both *this and RHS as signed quantities and compares them for + /// validity of the greater-or-equal relationship. + /// + /// \returns true if *this >= RHS when both are considered signed. + bool sge(const APInt &RHS) const { return !slt(RHS); } + + /// Signed greater or equal comparison + /// + /// Regards both *this as a signed quantity and compares it with RHS for + /// the validity of the greater-or-equal relationship. + /// + /// \returns true if *this >= RHS when considered signed. + bool sge(int64_t RHS) const { return !slt(RHS); } + + /// 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 { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + return (U.VAL & RHS.U.VAL) != 0; + return intersectsSlowCase(RHS); + } + + /// This operation checks that all bits set in this APInt are also set in RHS. + bool isSubsetOf(const APInt &RHS) const { + assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); + if (isSingleWord()) + return (U.VAL & ~RHS.U.VAL) == 0; + return isSubsetOfSlowCase(RHS); + } + + /// @} + /// \name Resizing Operators + /// @{ + + /// Truncate to new width. + /// + /// Truncate the APInt to a specified width. It is an error to specify a width + /// that is greater than or equal to the current width. + APInt trunc(unsigned width) const; + + /// Truncate to new width with unsigned saturation. + /// + /// If the APInt, treated as unsigned integer, can be losslessly truncated to + /// the new bitwidth, then return truncated APInt. Else, return max value. + APInt truncUSat(unsigned width) const; + + /// Truncate to new width with signed saturation. + /// + /// If this APInt, treated as signed integer, can be losslessly truncated to + /// the new bitwidth, then return truncated APInt. Else, return either + /// signed min value if the APInt was negative, or signed max value. + APInt truncSSat(unsigned width) const; + + /// Sign extend to a new width. + /// + /// This operation sign extends the APInt to a new width. If the high order + /// bit is set, the fill on the left will be done with 1 bits, otherwise zero. + /// It is an error to specify a width that is less than or equal to the + /// current width. + APInt sext(unsigned width) const; + + /// Zero extend to a new width. + /// + /// This operation zero extends the APInt to a new width. The high order bits + /// are filled with 0 bits. It is an error to specify a width that is less + /// than or equal to the current width. + APInt zext(unsigned width) const; + + /// Sign extend or truncate to width + /// + /// Make this APInt have the bit width given by \p width. The value is sign + /// extended, truncated, or left alone to make it that width. + APInt sextOrTrunc(unsigned width) const; + + /// Zero extend or truncate to width + /// + /// Make this APInt have the bit width given by \p width. The value is zero + /// extended, truncated, or left alone to make it that width. + APInt zextOrTrunc(unsigned width) const; + + /// Sign extend or truncate to width + /// + /// Make this APInt have the bit width given by \p width. The value is sign + /// extended, or left alone to make it that width. + APInt sextOrSelf(unsigned width) const; + + /// Zero extend or truncate to width + /// + /// Make this APInt have the bit width given by \p width. The value is zero + /// extended, or left alone to make it that width. + APInt zextOrSelf(unsigned width) const; + + /// @} + /// \name Bit Manipulation Operators + /// @{ + + /// Set every bit to 1. + void setAllBits() { + if (isSingleWord()) + U.VAL = WORDTYPE_MAX; + else + // Set all the bits in all the words. + memset(U.pVal, -1, getNumWords() * APINT_WORD_SIZE); + // Clear the unused ones + clearUnusedBits(); + } + + /// Set a given bit to 1. + /// + /// Set the given bit to 1 whose position is given as "bitPosition". + void setBit(unsigned BitPosition) { + assert(BitPosition < BitWidth && "BitPosition out of range"); + WordType Mask = maskBit(BitPosition); + if (isSingleWord()) + U.VAL |= Mask; + else + U.pVal[whichWord(BitPosition)] |= Mask; + } + + /// 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"); + assert(loBit <= hiBit && "loBit greater than hiBit"); + if (loBit == hiBit) + return; + if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) { + uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit)); + mask <<= loBit; + if (isSingleWord()) + U.VAL |= mask; + else + U.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); + } + + /// Set every bit to 0. + void clearAllBits() { + if (isSingleWord()) + U.VAL = 0; + else + memset(U.pVal, 0, getNumWords() * APINT_WORD_SIZE); + } + + /// Set a given bit to 0. + /// + /// Set the given bit to 0 whose position is given as "bitPosition". + void clearBit(unsigned BitPosition) { + assert(BitPosition < BitWidth && "BitPosition out of range"); + WordType Mask = ~maskBit(BitPosition); + if (isSingleWord()) + U.VAL &= Mask; + else + U.pVal[whichWord(BitPosition)] &= Mask; + } + + /// Set bottom loBits bits to 0. + void clearLowBits(unsigned loBits) { + assert(loBits <= BitWidth && "More bits than bitwidth"); + APInt Keep = getHighBitsSet(BitWidth, BitWidth - loBits); + *this &= Keep; + } + + /// Set the sign bit to 0. + void clearSignBit() { + clearBit(BitWidth - 1); + } + + /// Toggle every bit to its opposite value. + void flipAllBits() { + if (isSingleWord()) { + U.VAL ^= WORDTYPE_MAX; + clearUnusedBits(); + } else { + flipAllBitsSlowCase(); + } + } + + /// Toggles a given bit to its opposite value. + /// + /// Toggle a given bit to its opposite value whose position is given + /// as "bitPosition". + void flipBit(unsigned bitPosition); + + /// Negate this APInt in place. + void negate() { + flipAllBits(); + ++(*this); + } + + /// Insert the bits from a smaller APInt starting at bitPosition. + void insertBits(const APInt &SubBits, unsigned bitPosition); + void insertBits(uint64_t SubBits, unsigned bitPosition, unsigned numBits); + + /// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits). + APInt extractBits(unsigned numBits, unsigned bitPosition) const; + uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const; + + /// @} + /// \name Value Characterization Functions + /// @{ + + /// Return the number of bits in the APInt. + unsigned getBitWidth() const { return BitWidth; } + + /// Get the number of words. + /// + /// Here one word's bitwidth equals to that of uint64_t. + /// + /// \returns the number of words to hold the integer value of this APInt. + unsigned getNumWords() const { return getNumWords(BitWidth); } + + /// Get the number of words. + /// + /// *NOTE* Here one word's bitwidth equals to that of uint64_t. + /// + /// \returns the number of words to hold the integer value with a given bit + /// width. + static unsigned getNumWords(unsigned BitWidth) { + return ((uint64_t)BitWidth + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD; + } + + /// Compute the number of active bits in the value + /// + /// This function returns the number of active bits which is defined as the + /// bit width minus the number of leading zeros. This is used in several + /// computations to see how "wide" the value is. + unsigned getActiveBits() const { return BitWidth - countLeadingZeros(); } + + /// Compute the number of active words in the value of this APInt. + /// + /// This is used in conjunction with getActiveData to extract the raw value of + /// the APInt. + unsigned getActiveWords() const { + unsigned numActiveBits = getActiveBits(); + return numActiveBits ? whichWord(numActiveBits - 1) + 1 : 1; + } + + /// Get the minimum bit size for this signed APInt + /// + /// Computes the minimum bit width for this APInt while considering it to be a + /// signed (and probably negative) value. If the value is not negative, this + /// function returns the same value as getActiveBits()+1. Otherwise, it + /// returns the smallest bit width that will retain the negative value. For + /// example, -1 can be written as 0b1 or 0xFFFFFFFFFF. 0b1 is shorter and so + /// for -1, this function will always return 1. + unsigned getMinSignedBits() const { + if (isNegative()) + return BitWidth - countLeadingOnes() + 1; + return getActiveBits() + 1; + } + + /// Get zero extended value + /// + /// This method attempts to return the value of this APInt as a zero extended + /// uint64_t. The bitwidth must be <= 64 or the value must fit within a + /// uint64_t. Otherwise an assertion will result. + uint64_t getZExtValue() const { + if (isSingleWord()) + return U.VAL; + assert(getActiveBits() <= 64 && "Too many bits for uint64_t"); + return U.pVal[0]; + } + + /// Get sign extended value + /// + /// This method attempts to return the value of this APInt as a sign extended + /// int64_t. The bit width must be <= 64 or the value must fit within an + /// int64_t. Otherwise an assertion will result. + int64_t getSExtValue() const { + if (isSingleWord()) + return SignExtend64(U.VAL, BitWidth); + assert(getMinSignedBits() <= 64 && "Too many bits for int64_t"); + return int64_t(U.pVal[0]); + } + + /// Get bits required for string value. + /// + /// This method determines how many bits are required to hold the APInt + /// equivalent of the string given by \p str. + static unsigned getBitsNeeded(StringRef str, uint8_t radix); + + /// The APInt version of the countLeadingZeros functions in + /// MathExtras.h. + /// + /// It counts the number of zeros from the most significant bit to the first + /// one bit. + /// + /// \returns BitWidth if the value is zero, otherwise returns the number of + /// zeros from the most significant bit to the first one bits. + unsigned countLeadingZeros() const { + if (isSingleWord()) { + unsigned unusedBits = APINT_BITS_PER_WORD - BitWidth; + return llvm::countLeadingZeros(U.VAL) - unusedBits; + } + return countLeadingZerosSlowCase(); + } + + /// Count the number of leading one bits. + /// + /// This function is an APInt version of the countLeadingOnes + /// functions in MathExtras.h. It counts the number of ones from the most + /// significant bit to the first zero bit. + /// + /// \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 { + if (isSingleWord()) + return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth)); + return countLeadingOnesSlowCase(); + } + + /// Computes the number of leading bits of this APInt that are equal to its + /// sign bit. + unsigned getNumSignBits() const { + return isNegative() ? countLeadingOnes() : countLeadingZeros(); + } + + /// Count the number of trailing zero bits. + /// + /// This function is an APInt version of the countTrailingZeros + /// functions in MathExtras.h. It counts the number of zeros from the least + /// significant bit to the first set bit. + /// + /// \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 { + if (isSingleWord()) + return std::min(unsigned(llvm::countTrailingZeros(U.VAL)), BitWidth); + return countTrailingZerosSlowCase(); + } + + /// Count the number of trailing one bits. + /// + /// This function is an APInt version of the countTrailingOnes + /// functions in MathExtras.h. It counts the number of ones from the least + /// significant bit to the first zero bit. + /// + /// \returns BitWidth if the value is all ones, otherwise returns the number + /// of ones from the least significant bit to the first zero bit. + unsigned countTrailingOnes() const { + if (isSingleWord()) + return llvm::countTrailingOnes(U.VAL); + return countTrailingOnesSlowCase(); + } + + /// Count the number of bits set. + /// + /// This function is an APInt version of the countPopulation functions + /// in MathExtras.h. It counts the number of 1 bits in the APInt value. + /// + /// \returns 0 if the value is zero, otherwise returns the number of set bits. + unsigned countPopulation() const { + if (isSingleWord()) + return llvm::countPopulation(U.VAL); + return countPopulationSlowCase(); + } + + /// @} + /// \name Conversion Functions + /// @{ + void print(raw_ostream &OS, bool isSigned) const; + + /// Converts an APInt to a string and append it to Str. Str is commonly a + /// SmallString. + void toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed, + bool formatAsCLiteral = false) const; + + /// Considers the APInt to be unsigned and converts it into a string in the + /// radix given. The radix can be 2, 8, 10 16, or 36. + void toStringUnsigned(SmallVectorImpl<char> &Str, unsigned Radix = 10) const { + toString(Str, Radix, false, false); + } + + /// Considers the APInt to be signed and converts it into a string in the + /// radix given. The radix can be 2, 8, 10, 16, or 36. + void toStringSigned(SmallVectorImpl<char> &Str, unsigned Radix = 10) const { + toString(Str, Radix, true, false); + } + + /// Return the APInt as a std::string. + /// + /// Note that this is an inefficient method. It is better to pass in a + /// SmallVector/SmallString to the methods above to avoid thrashing the heap + /// for the string. + std::string toString(unsigned Radix, bool Signed) const; + + /// \returns a byte-swapped representation of this APInt Value. + APInt byteSwap() const; + + /// \returns the value with the bit representation reversed of this APInt + /// Value. + APInt reverseBits() const; + + /// Converts this APInt to a double value. + double roundToDouble(bool isSigned) const; + + /// Converts this unsigned APInt to a double value. + double roundToDouble() const { return roundToDouble(false); } + + /// Converts this signed APInt to a double value. + double signedRoundToDouble() const { return roundToDouble(true); } + + /// Converts APInt bits to a double + /// + /// The conversion does not do a translation from integer to double, it just + /// re-interprets the bits as a double. Note that it is valid to do this on + /// any bit width. Exactly 64 bits will be translated. + double bitsToDouble() const { + return BitsToDouble(getWord(0)); + } + + /// Converts APInt bits to a float + /// + /// The conversion does not do a translation from integer to float, it just + /// re-interprets the bits as a float. Note that it is valid to do this on + /// any bit width. Exactly 32 bits will be translated. + float bitsToFloat() const { + return BitsToFloat(static_cast<uint32_t>(getWord(0))); + } + + /// Converts a double to APInt bits. + /// + /// The conversion does not do a translation from double to integer, it just + /// re-interprets the bits of the double. + static APInt doubleToBits(double V) { + return APInt(sizeof(double) * CHAR_BIT, DoubleToBits(V)); + } + + /// Converts a float to APInt bits. + /// + /// The conversion does not do a translation from float to integer, it just + /// re-interprets the bits of the float. + static APInt floatToBits(float V) { + return APInt(sizeof(float) * CHAR_BIT, FloatToBits(V)); + } + + /// @} + /// \name Mathematics Operations + /// @{ + + /// \returns the floor log base 2 of this APInt. + unsigned logBase2() const { return getActiveBits() - 1; } + + /// \returns the ceil log base 2 of this APInt. + unsigned ceilLogBase2() const { + APInt temp(*this); + --temp; + return temp.getActiveBits(); + } + + /// \returns the nearest log base 2 of this APInt. Ties round up. + /// + /// NOTE: When we have a BitWidth of 1, we define: + /// + /// log2(0) = UINT32_MAX + /// log2(1) = 0 + /// + /// to get around any mathematical concerns resulting from + /// referencing 2 in a space where 2 does no exist. + unsigned nearestLogBase2() const { + // Special case when we have a bitwidth of 1. If VAL is 1, then we + // get 0. If VAL is 0, we get WORDTYPE_MAX which gets truncated to + // UINT32_MAX. + if (BitWidth == 1) + return U.VAL - 1; + + // Handle the zero case. + if (isNullValue()) + return UINT32_MAX; + + // The non-zero case is handled by computing: + // + // nearestLogBase2(x) = logBase2(x) + x[logBase2(x)-1]. + // + // where x[i] is referring to the value of the ith bit of x. + unsigned lg = logBase2(); + return lg + unsigned((*this)[lg - 1]); + } + + /// \returns the log base 2 of this APInt if its an exact power of two, -1 + /// otherwise + int32_t exactLogBase2() const { + if (!isPowerOf2()) + return -1; + return logBase2(); + } + + /// Compute the square root + APInt sqrt() const; + + /// Get the absolute value; + /// + /// If *this is < 0 then return -(*this), otherwise *this; + APInt abs() const { + if (isNegative()) + return -(*this); + return *this; + } + + /// \returns the multiplicative inverse for a given modulo. + APInt multiplicativeInverse(const APInt &modulo) const; + + /// @} + /// \name Support for division by constant + /// @{ + + /// Calculate the magic number for signed division by a constant. + struct ms; + ms magic() const; + + /// Calculate the magic number for unsigned division by a constant. + struct mu; + mu magicu(unsigned LeadingZeros = 0) const; + + /// @} + /// \name Building-block Operations for APInt and APFloat + /// @{ + + // These building block operations operate on a representation of arbitrary + // precision, two's-complement, bignum integer values. They should be + // sufficient to implement APInt and APFloat bignum requirements. Inputs are + // generally a pointer to the base of an array of integer parts, representing + // an unsigned bignum, and a count of how many parts there are. + + /// Sets the least significant part of a bignum to the input value, and zeroes + /// out higher parts. + static void tcSet(WordType *, WordType, unsigned); + + /// Assign one bignum to another. + static void tcAssign(WordType *, const WordType *, unsigned); + + /// Returns true if a bignum is zero, false otherwise. + static bool tcIsZero(const WordType *, unsigned); + + /// Extract the given bit of a bignum; returns 0 or 1. Zero-based. + 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(WordType *, unsigned dstCount, + const WordType *, unsigned srcBits, + unsigned srcLSB); + + /// Set the given bit of a bignum. Zero-based. + static void tcSetBit(WordType *, unsigned bit); + + /// Clear the given bit of a bignum. Zero-based. + 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 tcLSB(const WordType *, unsigned n); + static unsigned tcMSB(const WordType *parts, unsigned n); + + /// Negate a bignum in-place. + static void tcNegate(WordType *, unsigned); + + /// DST += RHS + CARRY where CARRY is zero or one. Returns the carry flag. + 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 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 + /// + /// Requires 0 <= DSTPARTS <= SRCPARTS + 1. If DST overlaps SRC they must + /// start at the same point, i.e. DST == SRC. + /// + /// If DSTPARTS == SRC_PARTS + 1 no overflow occurs and zero is returned. + /// 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(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(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. + static void 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 + /// REMAINDER to the remainder, return zero. i.e. + /// + /// OLD_LHS = RHS * LHS + REMAINDER + /// + /// 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(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(WordType *, unsigned Words, unsigned Count); + + /// Shift a bignum right Count bits. Shifted in bits are zero. There are no + /// restrictions on Count. + static void tcShiftRight(WordType *, unsigned Words, unsigned Count); + + /// The obvious AND, OR and XOR and complement operations. + 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 WordType *, const WordType *, unsigned); + + /// Increment a bignum in-place. Return the carry flag. + static WordType tcIncrement(WordType *dst, unsigned parts) { + return tcAddPart(dst, 1, parts); + } + + /// Decrement a bignum in-place. Return the borrow flag. + static WordType tcDecrement(WordType *dst, unsigned parts) { + return tcSubtractPart(dst, 1, parts); + } + + /// Set the least significant BITS and clear the rest. + static void tcSetLeastSignificantBits(WordType *, unsigned, unsigned bits); + + /// debug method + void dump() const; + + /// @} +}; + +/// Magic data for optimising signed division by a constant. +struct APInt::ms { + APInt m; ///< magic number + unsigned s; ///< shift amount +}; + +/// Magic data for optimising unsigned division by a constant. +struct APInt::mu { + APInt m; ///< magic number + bool a; ///< add indicator + unsigned s; ///< shift amount +}; + +inline bool operator==(uint64_t V1, const APInt &V2) { return V2 == V1; } + +inline bool operator!=(uint64_t V1, const APInt &V2) { return V2 != V1; } + +/// 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; +} + +inline APInt operator-(APInt v) { + v.negate(); + 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.negate(); + 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.negate(); + b += LHS; + return 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; +} + + +namespace APIntOps { + +/// Determine the smaller of two APInts considered to be signed. +inline const APInt &smin(const APInt &A, const APInt &B) { + return A.slt(B) ? A : B; +} + +/// Determine the larger of two APInts considered to be signed. +inline const APInt &smax(const APInt &A, const APInt &B) { + return A.sgt(B) ? A : B; +} + +/// Determine the smaller of two APInts considered to be signed. +inline const APInt &umin(const APInt &A, const APInt &B) { + return A.ult(B) ? A : B; +} + +/// Determine the larger of two APInts considered to be unsigned. +inline const APInt &umax(const APInt &A, const APInt &B) { + return A.ugt(B) ? A : B; +} + +/// Compute GCD of two unsigned APInt values. +/// +/// This function returns the greatest common divisor of the two APInt values +/// using Stein's algorithm. +/// +/// \returns the greatest common divisor of A and B. +APInt GreatestCommonDivisor(APInt A, APInt B); + +/// Converts the given APInt to a double value. +/// +/// Treats the APInt as an unsigned value for conversion purposes. +inline double RoundAPIntToDouble(const APInt &APIVal) { + return APIVal.roundToDouble(); +} + +/// Converts the given APInt to a double value. +/// +/// Treats the APInt as a signed value for conversion purposes. +inline double RoundSignedAPIntToDouble(const APInt &APIVal) { + return APIVal.signedRoundToDouble(); +} + +/// Converts the given APInt to a float vlalue. +inline float RoundAPIntToFloat(const APInt &APIVal) { + return float(RoundAPIntToDouble(APIVal)); +} + +/// Converts the given APInt to a float value. +/// +/// Treats the APInt as a signed value for conversion purposes. +inline float RoundSignedAPIntToFloat(const APInt &APIVal) { + return float(APIVal.signedRoundToDouble()); +} + +/// Converts the given double value into a APInt. +/// +/// This function convert a double value to an APInt value. +APInt RoundDoubleToAPInt(double Double, unsigned width); + +/// Converts a float value into a APInt. +/// +/// Converts a float value into an APInt value. +inline APInt RoundFloatToAPInt(float Float, unsigned width) { + return RoundDoubleToAPInt(double(Float), width); +} + +/// Return A unsign-divided by B, rounded by the given rounding mode. +APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM); + +/// Return A sign-divided by B, rounded by the given rounding mode. +APInt RoundingSDiv(const APInt &A, const APInt &B, APInt::Rounding RM); + +/// Let q(n) = An^2 + Bn + C, and BW = bit width of the value range +/// (e.g. 32 for i32). +/// This function finds the smallest number n, such that +/// (a) n >= 0 and q(n) = 0, or +/// (b) n >= 1 and q(n-1) and q(n), when evaluated in the set of all +/// integers, belong to two different intervals [Rk, Rk+R), +/// where R = 2^BW, and k is an integer. +/// The idea here is to find when q(n) "overflows" 2^BW, while at the +/// same time "allowing" subtraction. In unsigned modulo arithmetic a +/// subtraction (treated as addition of negated numbers) would always +/// count as an overflow, but here we want to allow values to decrease +/// and increase as long as they are within the same interval. +/// Specifically, adding of two negative numbers should not cause an +/// overflow (as long as the magnitude does not exceed the bit width). +/// On the other hand, given a positive number, adding a negative +/// number to it can give a negative result, which would cause the +/// value to go from [-2^BW, 0) to [0, 2^BW). In that sense, zero is +/// treated as a special case of an overflow. +/// +/// This function returns None if after finding k that minimizes the +/// positive solution to q(n) = kR, both solutions are contained between +/// two consecutive integers. +/// +/// There are cases where q(n) > T, and q(n+1) < T (assuming evaluation +/// in arithmetic modulo 2^BW, and treating the values as signed) by the +/// virtue of *signed* overflow. This function will *not* find such an n, +/// however it may find a value of n satisfying the inequalities due to +/// an *unsigned* overflow (if the values are treated as unsigned). +/// To find a solution for a signed overflow, treat it as a problem of +/// finding an unsigned overflow with a range with of BW-1. +/// +/// The returned value may have a different bit width from the input +/// coefficients. +Optional<APInt> SolveQuadraticEquationWrap(APInt A, APInt B, APInt C, + unsigned RangeWidth); + +/// Compare two values, and if they are different, return the position of the +/// most significant bit that is different in the values. +Optional<unsigned> GetMostSignificantDifferentBit(const APInt &A, + const APInt &B); + +} // End of APIntOps namespace + +// See friend declaration above. This additional declaration is required in +// order to compile LLVM with IBM xlC compiler. +hash_code hash_value(const APInt &Arg); + +/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst +/// with the integer held in IntVal. +void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, unsigned StoreBytes); + +/// LoadIntFromMemory - Loads the integer stored in the LoadBytes bytes starting +/// from Src into IntVal, which is assumed to be wide enough and to hold zero. +void LoadIntFromMemory(APInt &IntVal, uint8_t *Src, unsigned LoadBytes); + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/APSInt.h b/third_party/llvm-project/include/llvm/ADT/APSInt.h new file mode 100644 index 000000000..0f991826c --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/APSInt.h @@ -0,0 +1,353 @@ +//===-- llvm/ADT/APSInt.h - Arbitrary Precision Signed Int -----*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the APSInt class, which is a simple class that +// represents an arbitrary sized integer that knows its signedness. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_APSINT_H +#define LLVM_ADT_APSINT_H + +#include "llvm/ADT/APInt.h" + +namespace llvm { + +class LLVM_NODISCARD APSInt : public APInt { + bool IsUnsigned; + +public: + /// Default constructor that creates an uninitialized APInt. + explicit APSInt() : IsUnsigned(false) {} + + /// APSInt ctor - Create an APSInt with the specified width, default to + /// unsigned. + explicit APSInt(uint32_t BitWidth, bool isUnsigned = true) + : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {} + + explicit APSInt(APInt I, bool isUnsigned = true) + : APInt(std::move(I)), IsUnsigned(isUnsigned) {} + + /// Construct an APSInt from a string representation. + /// + /// This constructor interprets the string \p Str using the radix of 10. + /// The interpretation stops at the end of the string. The bit width of the + /// constructed APSInt is determined automatically. + /// + /// \param Str the string to be interpreted. + explicit APSInt(StringRef Str); + + /// Determine sign of this APSInt. + /// + /// \returns true if this APSInt is negative, false otherwise + bool isNegative() const { return isSigned() && APInt::isNegative(); } + + /// Determine if this APSInt Value is non-negative (>= 0) + /// + /// \returns true if this APSInt is non-negative, false otherwise + bool isNonNegative() const { return !isNegative(); } + + /// Determine if this APSInt Value is positive. + /// + /// This tests if the value of this APSInt is positive (> 0). Note + /// that 0 is not a positive value. + /// + /// \returns true if this APSInt is positive. + bool isStrictlyPositive() const { return isNonNegative() && !isNullValue(); } + + APSInt &operator=(APInt RHS) { + // Retain our current sign. + APInt::operator=(std::move(RHS)); + return *this; + } + + APSInt &operator=(uint64_t RHS) { + // Retain our current sign. + APInt::operator=(RHS); + return *this; + } + + // Query sign information. + bool isSigned() const { return !IsUnsigned; } + bool isUnsigned() const { return IsUnsigned; } + void setIsUnsigned(bool Val) { IsUnsigned = Val; } + void setIsSigned(bool Val) { IsUnsigned = !Val; } + + /// toString - Append this APSInt to the specified SmallString. + void toString(SmallVectorImpl<char> &Str, unsigned Radix = 10) const { + APInt::toString(Str, Radix, isSigned()); + } + /// toString - Converts an APInt to a std::string. This is an inefficient + /// method; you should prefer passing in a SmallString instead. + std::string toString(unsigned Radix) const { + return APInt::toString(Radix, isSigned()); + } + using APInt::toString; + + /// Get the correctly-extended \c int64_t value. + int64_t getExtValue() const { + assert(getMinSignedBits() <= 64 && "Too many bits for int64_t"); + return isSigned() ? getSExtValue() : getZExtValue(); + } + + APSInt trunc(uint32_t width) const { + return APSInt(APInt::trunc(width), IsUnsigned); + } + + APSInt extend(uint32_t width) const { + if (IsUnsigned) + return APSInt(zext(width), IsUnsigned); + else + return APSInt(sext(width), IsUnsigned); + } + + APSInt extOrTrunc(uint32_t width) const { + if (IsUnsigned) + return APSInt(zextOrTrunc(width), IsUnsigned); + else + return APSInt(sextOrTrunc(width), IsUnsigned); + } + + const APSInt &operator%=(const APSInt &RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + if (IsUnsigned) + *this = urem(RHS); + else + *this = srem(RHS); + return *this; + } + const APSInt &operator/=(const APSInt &RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + if (IsUnsigned) + *this = udiv(RHS); + else + *this = sdiv(RHS); + return *this; + } + APSInt operator%(const APSInt &RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? APSInt(urem(RHS), true) : APSInt(srem(RHS), false); + } + APSInt operator/(const APSInt &RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? APSInt(udiv(RHS), true) : APSInt(sdiv(RHS), false); + } + + APSInt operator>>(unsigned Amt) const { + return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false); + } + APSInt& operator>>=(unsigned Amt) { + if (IsUnsigned) + lshrInPlace(Amt); + else + ashrInPlace(Amt); + return *this; + } + + inline bool operator<(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? ult(RHS) : slt(RHS); + } + inline bool operator>(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? ugt(RHS) : sgt(RHS); + } + inline bool operator<=(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? ule(RHS) : sle(RHS); + } + inline bool operator>=(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return IsUnsigned ? uge(RHS) : sge(RHS); + } + inline bool operator==(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return eq(RHS); + } + inline bool operator!=(const APSInt& RHS) const { + return !((*this) == RHS); + } + + bool operator==(int64_t RHS) const { + return compareValues(*this, get(RHS)) == 0; + } + bool operator!=(int64_t RHS) const { + return compareValues(*this, get(RHS)) != 0; + } + bool operator<=(int64_t RHS) const { + return compareValues(*this, get(RHS)) <= 0; + } + bool operator>=(int64_t RHS) const { + return compareValues(*this, get(RHS)) >= 0; + } + bool operator<(int64_t RHS) const { + return compareValues(*this, get(RHS)) < 0; + } + bool operator>(int64_t RHS) const { + return compareValues(*this, get(RHS)) > 0; + } + + // The remaining operators just wrap the logic of APInt, but retain the + // signedness information. + + APSInt operator<<(unsigned Bits) const { + return APSInt(static_cast<const APInt&>(*this) << Bits, IsUnsigned); + } + APSInt& operator<<=(unsigned Amt) { + static_cast<APInt&>(*this) <<= Amt; + return *this; + } + + APSInt& operator++() { + ++(static_cast<APInt&>(*this)); + return *this; + } + APSInt& operator--() { + --(static_cast<APInt&>(*this)); + return *this; + } + APSInt operator++(int) { + return APSInt(++static_cast<APInt&>(*this), IsUnsigned); + } + APSInt operator--(int) { + return APSInt(--static_cast<APInt&>(*this), IsUnsigned); + } + APSInt operator-() const { + return APSInt(-static_cast<const APInt&>(*this), IsUnsigned); + } + APSInt& operator+=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) += RHS; + return *this; + } + APSInt& operator-=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) -= RHS; + return *this; + } + APSInt& operator*=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) *= RHS; + return *this; + } + APSInt& operator&=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) &= RHS; + return *this; + } + APSInt& operator|=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) |= RHS; + return *this; + } + APSInt& operator^=(const APSInt& RHS) { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + static_cast<APInt&>(*this) ^= RHS; + return *this; + } + + APSInt operator&(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned); + } + + APSInt operator|(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned); + } + + APSInt operator^(const APSInt &RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned); + } + + APSInt operator*(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) * RHS, IsUnsigned); + } + APSInt operator+(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) + RHS, IsUnsigned); + } + APSInt operator-(const APSInt& RHS) const { + assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); + return APSInt(static_cast<const APInt&>(*this) - RHS, IsUnsigned); + } + APSInt operator~() const { + return APSInt(~static_cast<const APInt&>(*this), IsUnsigned); + } + + /// getMaxValue - Return the APSInt representing the maximum integer value + /// with the given bit width and signedness. + static APSInt getMaxValue(uint32_t numBits, bool Unsigned) { + return APSInt(Unsigned ? APInt::getMaxValue(numBits) + : APInt::getSignedMaxValue(numBits), Unsigned); + } + + /// getMinValue - Return the APSInt representing the minimum integer value + /// with the given bit width and signedness. + static APSInt getMinValue(uint32_t numBits, bool Unsigned) { + return APSInt(Unsigned ? APInt::getMinValue(numBits) + : APInt::getSignedMinValue(numBits), Unsigned); + } + + /// Determine if two APSInts have the same value, zero- or + /// sign-extending as needed. + static bool isSameValue(const APSInt &I1, const APSInt &I2) { + return !compareValues(I1, I2); + } + + /// Compare underlying values of two numbers. + static int compareValues(const APSInt &I1, const APSInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned()) + return I1.IsUnsigned ? I1.compare(I2) : I1.compareSigned(I2); + + // Check for a bit-width mismatch. + if (I1.getBitWidth() > I2.getBitWidth()) + return compareValues(I1, I2.extend(I1.getBitWidth())); + if (I2.getBitWidth() > I1.getBitWidth()) + return compareValues(I1.extend(I2.getBitWidth()), I2); + + // We have a signedness mismatch. Check for negative values and do an + // unsigned compare if both are positive. + if (I1.isSigned()) { + assert(!I2.isSigned() && "Expected signed mismatch"); + if (I1.isNegative()) + return -1; + } else { + assert(I2.isSigned() && "Expected signed mismatch"); + if (I2.isNegative()) + return 1; + } + + return I1.compare(I2); + } + + static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); } + static APSInt getUnsigned(uint64_t X) { return APSInt(APInt(64, X), true); } + + /// Profile - Used to insert APSInt objects, or objects that contain APSInt + /// objects, into FoldingSets. + void Profile(FoldingSetNodeID& ID) const; +}; + +inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; } +inline bool operator!=(int64_t V1, const APSInt &V2) { return V2 != V1; } +inline bool operator<=(int64_t V1, const APSInt &V2) { return V2 >= V1; } +inline bool operator>=(int64_t V1, const APSInt &V2) { return V2 <= V1; } +inline bool operator<(int64_t V1, const APSInt &V2) { return V2 > V1; } +inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; } + +inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) { + I.print(OS, I.isSigned()); + return OS; +} + +} // end namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/AllocatorList.h b/third_party/llvm-project/include/llvm/ADT/AllocatorList.h new file mode 100644 index 000000000..405a2e426 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/AllocatorList.h @@ -0,0 +1,240 @@ +//===- llvm/ADT/AllocatorList.h - Custom allocator list ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ALLOCATORLIST_H +#define LLVM_ADT_ALLOCATORLIST_H + +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/simple_ilist.h" +#include "llvm/Support/Allocator.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// A linked-list with a custom, local allocator. +/// +/// Expose a std::list-like interface that owns and uses a custom LLVM-style +/// allocator (e.g., BumpPtrAllocator), leveraging \a simple_ilist for the +/// implementation details. +/// +/// Because this list owns the allocator, calling \a splice() with a different +/// list isn't generally safe. As such, \a splice has been left out of the +/// interface entirely. +template <class T, class AllocatorT> class AllocatorList : AllocatorT { + struct Node : ilist_node<Node> { + Node(Node &&) = delete; + Node(const Node &) = delete; + Node &operator=(Node &&) = delete; + Node &operator=(const Node &) = delete; + + Node(T &&V) : V(std::move(V)) {} + Node(const T &V) : V(V) {} + template <class... Ts> Node(Ts &&... Vs) : V(std::forward<Ts>(Vs)...) {} + T V; + }; + + using list_type = simple_ilist<Node>; + + list_type List; + + AllocatorT &getAlloc() { return *this; } + const AllocatorT &getAlloc() const { return *this; } + + template <class... ArgTs> Node *create(ArgTs &&... Args) { + return new (getAlloc()) Node(std::forward<ArgTs>(Args)...); + } + + struct Cloner { + AllocatorList &AL; + + Cloner(AllocatorList &AL) : AL(AL) {} + + Node *operator()(const Node &N) const { return AL.create(N.V); } + }; + + struct Disposer { + AllocatorList &AL; + + Disposer(AllocatorList &AL) : AL(AL) {} + + void operator()(Node *N) const { + N->~Node(); + AL.getAlloc().Deallocate(N); + } + }; + +public: + using value_type = T; + using pointer = T *; + using reference = T &; + using const_pointer = const T *; + using const_reference = const T &; + using size_type = typename list_type::size_type; + using difference_type = typename list_type::difference_type; + +private: + template <class ValueT, class IteratorBase> + class IteratorImpl + : public iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>, + IteratorBase, + std::bidirectional_iterator_tag, ValueT> { + template <class OtherValueT, class OtherIteratorBase> + friend class IteratorImpl; + friend AllocatorList; + + using base_type = + iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>, IteratorBase, + std::bidirectional_iterator_tag, ValueT>; + + public: + using value_type = ValueT; + using pointer = ValueT *; + using reference = ValueT &; + + IteratorImpl() = default; + IteratorImpl(const IteratorImpl &) = default; + IteratorImpl &operator=(const IteratorImpl &) = default; + + explicit IteratorImpl(const IteratorBase &I) : base_type(I) {} + + template <class OtherValueT, class OtherIteratorBase> + IteratorImpl(const IteratorImpl<OtherValueT, OtherIteratorBase> &X, + typename std::enable_if<std::is_convertible< + OtherIteratorBase, IteratorBase>::value>::type * = nullptr) + : base_type(X.wrapped()) {} + + ~IteratorImpl() = default; + + reference operator*() const { return base_type::wrapped()->V; } + pointer operator->() const { return &operator*(); } + + friend bool operator==(const IteratorImpl &L, const IteratorImpl &R) { + return L.wrapped() == R.wrapped(); + } + friend bool operator!=(const IteratorImpl &L, const IteratorImpl &R) { + return !(L == R); + } + }; + +public: + using iterator = IteratorImpl<T, typename list_type::iterator>; + using reverse_iterator = + IteratorImpl<T, typename list_type::reverse_iterator>; + using const_iterator = + IteratorImpl<const T, typename list_type::const_iterator>; + using const_reverse_iterator = + IteratorImpl<const T, typename list_type::const_reverse_iterator>; + + AllocatorList() = default; + AllocatorList(AllocatorList &&X) + : AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {} + + AllocatorList(const AllocatorList &X) { + List.cloneFrom(X.List, Cloner(*this), Disposer(*this)); + } + + AllocatorList &operator=(AllocatorList &&X) { + clear(); // Dispose of current nodes explicitly. + List = std::move(X.List); + getAlloc() = std::move(X.getAlloc()); + return *this; + } + + AllocatorList &operator=(const AllocatorList &X) { + List.cloneFrom(X.List, Cloner(*this), Disposer(*this)); + return *this; + } + + ~AllocatorList() { clear(); } + + void swap(AllocatorList &RHS) { + List.swap(RHS.List); + std::swap(getAlloc(), RHS.getAlloc()); + } + + bool empty() { return List.empty(); } + size_t size() { return List.size(); } + + iterator begin() { return iterator(List.begin()); } + iterator end() { return iterator(List.end()); } + const_iterator begin() const { return const_iterator(List.begin()); } + const_iterator end() const { return const_iterator(List.end()); } + reverse_iterator rbegin() { return reverse_iterator(List.rbegin()); } + reverse_iterator rend() { return reverse_iterator(List.rend()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(List.rbegin()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(List.rend()); + } + + T &back() { return List.back().V; } + T &front() { return List.front().V; } + const T &back() const { return List.back().V; } + const T &front() const { return List.front().V; } + + template <class... Ts> iterator emplace(iterator I, Ts &&... Vs) { + return iterator(List.insert(I.wrapped(), *create(std::forward<Ts>(Vs)...))); + } + + iterator insert(iterator I, T &&V) { + return iterator(List.insert(I.wrapped(), *create(std::move(V)))); + } + iterator insert(iterator I, const T &V) { + return iterator(List.insert(I.wrapped(), *create(V))); + } + + template <class Iterator> + void insert(iterator I, Iterator First, Iterator Last) { + for (; First != Last; ++First) + List.insert(I.wrapped(), *create(*First)); + } + + iterator erase(iterator I) { + return iterator(List.eraseAndDispose(I.wrapped(), Disposer(*this))); + } + + iterator erase(iterator First, iterator Last) { + return iterator( + List.eraseAndDispose(First.wrapped(), Last.wrapped(), Disposer(*this))); + } + + void clear() { List.clearAndDispose(Disposer(*this)); } + void pop_back() { List.eraseAndDispose(--List.end(), Disposer(*this)); } + void pop_front() { List.eraseAndDispose(List.begin(), Disposer(*this)); } + void push_back(T &&V) { insert(end(), std::move(V)); } + void push_front(T &&V) { insert(begin(), std::move(V)); } + void push_back(const T &V) { insert(end(), V); } + void push_front(const T &V) { insert(begin(), V); } + template <class... Ts> void emplace_back(Ts &&... Vs) { + emplace(end(), std::forward<Ts>(Vs)...); + } + template <class... Ts> void emplace_front(Ts &&... Vs) { + emplace(begin(), std::forward<Ts>(Vs)...); + } + + /// Reset the underlying allocator. + /// + /// \pre \c empty() + void resetAlloc() { + assert(empty() && "Cannot reset allocator if not empty"); + getAlloc().Reset(); + } +}; + +template <class T> using BumpPtrList = AllocatorList<T, BumpPtrAllocator>; + +} // end namespace llvm + +#endif // LLVM_ADT_ALLOCATORLIST_H diff --git a/third_party/llvm-project/include/llvm/ADT/ArrayRef.h b/third_party/llvm-project/include/llvm/ADT/ArrayRef.h new file mode 100644 index 000000000..f6455d3fa --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ArrayRef.h @@ -0,0 +1,540 @@ +//===- ArrayRef.h - Array Reference Wrapper ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ARRAYREF_H +#define LLVM_ADT_ARRAYREF_H + +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include <algorithm> +#include <array> +#include <cassert> +#include <cstddef> +#include <initializer_list> +#include <iterator> +#include <memory> +#include <type_traits> +#include <vector> + +namespace llvm { + + /// ArrayRef - Represent a constant reference to an array (0 or more elements + /// consecutively in memory), i.e. a start pointer and a length. It allows + /// various APIs to take consecutive elements easily and conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the ArrayRef. For this reason, it is not in general + /// safe to store an ArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template<typename T> + class LLVM_NODISCARD ArrayRef { + public: + using iterator = const T *; + using const_iterator = const T *; + using size_type = size_t; + using reverse_iterator = std::reverse_iterator<iterator>; + + private: + /// The start of the array, in an external buffer. + const T *Data = nullptr; + + /// The number of elements. + size_type Length = 0; + + public: + /// @name Constructors + /// @{ + + /// Construct an empty ArrayRef. + /*implicit*/ ArrayRef() = default; + + /// Construct an empty ArrayRef from None. + /*implicit*/ ArrayRef(NoneType) {} + + /// Construct an ArrayRef from a single element. + /*implicit*/ ArrayRef(const T &OneElt) + : Data(&OneElt), Length(1) {} + + /// Construct an ArrayRef from a pointer and length. + /*implicit*/ ArrayRef(const T *data, size_t length) + : Data(data), Length(length) {} + + /// Construct an ArrayRef from a range. + ArrayRef(const T *begin, const T *end) + : Data(begin), Length(end - begin) {} + + /// Construct an ArrayRef from a SmallVector. This is templated in order to + /// avoid instantiating SmallVectorTemplateCommon<T> whenever we + /// copy-construct an ArrayRef. + template<typename U> + /*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec) + : Data(Vec.data()), Length(Vec.size()) { + } + + /// Construct an ArrayRef from a std::vector. + template<typename A> + /*implicit*/ ArrayRef(const std::vector<T, A> &Vec) + : Data(Vec.data()), Length(Vec.size()) {} + + /// Construct an ArrayRef from a std::array + template <size_t N> + /*implicit*/ constexpr ArrayRef(const std::array<T, N> &Arr) + : Data(Arr.data()), Length(N) {} + + /// Construct an ArrayRef from a C array. + template <size_t N> + /*implicit*/ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {} + + /// Construct an ArrayRef from a std::initializer_list. + /*implicit*/ ArrayRef(const std::initializer_list<T> &Vec) + : Data(Vec.begin() == Vec.end() ? (T*)nullptr : Vec.begin()), + Length(Vec.size()) {} + + /// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to + /// ensure that only ArrayRefs of pointers can be converted. + template <typename U> + ArrayRef( + const ArrayRef<U *> &A, + typename std::enable_if< + std::is_convertible<U *const *, T const *>::value>::type * = nullptr) + : Data(A.data()), Length(A.size()) {} + + /// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is + /// templated in order to avoid instantiating SmallVectorTemplateCommon<T> + /// whenever we copy-construct an ArrayRef. + template<typename U, typename DummyT> + /*implicit*/ ArrayRef( + const SmallVectorTemplateCommon<U *, DummyT> &Vec, + typename std::enable_if< + std::is_convertible<U *const *, T const *>::value>::type * = nullptr) + : Data(Vec.data()), Length(Vec.size()) { + } + + /// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE + /// to ensure that only vectors of pointers can be converted. + template<typename U, typename A> + ArrayRef(const std::vector<U *, A> &Vec, + typename std::enable_if< + std::is_convertible<U *const *, T const *>::value>::type* = 0) + : Data(Vec.data()), Length(Vec.size()) {} + + /// @} + /// @name Simple Operations + /// @{ + + iterator begin() const { return Data; } + iterator end() const { return Data + Length; } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// empty - Check if the array is empty. + bool empty() const { return Length == 0; } + + const T *data() const { return Data; } + + /// size - Get the array size. + size_t size() const { return Length; } + + /// front - Get the first element. + const T &front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last element. + const T &back() const { + assert(!empty()); + return Data[Length-1]; + } + + // copy - Allocate copy in Allocator and return ArrayRef<T> to it. + template <typename Allocator> ArrayRef<T> copy(Allocator &A) { + T *Buff = A.template Allocate<T>(Length); + std::uninitialized_copy(begin(), end(), Buff); + return ArrayRef<T>(Buff, Length); + } + + /// equals - Check for element-wise equality. + bool equals(ArrayRef RHS) const { + if (Length != RHS.Length) + return false; + return std::equal(begin(), end(), RHS.begin()); + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + ArrayRef<T> slice(size_t N, size_t M) const { + assert(N+M <= size() && "Invalid specifier"); + return ArrayRef<T>(data()+N, M); + } + + /// slice(n) - Chop off the first N elements of the array. + ArrayRef<T> slice(size_t N) const { return slice(N, size() - N); } + + /// Drop the first \p N elements of the array. + ArrayRef<T> drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(N, size() - N); + } + + /// Drop the last \p N elements of the array. + ArrayRef<T> drop_back(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(0, size() - N); + } + + /// Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template <class PredicateT> ArrayRef<T> drop_while(PredicateT Pred) const { + return ArrayRef<T>(find_if_not(*this, Pred), end()); + } + + /// Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template <class PredicateT> ArrayRef<T> drop_until(PredicateT Pred) const { + return ArrayRef<T>(find_if(*this, Pred), end()); + } + + /// Return a copy of *this with only the first \p N elements. + ArrayRef<T> take_front(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_back(size() - N); + } + + /// Return a copy of *this with only the last \p N elements. + ArrayRef<T> take_back(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_front(size() - N); + } + + /// Return the first N elements of this Array that satisfy the given + /// predicate. + template <class PredicateT> ArrayRef<T> take_while(PredicateT Pred) const { + return ArrayRef<T>(begin(), find_if_not(*this, Pred)); + } + + /// Return the first N elements of this Array that don't satisfy the + /// given predicate. + template <class PredicateT> ArrayRef<T> take_until(PredicateT Pred) const { + return ArrayRef<T>(begin(), find_if(*this, Pred)); + } + + /// @} + /// @name Operator Overloads + /// @{ + const T &operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template <typename U> + typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type & + operator=(U &&Temporary) = delete; + + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template <typename U> + typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type & + operator=(std::initializer_list<U>) = delete; + + /// @} + /// @name Expensive Operations + /// @{ + std::vector<T> vec() const { + return std::vector<T>(Data, Data+Length); + } + + /// @} + /// @name Conversion operators + /// @{ + operator std::vector<T>() const { + return std::vector<T>(Data, Data+Length); + } + + /// @} + }; + + /// MutableArrayRef - Represent a mutable reference to an array (0 or more + /// elements consecutively in memory), i.e. a start pointer and a length. It + /// allows various APIs to take and modify consecutive elements easily and + /// conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the MutableArrayRef. For this reason, it is not in + /// general safe to store a MutableArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template<typename T> + class LLVM_NODISCARD MutableArrayRef : public ArrayRef<T> { + public: + using iterator = T *; + using reverse_iterator = std::reverse_iterator<iterator>; + + /// Construct an empty MutableArrayRef. + /*implicit*/ MutableArrayRef() = default; + + /// Construct an empty MutableArrayRef from None. + /*implicit*/ MutableArrayRef(NoneType) : ArrayRef<T>() {} + + /// Construct an MutableArrayRef from a single element. + /*implicit*/ MutableArrayRef(T &OneElt) : ArrayRef<T>(OneElt) {} + + /// Construct an MutableArrayRef from a pointer and length. + /*implicit*/ MutableArrayRef(T *data, size_t length) + : ArrayRef<T>(data, length) {} + + /// Construct an MutableArrayRef from a range. + MutableArrayRef(T *begin, T *end) : ArrayRef<T>(begin, end) {} + + /// Construct an MutableArrayRef from a SmallVector. + /*implicit*/ MutableArrayRef(SmallVectorImpl<T> &Vec) + : ArrayRef<T>(Vec) {} + + /// Construct a MutableArrayRef from a std::vector. + /*implicit*/ MutableArrayRef(std::vector<T> &Vec) + : ArrayRef<T>(Vec) {} + + /// Construct an ArrayRef from a std::array + template <size_t N> + /*implicit*/ constexpr MutableArrayRef(std::array<T, N> &Arr) + : ArrayRef<T>(Arr) {} + + /// Construct an MutableArrayRef from a C array. + template <size_t N> + /*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {} + + T *data() const { return const_cast<T*>(ArrayRef<T>::data()); } + + iterator begin() const { return data(); } + iterator end() const { return data() + this->size(); } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// front - Get the first element. + T &front() const { + assert(!this->empty()); + return data()[0]; + } + + /// back - Get the last element. + T &back() const { + assert(!this->empty()); + return data()[this->size()-1]; + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + MutableArrayRef<T> slice(size_t N, size_t M) const { + assert(N + M <= this->size() && "Invalid specifier"); + return MutableArrayRef<T>(this->data() + N, M); + } + + /// slice(n) - Chop off the first N elements of the array. + MutableArrayRef<T> slice(size_t N) const { + return slice(N, this->size() - N); + } + + /// Drop the first \p N elements of the array. + MutableArrayRef<T> drop_front(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(N, this->size() - N); + } + + MutableArrayRef<T> drop_back(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(0, this->size() - N); + } + + /// Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template <class PredicateT> + MutableArrayRef<T> drop_while(PredicateT Pred) const { + return MutableArrayRef<T>(find_if_not(*this, Pred), end()); + } + + /// Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template <class PredicateT> + MutableArrayRef<T> drop_until(PredicateT Pred) const { + return MutableArrayRef<T>(find_if(*this, Pred), end()); + } + + /// Return a copy of *this with only the first \p N elements. + MutableArrayRef<T> take_front(size_t N = 1) const { + if (N >= this->size()) + return *this; + return drop_back(this->size() - N); + } + + /// Return a copy of *this with only the last \p N elements. + MutableArrayRef<T> take_back(size_t N = 1) const { + if (N >= this->size()) + return *this; + return drop_front(this->size() - N); + } + + /// Return the first N elements of this Array that satisfy the given + /// predicate. + template <class PredicateT> + MutableArrayRef<T> take_while(PredicateT Pred) const { + return MutableArrayRef<T>(begin(), find_if_not(*this, Pred)); + } + + /// Return the first N elements of this Array that don't satisfy the + /// given predicate. + template <class PredicateT> + MutableArrayRef<T> take_until(PredicateT Pred) const { + return MutableArrayRef<T>(begin(), find_if(*this, Pred)); + } + + /// @} + /// @name Operator Overloads + /// @{ + T &operator[](size_t Index) const { + assert(Index < this->size() && "Invalid index!"); + return data()[Index]; + } + }; + + /// This is a MutableArrayRef that owns its array. + template <typename T> class OwningArrayRef : public MutableArrayRef<T> { + public: + OwningArrayRef() = default; + OwningArrayRef(size_t Size) : MutableArrayRef<T>(new T[Size], Size) {} + + OwningArrayRef(ArrayRef<T> Data) + : MutableArrayRef<T>(new T[Data.size()], Data.size()) { + std::copy(Data.begin(), Data.end(), this->begin()); + } + + OwningArrayRef(OwningArrayRef &&Other) { *this = std::move(Other); } + + OwningArrayRef &operator=(OwningArrayRef &&Other) { + delete[] this->data(); + this->MutableArrayRef<T>::operator=(Other); + Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>()); + return *this; + } + + ~OwningArrayRef() { delete[] this->data(); } + }; + + /// @name ArrayRef Convenience constructors + /// @{ + + /// Construct an ArrayRef from a single element. + template<typename T> + ArrayRef<T> makeArrayRef(const T &OneElt) { + return OneElt; + } + + /// Construct an ArrayRef from a pointer and length. + template<typename T> + ArrayRef<T> makeArrayRef(const T *data, size_t length) { + return ArrayRef<T>(data, length); + } + + /// Construct an ArrayRef from a range. + template<typename T> + ArrayRef<T> makeArrayRef(const T *begin, const T *end) { + return ArrayRef<T>(begin, end); + } + + /// Construct an ArrayRef from a SmallVector. + template <typename T> + ArrayRef<T> makeArrayRef(const SmallVectorImpl<T> &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a SmallVector. + template <typename T, unsigned N> + ArrayRef<T> makeArrayRef(const SmallVector<T, N> &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a std::vector. + template<typename T> + ArrayRef<T> makeArrayRef(const std::vector<T> &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a std::array. + template <typename T, std::size_t N> + ArrayRef<T> makeArrayRef(const std::array<T, N> &Arr) { + return Arr; + } + + /// Construct an ArrayRef from an ArrayRef (no-op) (const) + template <typename T> ArrayRef<T> makeArrayRef(const ArrayRef<T> &Vec) { + return Vec; + } + + /// Construct an ArrayRef from an ArrayRef (no-op) + template <typename T> ArrayRef<T> &makeArrayRef(ArrayRef<T> &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a C array. + template<typename T, size_t N> + ArrayRef<T> makeArrayRef(const T (&Arr)[N]) { + 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 + /// @{ + + template<typename T> + inline bool operator==(ArrayRef<T> LHS, ArrayRef<T> RHS) { + return LHS.equals(RHS); + } + + template<typename T> + inline bool operator!=(ArrayRef<T> LHS, ArrayRef<T> RHS) { + return !(LHS == RHS); + } + + /// @} + + template <typename T> hash_code hash_value(ArrayRef<T> S) { + return hash_combine_range(S.begin(), S.end()); + } + +} // end namespace llvm + +#endif // LLVM_ADT_ARRAYREF_H diff --git a/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h b/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h new file mode 100644 index 000000000..1a18bc721 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h @@ -0,0 +1,152 @@ +//===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BITMASKENUM_H +#define LLVM_ADT_BITMASKENUM_H + +#include <cassert> +#include <type_traits> +#include <utility> + +#include "llvm/Support/MathExtras.h" + +/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can +/// perform bitwise operations on it without putting static_cast everywhere. +/// +/// \code +/// enum MyEnum { +/// E1 = 1, E2 = 2, E3 = 4, E4 = 8, +/// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4) +/// }; +/// +/// void Foo() { +/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast! +/// } +/// \endcode +/// +/// Normally when you do a bitwise operation on an enum value, you get back an +/// instance of the underlying type (e.g. int). But using this macro, bitwise +/// ops on your enum will return you back instances of the enum. This is +/// particularly useful for enums which represent a combination of flags. +/// +/// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual +/// value in your enum. +/// +/// All of the enum's values must be non-negative. +#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \ + LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue + +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used +/// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. +/// +/// Suppose you have an enum foo::bar::MyEnum. Before using +/// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or +/// namespace foo::bar. This allows the relevant operator overloads to be found +/// by ADL. +/// +/// You don't need to use this macro in namespace llvm; it's done at the bottom +/// of this file. +#define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ + using ::llvm::BitmaskEnumDetail::operator~; \ + using ::llvm::BitmaskEnumDetail::operator|; \ + using ::llvm::BitmaskEnumDetail::operator&; \ + using ::llvm::BitmaskEnumDetail::operator^; \ + using ::llvm::BitmaskEnumDetail::operator|=; \ + using ::llvm::BitmaskEnumDetail::operator&=; \ + /* Force a semicolon at the end of this macro. */ \ + using ::llvm::BitmaskEnumDetail::operator^= + +namespace llvm { + +/// Traits class to determine whether an enum has a +/// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. +template <typename E, typename Enable = void> +struct is_bitmask_enum : std::false_type {}; + +template <typename E> +struct is_bitmask_enum< + E, typename std::enable_if<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= + 0>::type> : std::true_type {}; +namespace BitmaskEnumDetail { + +/// Get a bitmask with 1s in all places up to the high-order bit of E's largest +/// value. +template <typename E> typename std::underlying_type<E>::type Mask() { + // On overflow, NextPowerOf2 returns zero with the type uint64_t, so + // subtracting 1 gives us the mask with all bits set, like we want. + return NextPowerOf2(static_cast<typename std::underlying_type<E>::type>( + E::LLVM_BITMASK_LARGEST_ENUMERATOR)) - + 1; +} + +/// Check that Val is in range for E, and return Val cast to E's underlying +/// type. +template <typename E> typename std::underlying_type<E>::type Underlying(E Val) { + auto U = static_cast<typename std::underlying_type<E>::type>(Val); + assert(U >= 0 && "Negative enum values are not allowed."); + assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)"); + return U; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator~(E Val) { + return static_cast<E>(~Underlying(Val) & Mask<E>()); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator|(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) | Underlying(RHS)); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator&(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) & Underlying(RHS)); +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E operator^(E LHS, E RHS) { + return static_cast<E>(Underlying(LHS) ^ Underlying(RHS)); +} + +// |=, &=, and ^= return a reference to LHS, to match the behavior of the +// operators on builtin types. + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator|=(E &LHS, E RHS) { + LHS = LHS | RHS; + return LHS; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator&=(E &LHS, E RHS) { + LHS = LHS & RHS; + return LHS; +} + +template <typename E, + typename = typename std::enable_if<is_bitmask_enum<E>::value>::type> +E &operator^=(E &LHS, E RHS) { + LHS = LHS ^ RHS; + return LHS; +} + +} // namespace BitmaskEnumDetail + +// Enable bitmask enums in namespace ::llvm and all nested namespaces. +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/DenseMap.h b/third_party/llvm-project/include/llvm/ADT/DenseMap.h new file mode 100644 index 000000000..948a6e6bf --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/DenseMap.h @@ -0,0 +1,1275 @@ +//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the DenseMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_DENSEMAP_H +#define LLVM_ADT_DENSEMAP_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/EpochTracker.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/ReverseIteration.h" +#include "llvm/Support/type_traits.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <initializer_list> +#include <iterator> +#include <new> +#include <type_traits> +#include <utility> + +namespace llvm { + +namespace detail { + +// We extend a pair to allow users to override the bucket type with their own +// implementation without requiring two members. +template <typename KeyT, typename ValueT> +struct DenseMapPair : public std::pair<KeyT, ValueT> { + using std::pair<KeyT, ValueT>::pair; + + KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; } + const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; } + ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; } + const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; } +}; + +} // end namespace detail + +template <typename KeyT, typename ValueT, + typename KeyInfoT = DenseMapInfo<KeyT>, + typename Bucket = llvm::detail::DenseMapPair<KeyT, ValueT>, + bool IsConst = false> +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: + using size_type = unsigned; + using key_type = KeyT; + using mapped_type = ValueT; + using value_type = BucketT; + + using iterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT>; + using const_iterator = + DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>; + + inline iterator begin() { + // When the map is empty, avoid the overhead of advancing/retreating past + // empty buckets. + if (empty()) + return end(); + if (shouldReverseIterate<KeyT>()) + return makeIterator(getBucketsEnd() - 1, getBuckets(), *this); + return makeIterator(getBuckets(), getBucketsEnd(), *this); + } + inline iterator end() { + return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true); + } + inline const_iterator begin() const { + if (empty()) + return end(); + if (shouldReverseIterate<KeyT>()) + return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this); + return makeConstIterator(getBuckets(), getBucketsEnd(), *this); + } + inline const_iterator end() const { + return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true); + } + + LLVM_NODISCARD bool empty() const { + return getNumEntries() == 0; + } + unsigned size() const { return getNumEntries(); } + + /// Grow the densemap so that it can contain at least \p NumEntries items + /// before resizing again. + void reserve(size_type NumEntries) { + auto NumBuckets = getMinBucketToReserveForEntries(NumEntries); + incrementEpoch(); + if (NumBuckets > getNumBuckets()) + grow(NumBuckets); + } + + void clear() { + incrementEpoch(); + if (getNumEntries() == 0 && getNumTombstones() == 0) return; + + // If the capacity of the array is huge, and the # elements used is small, + // shrink the array. + if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) { + shrink_and_clear(); + return; + } + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + if (is_trivially_copyable<KeyT>::value && + is_trivially_copyable<ValueT>::value) { + // Use a simpler loop when these are trivial types. + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) + P->getFirst() = EmptyKey; + } else { + unsigned NumEntries = getNumEntries(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) { + if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) { + P->getSecond().~ValueT(); + --NumEntries; + } + P->getFirst() = EmptyKey; + } + } + assert(NumEntries == 0 && "Node count imbalance!"); + } + setNumEntries(0); + setNumTombstones(0); + } + + /// Return 1 if the specified key is in the map, 0 otherwise. + size_type count(const_arg_type_t<KeyT> Val) const { + const BucketT *TheBucket; + return LookupBucketFor(Val, TheBucket) ? 1 : 0; + } + + iterator find(const_arg_type_t<KeyT> Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return makeIterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + const_iterator find(const_arg_type_t<KeyT> Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return makeConstIterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + + /// Alternate version of find() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template<class LookupKeyT> + iterator find_as(const LookupKeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return makeIterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + template<class LookupKeyT> + const_iterator find_as(const LookupKeyT &Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return makeConstIterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueT lookup(const_arg_type_t<KeyT> Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return TheBucket->getSecond(); + return ValueT(); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) { + return try_emplace(KV.first, KV.second); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) { + return try_emplace(std::move(KV.first), std::move(KV.second)); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // The value is constructed in-place if the key is not in the map, otherwise + // it is not moved. + template <typename... Ts> + std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = + InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // The value is constructed in-place if the key is not in the map, otherwise + // it is not moved. + template <typename... Ts> + std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + + /// Alternate version of insert() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV, + const LookupKeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first), + std::move(KV.second), Val); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + + /// insert - Range insertion of pairs. + template<typename InputIt> + void insert(InputIt I, InputIt E) { + for (; I != E; ++I) + insert(*I); + } + + bool erase(const KeyT &Val) { + BucketT *TheBucket; + if (!LookupBucketFor(Val, TheBucket)) + return false; // not in map. + + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + return true; + } + void erase(iterator I) { + BucketT *TheBucket = &*I; + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + } + + value_type& FindAndConstruct(const KeyT &Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(TheBucket, Key); + } + + ValueT &operator[](const KeyT &Key) { + return FindAndConstruct(Key).second; + } + + value_type& FindAndConstruct(KeyT &&Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(TheBucket, std::move(Key)); + } + + ValueT &operator[](KeyT &&Key) { + return FindAndConstruct(std::move(Key)).second; + } + + /// isPointerIntoBucketsArray - Return true if the specified pointer points + /// somewhere into the DenseMap's array of buckets (i.e. either to a key or + /// value in the DenseMap). + bool isPointerIntoBucketsArray(const void *Ptr) const { + return Ptr >= getBuckets() && Ptr < getBucketsEnd(); + } + + /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets + /// array. In conjunction with the previous method, this can be used to + /// determine whether an insertion caused the DenseMap to reallocate. + const void *getPointerIntoBucketsArray() const { return getBuckets(); } + +protected: + DenseMapBase() = default; + + void destroyAll() { + if (getNumBuckets() == 0) // Nothing to do. + return; + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) + P->getSecond().~ValueT(); + P->getFirst().~KeyT(); + } + } + + void initEmpty() { + setNumEntries(0); + setNumTombstones(0); + + assert((getNumBuckets() & (getNumBuckets()-1)) == 0 && + "# initial buckets must be a power of two!"); + const KeyT EmptyKey = getEmptyKey(); + for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B) + ::new (&B->getFirst()) KeyT(EmptyKey); + } + + /// Returns the number of buckets to allocate to ensure that the DenseMap can + /// accommodate \p NumEntries without need to grow(). + unsigned getMinBucketToReserveForEntries(unsigned NumEntries) { + // Ensure that "NumEntries * 4 < NumBuckets * 3" + if (NumEntries == 0) + return 0; + // +1 is required because of the strict equality. + // For example if NumEntries is 48, we need to return 401. + return NextPowerOf2(NumEntries * 4 / 3 + 1); + } + + void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) { + initEmpty(); + + // Insert all the old elements. + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) { + if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) { + // Insert the key/value into the new table. + BucketT *DestBucket; + bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket); + (void)FoundVal; // silence warning. + assert(!FoundVal && "Key already in new map?"); + DestBucket->getFirst() = std::move(B->getFirst()); + ::new (&DestBucket->getSecond()) ValueT(std::move(B->getSecond())); + incrementNumEntries(); + + // Free the value. + B->getSecond().~ValueT(); + } + B->getFirst().~KeyT(); + } + } + + template <typename OtherBaseT> + void copyFrom( + const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) { + assert(&other != this); + assert(getNumBuckets() == other.getNumBuckets()); + + setNumEntries(other.getNumEntries()); + setNumTombstones(other.getNumTombstones()); + + if (is_trivially_copyable<KeyT>::value && + is_trivially_copyable<ValueT>::value) + memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(), + getNumBuckets() * sizeof(BucketT)); + else + for (size_t i = 0; i < getNumBuckets(); ++i) { + ::new (&getBuckets()[i].getFirst()) + KeyT(other.getBuckets()[i].getFirst()); + if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) && + !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey())) + ::new (&getBuckets()[i].getSecond()) + ValueT(other.getBuckets()[i].getSecond()); + } + } + + static unsigned getHashValue(const KeyT &Val) { + return KeyInfoT::getHashValue(Val); + } + + template<typename LookupKeyT> + static unsigned getHashValue(const LookupKeyT &Val) { + 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() { + return KeyInfoT::getTombstoneKey(); + } + +private: + iterator makeIterator(BucketT *P, BucketT *E, + DebugEpochBase &Epoch, + bool NoAdvance=false) { + if (shouldReverseIterate<KeyT>()) { + BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1; + return iterator(B, E, Epoch, NoAdvance); + } + return iterator(P, E, Epoch, NoAdvance); + } + + const_iterator makeConstIterator(const BucketT *P, const BucketT *E, + const DebugEpochBase &Epoch, + const bool NoAdvance=false) const { + if (shouldReverseIterate<KeyT>()) { + const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1; + return const_iterator(B, E, Epoch, NoAdvance); + } + return const_iterator(P, E, Epoch, NoAdvance); + } + + unsigned getNumEntries() const { + return static_cast<const DerivedT *>(this)->getNumEntries(); + } + + void setNumEntries(unsigned Num) { + static_cast<DerivedT *>(this)->setNumEntries(Num); + } + + void incrementNumEntries() { + setNumEntries(getNumEntries() + 1); + } + + void decrementNumEntries() { + setNumEntries(getNumEntries() - 1); + } + + unsigned getNumTombstones() const { + return static_cast<const DerivedT *>(this)->getNumTombstones(); + } + + void setNumTombstones(unsigned Num) { + static_cast<DerivedT *>(this)->setNumTombstones(Num); + } + + void incrementNumTombstones() { + setNumTombstones(getNumTombstones() + 1); + } + + void decrementNumTombstones() { + setNumTombstones(getNumTombstones() - 1); + } + + const BucketT *getBuckets() const { + return static_cast<const DerivedT *>(this)->getBuckets(); + } + + BucketT *getBuckets() { + return static_cast<DerivedT *>(this)->getBuckets(); + } + + unsigned getNumBuckets() const { + return static_cast<const DerivedT *>(this)->getNumBuckets(); + } + + BucketT *getBucketsEnd() { + return getBuckets() + getNumBuckets(); + } + + const BucketT *getBucketsEnd() const { + return getBuckets() + getNumBuckets(); + } + + void grow(unsigned AtLeast) { + static_cast<DerivedT *>(this)->grow(AtLeast); + } + + void shrink_and_clear() { + static_cast<DerivedT *>(this)->shrink_and_clear(); + } + + template <typename KeyArg, typename... ValueArgs> + BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key, + ValueArgs &&... Values) { + TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket); + + TheBucket->getFirst() = std::forward<KeyArg>(Key); + ::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...); + return TheBucket; + } + + template <typename LookupKeyT> + BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key, + ValueT &&Value, LookupKeyT &Lookup) { + TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket); + + TheBucket->getFirst() = std::move(Key); + ::new (&TheBucket->getSecond()) ValueT(std::move(Value)); + return TheBucket; + } + + template <typename LookupKeyT> + BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup, + BucketT *TheBucket) { + incrementEpoch(); + + // If the load of the hash table is more than 3/4, or if fewer than 1/8 of + // the buckets are empty (meaning that many are filled with tombstones), + // grow the table. + // + // The later case is tricky. For example, if we had one empty bucket with + // tons of tombstones, failing lookups (e.g. for insertion) would have to + // probe almost the entire table until it found the empty bucket. If the + // table completely filled with tombstones, no lookup would ever succeed, + // causing infinite loops in lookup. + unsigned NewNumEntries = getNumEntries() + 1; + unsigned NumBuckets = getNumBuckets(); + if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) { + this->grow(NumBuckets * 2); + LookupBucketFor(Lookup, TheBucket); + NumBuckets = getNumBuckets(); + } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <= + NumBuckets/8)) { + this->grow(NumBuckets); + LookupBucketFor(Lookup, TheBucket); + } + assert(TheBucket); + + // Only update the state after we've grown our bucket space appropriately + // so that when growing buckets we have self-consistent entry count. + incrementNumEntries(); + + // If we are writing over a tombstone, remember this. + const KeyT EmptyKey = getEmptyKey(); + if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey)) + decrementNumTombstones(); + + return TheBucket; + } + + /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in + /// FoundBucket. If the bucket contains the key and a value, this returns + /// true, otherwise it returns a bucket with an empty marker or tombstone and + /// returns false. + template<typename LookupKeyT> + bool LookupBucketFor(const LookupKeyT &Val, + const BucketT *&FoundBucket) const { + const BucketT *BucketsPtr = getBuckets(); + const unsigned NumBuckets = getNumBuckets(); + + if (NumBuckets == 0) { + FoundBucket = nullptr; + return false; + } + + // FoundTombstone - Keep track of whether we find a tombstone while probing. + const BucketT *FoundTombstone = nullptr; + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + assert(!KeyInfoT::isEqual(Val, EmptyKey) && + !KeyInfoT::isEqual(Val, TombstoneKey) && + "Empty/Tombstone value shouldn't be inserted into map!"); + + unsigned BucketNo = getHashValue(Val) & (NumBuckets-1); + unsigned ProbeAmt = 1; + while (true) { + const BucketT *ThisBucket = BucketsPtr + BucketNo; + // Found Val's bucket? If so, return it. + if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) { + FoundBucket = ThisBucket; + return true; + } + + // If we found an empty bucket, the key doesn't exist in the set. + // Insert it and return the default value. + if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) { + // If we've already seen a tombstone while probing, fill it in instead + // of the empty bucket we eventually probed to. + FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; + return false; + } + + // If this is a tombstone, remember it. If Val ends up not in the map, we + // prefer to return it than something that would require more probing. + if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) && + !FoundTombstone) + FoundTombstone = ThisBucket; // Remember the first tombstone found. + + // Otherwise, it's a hash collision or a tombstone, continue quadratic + // probing. + BucketNo += ProbeAmt++; + BucketNo &= (NumBuckets-1); + } + } + + template <typename LookupKeyT> + bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) { + const BucketT *ConstFoundBucket; + bool Result = const_cast<const DenseMapBase *>(this) + ->LookupBucketFor(Val, ConstFoundBucket); + FoundBucket = const_cast<BucketT *>(ConstFoundBucket); + return Result; + } + +public: + /// Return the approximate size (in bytes) of the actual map. + /// This is just the raw memory used by DenseMap. + /// If entries are pointers to objects, the size of the referenced objects + /// are not included. + size_t getMemorySize() const { + return getNumBuckets() * sizeof(BucketT); + } +}; + +/// Equality comparison for DenseMap. +/// +/// Iterates over elements of LHS confirming that each (key, value) pair in LHS +/// is also in RHS, and that no additional pairs are in RHS. +/// Equivalent to N calls to RHS.find and N value comparisons. Amortized +/// complexity is linear, worst case is O(N^2) (if every hash collides). +template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, + typename BucketT> +bool operator==( + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS, + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) { + if (LHS.size() != RHS.size()) + return false; + + for (auto &KV : LHS) { + auto I = RHS.find(KV.first); + if (I == RHS.end() || I->second != KV.second) + return false; + } + + return true; +} + +/// Inequality comparison for DenseMap. +/// +/// Equivalent to !(LHS == RHS). See operator== for performance notes. +template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, + typename BucketT> +bool operator!=( + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS, + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) { + return !(LHS == RHS); +} + +template <typename KeyT, typename ValueT, + typename KeyInfoT = DenseMapInfo<KeyT>, + typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>> +class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>, + KeyT, ValueT, KeyInfoT, BucketT> { + friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + // Lift some types from the dependent base class into this class for + // simplicity of referring to them. + using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + BucketT *Buckets; + unsigned NumEntries; + unsigned NumTombstones; + unsigned NumBuckets; + +public: + /// Create a DenseMap wth an optional \p InitialReserve that guarantee that + /// this number of elements can be inserted in the map without grow() + explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); } + + DenseMap(const DenseMap &other) : BaseT() { + init(0); + copyFrom(other); + } + + DenseMap(DenseMap &&other) : BaseT() { + init(0); + swap(other); + } + + template<typename InputIt> + DenseMap(const InputIt &I, const InputIt &E) { + init(std::distance(I, E)); + this->insert(I, E); + } + + DenseMap(std::initializer_list<typename BaseT::value_type> Vals) { + init(Vals.size()); + this->insert(Vals.begin(), Vals.end()); + } + + ~DenseMap() { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT)); + } + + void swap(DenseMap& RHS) { + this->incrementEpoch(); + RHS.incrementEpoch(); + std::swap(Buckets, RHS.Buckets); + std::swap(NumEntries, RHS.NumEntries); + std::swap(NumTombstones, RHS.NumTombstones); + std::swap(NumBuckets, RHS.NumBuckets); + } + + DenseMap& operator=(const DenseMap& other) { + if (&other != this) + copyFrom(other); + return *this; + } + + DenseMap& operator=(DenseMap &&other) { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT)); + init(0); + swap(other); + return *this; + } + + void copyFrom(const DenseMap& other) { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT)); + if (allocateBuckets(other.NumBuckets)) { + this->BaseT::copyFrom(other); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void init(unsigned InitNumEntries) { + auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries); + if (allocateBuckets(InitBuckets)) { + this->BaseT::initEmpty(); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void grow(unsigned AtLeast) { + unsigned OldNumBuckets = NumBuckets; + BucketT *OldBuckets = Buckets; + + allocateBuckets(std::max<unsigned>(64, static_cast<unsigned>(NextPowerOf2(AtLeast-1)))); + assert(Buckets); + if (!OldBuckets) { + this->BaseT::initEmpty(); + return; + } + + this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets); + + // Free the old table. + deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets, + alignof(BucketT)); + } + + void shrink_and_clear() { + unsigned OldNumBuckets = NumBuckets; + unsigned OldNumEntries = NumEntries; + this->destroyAll(); + + // Reduce the number of buckets. + unsigned NewNumBuckets = 0; + if (OldNumEntries) + NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1)); + if (NewNumBuckets == NumBuckets) { + this->BaseT::initEmpty(); + return; + } + + deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets, + alignof(BucketT)); + init(NewNumBuckets); + } + +private: + unsigned getNumEntries() const { + return NumEntries; + } + + void setNumEntries(unsigned Num) { + NumEntries = Num; + } + + unsigned getNumTombstones() const { + return NumTombstones; + } + + void setNumTombstones(unsigned Num) { + NumTombstones = Num; + } + + BucketT *getBuckets() const { + return Buckets; + } + + unsigned getNumBuckets() const { + return NumBuckets; + } + + bool allocateBuckets(unsigned Num) { + NumBuckets = Num; + if (NumBuckets == 0) { + Buckets = nullptr; + return false; + } + + Buckets = static_cast<BucketT *>( + allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT))); + return true; + } +}; + +template <typename KeyT, typename ValueT, unsigned InlineBuckets = 4, + typename KeyInfoT = DenseMapInfo<KeyT>, + typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>> +class SmallDenseMap + : public DenseMapBase< + SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT, + ValueT, KeyInfoT, BucketT> { + friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + // Lift some types from the dependent base class into this class for + // simplicity of referring to them. + using BaseT = DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + static_assert(isPowerOf2_64(InlineBuckets), + "InlineBuckets must be a power of 2."); + + unsigned Small : 1; + unsigned NumEntries : 31; + unsigned NumTombstones; + + struct LargeRep { + BucketT *Buckets; + unsigned NumBuckets; + }; + + /// A "union" of an inline bucket array and the struct representing + /// a large bucket. This union will be discriminated by the 'Small' bit. + AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage; + +public: + explicit SmallDenseMap(unsigned NumInitBuckets = 0) { + init(NumInitBuckets); + } + + SmallDenseMap(const SmallDenseMap &other) : BaseT() { + init(0); + copyFrom(other); + } + + SmallDenseMap(SmallDenseMap &&other) : BaseT() { + init(0); + swap(other); + } + + template<typename InputIt> + SmallDenseMap(const InputIt &I, const InputIt &E) { + init(NextPowerOf2(std::distance(I, E))); + this->insert(I, E); + } + + ~SmallDenseMap() { + this->destroyAll(); + deallocateBuckets(); + } + + void swap(SmallDenseMap& RHS) { + unsigned TmpNumEntries = RHS.NumEntries; + RHS.NumEntries = NumEntries; + NumEntries = TmpNumEntries; + std::swap(NumTombstones, RHS.NumTombstones); + + const KeyT EmptyKey = this->getEmptyKey(); + const KeyT TombstoneKey = this->getTombstoneKey(); + if (Small && RHS.Small) { + // If we're swapping inline bucket arrays, we have to cope with some of + // the tricky bits of DenseMap's storage system: the buckets are not + // fully initialized. Thus we swap every key, but we may have + // a one-directional move of the value. + for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { + BucketT *LHSB = &getInlineBuckets()[i], + *RHSB = &RHS.getInlineBuckets()[i]; + bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(LHSB->getFirst(), TombstoneKey)); + bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(RHSB->getFirst(), TombstoneKey)); + if (hasLHSValue && hasRHSValue) { + // Swap together if we can... + std::swap(*LHSB, *RHSB); + continue; + } + // Swap separately and handle any assymetry. + std::swap(LHSB->getFirst(), RHSB->getFirst()); + if (hasLHSValue) { + ::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond())); + LHSB->getSecond().~ValueT(); + } else if (hasRHSValue) { + ::new (&LHSB->getSecond()) ValueT(std::move(RHSB->getSecond())); + RHSB->getSecond().~ValueT(); + } + } + return; + } + if (!Small && !RHS.Small) { + std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets); + std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets); + return; + } + + SmallDenseMap &SmallSide = Small ? *this : RHS; + SmallDenseMap &LargeSide = Small ? RHS : *this; + + // First stash the large side's rep and move the small side across. + LargeRep TmpRep = std::move(*LargeSide.getLargeRep()); + LargeSide.getLargeRep()->~LargeRep(); + LargeSide.Small = true; + // This is similar to the standard move-from-old-buckets, but the bucket + // count hasn't actually rotated in this case. So we have to carefully + // move construct the keys and values into their new locations, but there + // is no need to re-hash things. + for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { + BucketT *NewB = &LargeSide.getInlineBuckets()[i], + *OldB = &SmallSide.getInlineBuckets()[i]; + ::new (&NewB->getFirst()) KeyT(std::move(OldB->getFirst())); + OldB->getFirst().~KeyT(); + if (!KeyInfoT::isEqual(NewB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(NewB->getFirst(), TombstoneKey)) { + ::new (&NewB->getSecond()) ValueT(std::move(OldB->getSecond())); + OldB->getSecond().~ValueT(); + } + } + + // The hard part of moving the small buckets across is done, just move + // the TmpRep into its new home. + SmallSide.Small = false; + new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep)); + } + + SmallDenseMap& operator=(const SmallDenseMap& other) { + if (&other != this) + copyFrom(other); + return *this; + } + + SmallDenseMap& operator=(SmallDenseMap &&other) { + this->destroyAll(); + deallocateBuckets(); + init(0); + swap(other); + return *this; + } + + void copyFrom(const SmallDenseMap& other) { + this->destroyAll(); + deallocateBuckets(); + Small = true; + if (other.getNumBuckets() > InlineBuckets) { + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets())); + } + this->BaseT::copyFrom(other); + } + + void init(unsigned InitBuckets) { + Small = true; + if (InitBuckets > InlineBuckets) { + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets)); + } + this->BaseT::initEmpty(); + } + + void grow(unsigned AtLeast) { + if (AtLeast >= InlineBuckets) + AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1)); + + if (Small) { + if (AtLeast < InlineBuckets) + return; // Nothing to do. + + // First move the inline buckets into a temporary storage. + AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage; + BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer); + BucketT *TmpEnd = TmpBegin; + + // Loop over the buckets, moving non-empty, non-tombstones into the + // temporary storage. Have the loop move the TmpEnd forward as it goes. + const KeyT EmptyKey = this->getEmptyKey(); + const KeyT TombstoneKey = this->getTombstoneKey(); + for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) { + assert(size_t(TmpEnd - TmpBegin) < InlineBuckets && + "Too many inline buckets!"); + ::new (&TmpEnd->getFirst()) KeyT(std::move(P->getFirst())); + ::new (&TmpEnd->getSecond()) ValueT(std::move(P->getSecond())); + ++TmpEnd; + P->getSecond().~ValueT(); + } + P->getFirst().~KeyT(); + } + + // Now make this map use the large rep, and move all the entries back + // into it. + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); + this->moveFromOldBuckets(TmpBegin, TmpEnd); + return; + } + + LargeRep OldRep = std::move(*getLargeRep()); + getLargeRep()->~LargeRep(); + if (AtLeast <= InlineBuckets) { + Small = true; + } else { + new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); + } + + this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets); + + // Free the old table. + deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets, + alignof(BucketT)); + } + + void shrink_and_clear() { + unsigned OldSize = this->size(); + this->destroyAll(); + + // Reduce the number of buckets. + unsigned NewNumBuckets = 0; + if (OldSize) { + NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1); + if (NewNumBuckets > InlineBuckets && NewNumBuckets < 64u) + NewNumBuckets = 64; + } + if ((Small && NewNumBuckets <= InlineBuckets) || + (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) { + this->BaseT::initEmpty(); + return; + } + + deallocateBuckets(); + init(NewNumBuckets); + } + +private: + unsigned getNumEntries() const { + return NumEntries; + } + + void setNumEntries(unsigned Num) { + // NumEntries is hardcoded to be 31 bits wide. + assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries"); + NumEntries = Num; + } + + unsigned getNumTombstones() const { + return NumTombstones; + } + + void setNumTombstones(unsigned Num) { + NumTombstones = Num; + } + + const BucketT *getInlineBuckets() const { + assert(Small); + // Note that this cast does not violate aliasing rules as we assert that + // the memory's dynamic type is the small, inline bucket buffer, and the + // 'storage.buffer' static type is 'char *'. + return reinterpret_cast<const BucketT *>(storage.buffer); + } + + BucketT *getInlineBuckets() { + return const_cast<BucketT *>( + const_cast<const SmallDenseMap *>(this)->getInlineBuckets()); + } + + const LargeRep *getLargeRep() const { + assert(!Small); + // Note, same rule about aliasing as with getInlineBuckets. + return reinterpret_cast<const LargeRep *>(storage.buffer); + } + + LargeRep *getLargeRep() { + return const_cast<LargeRep *>( + const_cast<const SmallDenseMap *>(this)->getLargeRep()); + } + + const BucketT *getBuckets() const { + return Small ? getInlineBuckets() : getLargeRep()->Buckets; + } + + BucketT *getBuckets() { + return const_cast<BucketT *>( + const_cast<const SmallDenseMap *>(this)->getBuckets()); + } + + unsigned getNumBuckets() const { + return Small ? InlineBuckets : getLargeRep()->NumBuckets; + } + + void deallocateBuckets() { + if (Small) + return; + + deallocate_buffer(getLargeRep()->Buckets, + sizeof(BucketT) * getLargeRep()->NumBuckets, + alignof(BucketT)); + getLargeRep()->~LargeRep(); + } + + LargeRep allocateBuckets(unsigned Num) { + assert(Num > InlineBuckets && "Must allocate more buckets than are inline"); + LargeRep Rep = {static_cast<BucketT *>(allocate_buffer( + sizeof(BucketT) * Num, alignof(BucketT))), + Num}; + return Rep; + } +}; + +template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket, + bool IsConst> +class DenseMapIterator : DebugEpochBase::HandleBase { + friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>; + friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>; + + using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>; + +public: + using difference_type = ptrdiff_t; + using value_type = + typename std::conditional<IsConst, const Bucket, Bucket>::type; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; + +private: + pointer Ptr = nullptr; + pointer End = nullptr; + +public: + DenseMapIterator() = default; + + DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch, + bool NoAdvance = false) + : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) { + assert(isHandleInSync() && "invalid construction!"); + + if (NoAdvance) return; + if (shouldReverseIterate<KeyT>()) { + RetreatPastEmptyBuckets(); + return; + } + AdvancePastEmptyBuckets(); + } + + // Converting ctor from non-const iterators to const iterators. SFINAE'd out + // for const iterator destinations so it doesn't end up as a user defined copy + // constructor. + template <bool IsConstSrc, + typename = typename std::enable_if<!IsConstSrc && IsConst>::type> + DenseMapIterator( + const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I) + : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {} + + reference operator*() const { + assert(isHandleInSync() && "invalid iterator access!"); + if (shouldReverseIterate<KeyT>()) + return Ptr[-1]; + return *Ptr; + } + pointer operator->() const { + assert(isHandleInSync() && "invalid iterator access!"); + if (shouldReverseIterate<KeyT>()) + return &(Ptr[-1]); + return Ptr; + } + + bool operator==(const ConstIterator &RHS) const { + assert((!Ptr || isHandleInSync()) && "handle not in sync!"); + assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!"); + assert(getEpochAddress() == RHS.getEpochAddress() && + "comparing incomparable iterators!"); + return Ptr == RHS.Ptr; + } + bool operator!=(const ConstIterator &RHS) const { + assert((!Ptr || isHandleInSync()) && "handle not in sync!"); + assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!"); + assert(getEpochAddress() == RHS.getEpochAddress() && + "comparing incomparable iterators!"); + return Ptr != RHS.Ptr; + } + + inline DenseMapIterator& operator++() { // Preincrement + assert(isHandleInSync() && "invalid iterator access!"); + if (shouldReverseIterate<KeyT>()) { + --Ptr; + RetreatPastEmptyBuckets(); + return *this; + } + ++Ptr; + AdvancePastEmptyBuckets(); + return *this; + } + DenseMapIterator operator++(int) { // Postincrement + assert(isHandleInSync() && "invalid iterator access!"); + DenseMapIterator tmp = *this; ++*this; return tmp; + } + +private: + void AdvancePastEmptyBuckets() { + assert(Ptr <= End); + const KeyT Empty = KeyInfoT::getEmptyKey(); + const KeyT Tombstone = KeyInfoT::getTombstoneKey(); + + while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) || + KeyInfoT::isEqual(Ptr->getFirst(), Tombstone))) + ++Ptr; + } + + void RetreatPastEmptyBuckets() { + assert(Ptr >= End); + const KeyT Empty = KeyInfoT::getEmptyKey(); + const KeyT Tombstone = KeyInfoT::getTombstoneKey(); + + while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) || + KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone))) + --Ptr; + } +}; + +template <typename KeyT, typename ValueT, typename KeyInfoT> +inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) { + return X.getMemorySize(); +} + +} // end namespace llvm + +#endif // LLVM_ADT_DENSEMAP_H diff --git a/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h b/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h new file mode 100644 index 000000000..bd4c60c8f --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h @@ -0,0 +1,300 @@ +//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines DenseMapInfo traits for DenseMap. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_DENSEMAPINFO_H +#define LLVM_ADT_DENSEMAPINFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/TypeSize.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <utility> + +namespace llvm { + +template<typename T> +struct DenseMapInfo { + //static inline T getEmptyKey(); + //static inline T getTombstoneKey(); + //static unsigned getHashValue(const T &Val); + //static bool isEqual(const T &LHS, const T &RHS); +}; + +// Provide DenseMapInfo for all pointers. +template<typename T> +struct DenseMapInfo<T*> { + static inline T* getEmptyKey() { + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable; + return reinterpret_cast<T*>(Val); + } + + static inline T* getTombstoneKey() { + uintptr_t Val = static_cast<uintptr_t>(-2); + Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable; + return reinterpret_cast<T*>(Val); + } + + static unsigned getHashValue(const T *PtrVal) { + return (unsigned((uintptr_t)PtrVal) >> 4) ^ + (unsigned((uintptr_t)PtrVal) >> 9); + } + + static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; } +}; + +// Provide DenseMapInfo for chars. +template<> struct DenseMapInfo<char> { + static inline char getEmptyKey() { return ~0; } + static inline char getTombstoneKey() { return ~0 - 1; } + static unsigned getHashValue(const char& Val) { return Val * 37U; } + + static bool isEqual(const char &LHS, const char &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned chars. +template <> struct DenseMapInfo<unsigned char> { + static inline unsigned char getEmptyKey() { return ~0; } + static inline unsigned char getTombstoneKey() { return ~0 - 1; } + static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; } + + static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) { + return LHS == RHS; + } +}; + +// 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; } + static inline unsigned getTombstoneKey() { return ~0U - 1; } + static unsigned getHashValue(const unsigned& Val) { return Val * 37U; } + + static bool isEqual(const unsigned& LHS, const unsigned& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned longs. +template<> struct DenseMapInfo<unsigned long> { + static inline unsigned long getEmptyKey() { return ~0UL; } + static inline unsigned long getTombstoneKey() { return ~0UL - 1L; } + + static unsigned getHashValue(const unsigned long& Val) { + return (unsigned)(Val * 37UL); + } + + static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned long longs. +template<> struct DenseMapInfo<unsigned long long> { + static inline unsigned long long getEmptyKey() { return ~0ULL; } + static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; } + + static unsigned getHashValue(const unsigned long long& Val) { + return (unsigned)(Val * 37ULL); + } + + static bool isEqual(const unsigned long long& LHS, + const unsigned long long& RHS) { + return LHS == RHS; + } +}; + +// 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; } + static inline int getTombstoneKey() { return -0x7fffffff - 1; } + static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); } + + static bool isEqual(const int& LHS, const int& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for longs. +template<> struct DenseMapInfo<long> { + static inline long getEmptyKey() { + return (1UL << (sizeof(long) * 8 - 1)) - 1UL; + } + + static inline long getTombstoneKey() { return getEmptyKey() - 1L; } + + static unsigned getHashValue(const long& Val) { + return (unsigned)(Val * 37UL); + } + + static bool isEqual(const long& LHS, const long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for long longs. +template<> struct DenseMapInfo<long long> { + static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; } + static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; } + + static unsigned getHashValue(const long long& Val) { + return (unsigned)(Val * 37ULL); + } + + static bool isEqual(const long long& LHS, + const long long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for all pairs whose members have info. +template<typename T, typename U> +struct DenseMapInfo<std::pair<T, U>> { + using Pair = std::pair<T, U>; + using FirstInfo = DenseMapInfo<T>; + using SecondInfo = DenseMapInfo<U>; + + static inline Pair getEmptyKey() { + return std::make_pair(FirstInfo::getEmptyKey(), + SecondInfo::getEmptyKey()); + } + + static inline Pair getTombstoneKey() { + return std::make_pair(FirstInfo::getTombstoneKey(), + SecondInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const Pair& PairVal) { + uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32 + | (uint64_t)SecondInfo::getHashValue(PairVal.second); + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + return (unsigned)key; + } + + static bool isEqual(const Pair &LHS, const Pair &RHS) { + return FirstInfo::isEqual(LHS.first, RHS.first) && + SecondInfo::isEqual(LHS.second, RHS.second); + } +}; + +// Provide DenseMapInfo for StringRefs. +template <> struct DenseMapInfo<StringRef> { + static inline StringRef getEmptyKey() { + return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)), + 0); + } + + static inline StringRef getTombstoneKey() { + return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)), + 0); + } + + static unsigned getHashValue(StringRef Val) { + assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!"); + assert(Val.data() != getTombstoneKey().data() && + "Cannot hash the tombstone key!"); + return (unsigned)(hash_value(Val)); + } + + static bool isEqual(StringRef LHS, StringRef RHS) { + if (RHS.data() == getEmptyKey().data()) + return LHS.data() == getEmptyKey().data(); + if (RHS.data() == getTombstoneKey().data()) + return LHS.data() == getTombstoneKey().data(); + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for ArrayRefs. +template <typename T> struct DenseMapInfo<ArrayRef<T>> { + static inline ArrayRef<T> getEmptyKey() { + return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)), + size_t(0)); + } + + static inline ArrayRef<T> getTombstoneKey() { + return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)), + size_t(0)); + } + + static unsigned getHashValue(ArrayRef<T> Val) { + assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!"); + assert(Val.data() != getTombstoneKey().data() && + "Cannot hash the tombstone key!"); + return (unsigned)(hash_value(Val)); + } + + static bool isEqual(ArrayRef<T> LHS, ArrayRef<T> RHS) { + if (RHS.data() == getEmptyKey().data()) + return LHS.data() == getEmptyKey().data(); + if (RHS.data() == getTombstoneKey().data()) + return LHS.data() == getTombstoneKey().data(); + return LHS == RHS; + } +}; + +template <> struct DenseMapInfo<hash_code> { + static inline hash_code getEmptyKey() { return hash_code(-1); } + static inline hash_code getTombstoneKey() { return hash_code(-2); } + static unsigned getHashValue(hash_code val) { return val; } + static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; } +}; + +template <> struct DenseMapInfo<ElementCount> { + static inline ElementCount getEmptyKey() { return {~0U, true}; } + static inline ElementCount getTombstoneKey() { return {~0U - 1, false}; } + static unsigned getHashValue(const ElementCount& EltCnt) { + if (EltCnt.Scalable) + return (EltCnt.Min * 37U) - 1U; + + return EltCnt.Min * 37U; + } + + static bool isEqual(const ElementCount& LHS, const ElementCount& RHS) { + return LHS == RHS; + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_DENSEMAPINFO_H diff --git a/third_party/llvm-project/include/llvm/ADT/DenseSet.h b/third_party/llvm-project/include/llvm/ADT/DenseSet.h new file mode 100644 index 000000000..9afb715ae --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/DenseSet.h @@ -0,0 +1,283 @@ +//===- llvm/ADT/DenseSet.h - Dense probed hash table ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the DenseSet and SmallDenseSet classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_DENSESET_H +#define LLVM_ADT_DENSESET_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/type_traits.h" +#include <algorithm> +#include <cstddef> +#include <initializer_list> +#include <iterator> +#include <utility> + +namespace llvm { + +namespace detail { + +struct DenseSetEmpty {}; + +// Use the empty base class trick so we can create a DenseMap where the buckets +// contain only a single item. +template <typename KeyT> class DenseSetPair : public DenseSetEmpty { + KeyT key; + +public: + KeyT &getFirst() { return key; } + const KeyT &getFirst() const { return key; } + DenseSetEmpty &getSecond() { return *this; } + const DenseSetEmpty &getSecond() const { return *this; } +}; + +/// Base class for DenseSet and DenseSmallSet. +/// +/// MapTy should be either +/// +/// DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT, +/// detail::DenseSetPair<ValueT>> +/// +/// or the equivalent SmallDenseMap type. ValueInfoT must implement the +/// DenseMapInfo "concept". +template <typename ValueT, typename MapTy, typename ValueInfoT> +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: + using key_type = ValueT; + using value_type = ValueT; + using size_type = unsigned; + + explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {} + + DenseSetImpl(std::initializer_list<ValueT> Elems) + : DenseSetImpl(PowerOf2Ceil(Elems.size())) { + insert(Elems.begin(), Elems.end()); + } + + bool empty() const { return TheMap.empty(); } + size_type size() const { return TheMap.size(); } + size_t getMemorySize() const { return TheMap.getMemorySize(); } + + /// Grow the DenseSet so that it has at least Size buckets. Will not shrink + /// the Size of the set. + void resize(size_t Size) { TheMap.resize(Size); } + + /// Grow the DenseSet so that it can contain at least \p NumEntries items + /// before resizing again. + void reserve(size_t Size) { TheMap.reserve(Size); } + + void clear() { + TheMap.clear(); + } + + /// Return 1 if the specified key is in the set, 0 otherwise. + size_type count(const_arg_type_t<ValueT> V) const { + return TheMap.count(V); + } + + bool erase(const ValueT &V) { + return TheMap.erase(V); + } + + void swap(DenseSetImpl &RHS) { TheMap.swap(RHS.TheMap); } + + // Iterators. + + class ConstIterator; + + class Iterator { + typename MapTy::iterator I; + friend class DenseSetImpl; + friend class ConstIterator; + + public: + using difference_type = typename MapTy::iterator::difference_type; + using value_type = ValueT; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; + + 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 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 DenseSetImpl; + friend class Iterator; + + public: + using difference_type = typename MapTy::const_iterator::difference_type; + using value_type = ValueT; + using pointer = const value_type *; + using reference = const value_type &; + using iterator_category = std::forward_iterator_tag; + + ConstIterator() = default; + ConstIterator(const Iterator &B) : I(B.I) {} + ConstIterator(const typename MapTy::const_iterator &i) : I(i) {} + + 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; } + bool operator==(const ConstIterator& X) const { return I == X.I; } + bool operator!=(const ConstIterator& X) const { return I != X.I; } + }; + + using iterator = Iterator; + using const_iterator = ConstIterator; + + iterator begin() { return Iterator(TheMap.begin()); } + iterator end() { return Iterator(TheMap.end()); } + + const_iterator begin() const { return ConstIterator(TheMap.begin()); } + const_iterator end() const { return ConstIterator(TheMap.end()); } + + 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)); + } + + /// Alternative version of find() which allows a different, and possibly less + /// expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key type + /// used. + template <class LookupKeyT> + iterator find_as(const LookupKeyT &Val) { + return Iterator(TheMap.find_as(Val)); + } + template <class LookupKeyT> + const_iterator find_as(const LookupKeyT &Val) const { + return ConstIterator(TheMap.find_as(Val)); + } + + void erase(Iterator I) { return TheMap.erase(I.I); } + void erase(ConstIterator CI) { return TheMap.erase(CI.I); } + + std::pair<iterator, bool> insert(const ValueT &V) { + detail::DenseSetEmpty Empty; + return TheMap.try_emplace(V, Empty); + } + + std::pair<iterator, bool> insert(ValueT &&V) { + detail::DenseSetEmpty Empty; + return TheMap.try_emplace(std::move(V), Empty); + } + + /// Alternative version of insert that uses a different (and possibly less + /// expensive) key type. + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(const ValueT &V, + const LookupKeyT &LookupKey) { + return TheMap.insert_as({V, detail::DenseSetEmpty()}, LookupKey); + } + template <typename LookupKeyT> + std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) { + return TheMap.insert_as({std::move(V), detail::DenseSetEmpty()}, LookupKey); + } + + // Range insertion of values. + template<typename InputIt> + void insert(InputIt I, InputIt E) { + for (; I != E; ++I) + insert(*I); + } +}; + +/// Equality comparison for DenseSet. +/// +/// Iterates over elements of LHS confirming that each element is also a member +/// of RHS, and that RHS contains no additional values. +/// Equivalent to N calls to RHS.count. Amortized complexity is linear, worst +/// case is O(N^2) (if every hash collides). +template <typename ValueT, typename MapTy, typename ValueInfoT> +bool operator==(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS, + const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) { + if (LHS.size() != RHS.size()) + return false; + + for (auto &E : LHS) + if (!RHS.count(E)) + return false; + + return true; +} + +/// Inequality comparison for DenseSet. +/// +/// Equivalent to !(LHS == RHS). See operator== for performance notes. +template <typename ValueT, typename MapTy, typename ValueInfoT> +bool operator!=(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS, + const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) { + return !(LHS == RHS); +} + +} // end namespace detail + +/// Implements a dense probed hash-table based set. +template <typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT>> +class DenseSet : public detail::DenseSetImpl< + ValueT, DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT, + detail::DenseSetPair<ValueT>>, + ValueInfoT> { + using BaseT = + detail::DenseSetImpl<ValueT, + DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT, + detail::DenseSetPair<ValueT>>, + ValueInfoT>; + +public: + using BaseT::BaseT; +}; + +/// Implements a dense probed hash-table based set with some number of buckets +/// stored inline. +template <typename ValueT, unsigned InlineBuckets = 4, + typename ValueInfoT = DenseMapInfo<ValueT>> +class SmallDenseSet + : public detail::DenseSetImpl< + ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets, + ValueInfoT, detail::DenseSetPair<ValueT>>, + ValueInfoT> { + using BaseT = detail::DenseSetImpl< + ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets, + ValueInfoT, detail::DenseSetPair<ValueT>>, + ValueInfoT>; + +public: + using BaseT::BaseT; +}; + +} // end namespace llvm + +#endif // LLVM_ADT_DENSESET_H diff --git a/third_party/llvm-project/include/llvm/ADT/EpochTracker.h b/third_party/llvm-project/include/llvm/ADT/EpochTracker.h new file mode 100644 index 000000000..a782b4756 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/EpochTracker.h @@ -0,0 +1,98 @@ +//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes. +// These can be used to write iterators that are fail-fast when LLVM is built +// with asserts enabled. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_EPOCH_TRACKER_H +#define LLVM_ADT_EPOCH_TRACKER_H + +#include "llvm/Config/abi-breaking.h" + +#include <cstdint> + +namespace llvm { + +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + +/// A base class for data structure classes wishing to make iterators +/// ("handles") pointing into themselves fail-fast. When building without +/// asserts, this class is empty and does nothing. +/// +/// DebugEpochBase does not by itself track handles pointing into itself. The +/// expectation is that routines touching the handles will poll on +/// isHandleInSync at appropriate points to assert that the handle they're using +/// is still valid. +/// +class DebugEpochBase { + uint64_t Epoch; + +public: + DebugEpochBase() : Epoch(0) {} + + /// Calling incrementEpoch invalidates all handles pointing into the + /// calling instance. + void incrementEpoch() { ++Epoch; } + + /// The destructor calls incrementEpoch to make use-after-free bugs + /// more likely to crash deterministically. + ~DebugEpochBase() { incrementEpoch(); } + + /// A base class for iterator classes ("handles") that wish to poll for + /// iterator invalidating modifications in the underlying data structure. + /// When LLVM is built without asserts, this class is empty and does nothing. + /// + /// HandleBase does not track the parent data structure by itself. It expects + /// the routines modifying the data structure to call incrementEpoch when they + /// make an iterator-invalidating modification. + /// + class HandleBase { + const uint64_t *EpochAddress; + uint64_t EpochAtCreation; + + public: + HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {} + + explicit HandleBase(const DebugEpochBase *Parent) + : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {} + + /// Returns true if the DebugEpochBase this Handle is linked to has + /// not called incrementEpoch on itself since the creation of this + /// HandleBase instance. + bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; } + + /// Returns a pointer to the epoch word stored in the data structure + /// this handle points into. Can be used to check if two iterators point + /// into the same data structure. + const void *getEpochAddress() const { return EpochAddress; } + }; +}; + +#else + +class DebugEpochBase { +public: + void incrementEpoch() {} + + class HandleBase { + public: + HandleBase() = default; + explicit HandleBase(const DebugEpochBase *) {} + bool isHandleInSync() const { return true; } + const void *getEpochAddress() const { return nullptr; } + }; +}; + +#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/FoldingSet.h b/third_party/llvm-project/include/llvm/ADT/FoldingSet.h new file mode 100644 index 000000000..d5837e51b --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/FoldingSet.h @@ -0,0 +1,761 @@ +//===- llvm/ADT/FoldingSet.h - Uniquing Hash Set ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a hash set that can be used to remove duplication of nodes +// in a graph. This code was originally created by Chris Lattner for use with +// SelectionDAGCSEMap, but was isolated to provide use across the llvm code set. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_FOLDINGSET_H +#define LLVM_ADT_FOLDINGSET_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <utility> + +namespace llvm { + +/// This folding set used for two purposes: +/// 1. Given information about a node we want to create, look up the unique +/// instance of the node in the set. If the node already exists, return +/// it, otherwise return the bucket it should be inserted into. +/// 2. Given a node that has already been created, remove it from the set. +/// +/// This class is implemented as a single-link chained hash table, where the +/// "buckets" are actually the nodes themselves (the next pointer is in the +/// node). The last node points back to the bucket to simplify node removal. +/// +/// Any node that is to be included in the folding set must be a subclass of +/// FoldingSetNode. The node class must also define a Profile method used to +/// establish the unique bits of data for the node. The Profile method is +/// passed a FoldingSetNodeID object which is used to gather the bits. Just +/// call one of the Add* functions defined in the FoldingSetBase::NodeID class. +/// NOTE: That the folding set does not own the nodes and it is the +/// responsibility of the user to dispose of the nodes. +/// +/// Eg. +/// class MyNode : public FoldingSetNode { +/// private: +/// std::string Name; +/// unsigned Value; +/// public: +/// MyNode(const char *N, unsigned V) : Name(N), Value(V) {} +/// ... +/// void Profile(FoldingSetNodeID &ID) const { +/// ID.AddString(Name); +/// ID.AddInteger(Value); +/// } +/// ... +/// }; +/// +/// To define the folding set itself use the FoldingSet template; +/// +/// Eg. +/// FoldingSet<MyNode> MyFoldingSet; +/// +/// Four public methods are available to manipulate the folding set; +/// +/// 1) If you have an existing node that you want add to the set but unsure +/// that the node might already exist then call; +/// +/// MyNode *M = MyFoldingSet.GetOrInsertNode(N); +/// +/// If The result is equal to the input then the node has been inserted. +/// Otherwise, the result is the node existing in the folding set, and the +/// input can be discarded (use the result instead.) +/// +/// 2) If you are ready to construct a node but want to check if it already +/// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to +/// check; +/// +/// FoldingSetNodeID ID; +/// ID.AddString(Name); +/// ID.AddInteger(Value); +/// void *InsertPoint; +/// +/// MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint); +/// +/// If found then M with be non-NULL, else InsertPoint will point to where it +/// should be inserted using InsertNode. +/// +/// 3) If you get a NULL result from FindNodeOrInsertPos then you can as a new +/// node with FindNodeOrInsertPos; +/// +/// InsertNode(N, InsertPoint); +/// +/// 4) Finally, if you want to remove a node from the folding set call; +/// +/// bool WasRemoved = RemoveNode(N); +/// +/// The result indicates whether the node existed in the folding set. + +class FoldingSetNodeID; +class StringRef; + +//===----------------------------------------------------------------------===// +/// FoldingSetBase - Implements the folding set functionality. The main +/// structure is an array of buckets. Each bucket is indexed by the hash of +/// the nodes it contains. The bucket itself points to the nodes contained +/// in the bucket via a singly linked list. The last node in the list points +/// back to the bucket to facilitate node removal. +/// +class FoldingSetBase { + virtual void anchor(); // Out of line virtual method. + +protected: + /// Buckets - Array of bucket chains. + void **Buckets; + + /// NumBuckets - Length of the Buckets array. Always a power of 2. + unsigned NumBuckets; + + /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes + /// is greater than twice the number of buckets. + unsigned NumNodes; + + explicit FoldingSetBase(unsigned Log2InitSize = 6); + FoldingSetBase(FoldingSetBase &&Arg); + FoldingSetBase &operator=(FoldingSetBase &&RHS); + ~FoldingSetBase(); + +public: + //===--------------------------------------------------------------------===// + /// Node - This class is used to maintain the singly linked bucket list in + /// a folding set. + class Node { + private: + // NextInFoldingSetBucket - next link in the bucket list. + void *NextInFoldingSetBucket = nullptr; + + public: + Node() = default; + + // Accessors + void *getNextInBucket() const { return NextInFoldingSetBucket; } + void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; } + }; + + /// clear - Remove all nodes from the folding set. + void clear(); + + /// size - Returns the number of nodes in the folding set. + unsigned size() const { return NumNodes; } + + /// empty - Returns true if there are no nodes in the folding set. + bool empty() const { return NumNodes == 0; } + + /// reserve - Increase the number of buckets such that adding the + /// EltCount-th node won't cause a rebucket operation. reserve is permitted + /// to allocate more space than requested by EltCount. + void reserve(unsigned EltCount); + + /// capacity - Returns the number of nodes permitted in the folding set + /// before a rebucket operation is performed. + unsigned capacity() { + // We allow a load factor of up to 2.0, + // so that means our capacity is NumBuckets * 2 + return NumBuckets * 2; + } + +private: + /// GrowHashTable - Double the size of the hash table and rehash everything. + void GrowHashTable(); + + /// GrowBucketCount - resize the hash table and rehash everything. + /// NewBucketCount must be a power of two, and must be greater than the old + /// bucket count. + void GrowBucketCount(unsigned NewBucketCount); + +protected: + /// GetNodeProfile - Instantiations of the FoldingSet template implement + /// this function to gather data bits for the given node. + virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const = 0; + + /// NodeEquals - Instantiations of the FoldingSet template implement + /// this function to compare the given node with the given ID. + virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) const=0; + + /// ComputeNodeHash - Instantiations of the FoldingSet template implement + /// this function to compute a hash value for the given node. + virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0; + + // The below methods are protected to encourage subclasses to provide a more + // type-safe API. + + /// RemoveNode - Remove a node from the folding set, returning true if one + /// was removed or false if the node was not in the folding set. + bool RemoveNode(Node *N); + + /// GetOrInsertNode - If there is an existing simple Node exactly + /// equal to the specified node, return it. Otherwise, insert 'N' and return + /// it instead. + Node *GetOrInsertNode(Node *N); + + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, + /// return it. If not, return the insertion token that will make insertion + /// faster. + Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos); + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. InsertPos must be obtained from + /// FindNodeOrInsertPos. + void InsertNode(Node *N, void *InsertPos); +}; + +//===----------------------------------------------------------------------===// + +/// DefaultFoldingSetTrait - This class provides default implementations +/// for FoldingSetTrait implementations. +template<typename T> struct DefaultFoldingSetTrait { + static void Profile(const T &X, FoldingSetNodeID &ID) { + X.Profile(ID); + } + static void Profile(T &X, FoldingSetNodeID &ID) { + X.Profile(ID); + } + + // Equals - Test if the profile for X would match ID, using TempID + // to compute a temporary ID if necessary. The default implementation + // just calls Profile and does a regular comparison. Implementations + // can override this to provide more efficient implementations. + static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID); + + // ComputeHash - Compute a hash value for X, using TempID to + // compute a temporary ID if necessary. The default implementation + // just calls Profile and does a regular hash computation. + // Implementations can override this to provide more efficient + // implementations. + static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID); +}; + +/// FoldingSetTrait - This trait class is used to define behavior of how +/// to "profile" (in the FoldingSet parlance) an object of a given type. +/// The default behavior is to invoke a 'Profile' method on an object, but +/// through template specialization the behavior can be tailored for specific +/// types. Combined with the FoldingSetNodeWrapper class, one can add objects +/// to FoldingSets that were not originally designed to have that behavior. +template<typename T> struct FoldingSetTrait + : public DefaultFoldingSetTrait<T> {}; + +/// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but +/// for ContextualFoldingSets. +template<typename T, typename Ctx> +struct DefaultContextualFoldingSetTrait { + static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) { + X.Profile(ID, Context); + } + + static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID, Ctx Context); + static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID, + Ctx Context); +}; + +/// ContextualFoldingSetTrait - Like FoldingSetTrait, but for +/// ContextualFoldingSets. +template<typename T, typename Ctx> struct ContextualFoldingSetTrait + : public DefaultContextualFoldingSetTrait<T, Ctx> {}; + +//===--------------------------------------------------------------------===// +/// FoldingSetNodeIDRef - This class describes a reference to an interned +/// FoldingSetNodeID, which can be a useful to store node id data rather +/// than using plain FoldingSetNodeIDs, since the 32-element SmallVector +/// is often much larger than necessary, and the possibility of heap +/// allocation means it requires a non-trivial destructor call. +class FoldingSetNodeIDRef { + const unsigned *Data = nullptr; + size_t Size = 0; + +public: + FoldingSetNodeIDRef() = default; + FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {} + + /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, + /// used to lookup the node in the FoldingSetBase. + unsigned ComputeHash() const; + + bool operator==(FoldingSetNodeIDRef) const; + + bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); } + + /// Used to compare the "ordering" of two nodes as defined by the + /// profiled bits and their ordering defined by memcmp(). + bool operator<(FoldingSetNodeIDRef) const; + + const unsigned *getData() const { return Data; } + size_t getSize() const { return Size; } +}; + +//===--------------------------------------------------------------------===// +/// FoldingSetNodeID - This class is used to gather all the unique data bits of +/// a node. When all the bits are gathered this class is used to produce a +/// hash value for the node. +class FoldingSetNodeID { + /// Bits - Vector of all the data bits that make the node unique. + /// Use a SmallVector to avoid a heap allocation in the common case. + SmallVector<unsigned, 32> Bits; + +public: + FoldingSetNodeID() = default; + + FoldingSetNodeID(FoldingSetNodeIDRef Ref) + : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {} + + /// Add* - Add various data types to Bit data. + void AddPointer(const void *Ptr); + void AddInteger(signed I); + void AddInteger(unsigned I); + void AddInteger(long I); + void AddInteger(unsigned long I); + void AddInteger(long long I); + void AddInteger(unsigned long long I); + void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); } + void AddString(StringRef String); + void AddNodeID(const FoldingSetNodeID &ID); + + template <typename T> + inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); } + + /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID + /// object to be used to compute a new profile. + inline void clear() { Bits.clear(); } + + /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used + /// to lookup the node in the FoldingSetBase. + unsigned ComputeHash() const; + + /// operator== - Used to compare two nodes to each other. + bool operator==(const FoldingSetNodeID &RHS) const; + bool operator==(const FoldingSetNodeIDRef RHS) const; + + bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); } + bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);} + + /// Used to compare the "ordering" of two nodes as defined by the + /// profiled bits and their ordering defined by memcmp(). + bool operator<(const FoldingSetNodeID &RHS) const; + bool operator<(const FoldingSetNodeIDRef RHS) const; + + /// Intern - Copy this node's data to a memory region allocated from the + /// given allocator and return a FoldingSetNodeIDRef describing the + /// interned data. + FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const; +}; + +// Convenience type to hide the implementation of the folding set. +using FoldingSetNode = FoldingSetBase::Node; +template<class T> class FoldingSetIterator; +template<class T> class FoldingSetBucketIterator; + +// Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which +// require the definition of FoldingSetNodeID. +template<typename T> +inline bool +DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID, + unsigned /*IDHash*/, + FoldingSetNodeID &TempID) { + FoldingSetTrait<T>::Profile(X, TempID); + return TempID == ID; +} +template<typename T> +inline unsigned +DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) { + FoldingSetTrait<T>::Profile(X, TempID); + return TempID.ComputeHash(); +} +template<typename T, typename Ctx> +inline bool +DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X, + const FoldingSetNodeID &ID, + unsigned /*IDHash*/, + FoldingSetNodeID &TempID, + Ctx Context) { + ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context); + return TempID == ID; +} +template<typename T, typename Ctx> +inline unsigned +DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X, + FoldingSetNodeID &TempID, + Ctx Context) { + ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context); + return TempID.ComputeHash(); +} + +//===----------------------------------------------------------------------===// +/// FoldingSetImpl - An implementation detail that lets us share code between +/// FoldingSet and ContextualFoldingSet. +template <class T> class FoldingSetImpl : public FoldingSetBase { +protected: + explicit FoldingSetImpl(unsigned Log2InitSize) + : FoldingSetBase(Log2InitSize) {} + + FoldingSetImpl(FoldingSetImpl &&Arg) = default; + FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default; + ~FoldingSetImpl() = default; + +public: + using iterator = FoldingSetIterator<T>; + + iterator begin() { return iterator(Buckets); } + iterator end() { return iterator(Buckets+NumBuckets); } + + using const_iterator = FoldingSetIterator<const T>; + + const_iterator begin() const { return const_iterator(Buckets); } + const_iterator end() const { return const_iterator(Buckets+NumBuckets); } + + using bucket_iterator = FoldingSetBucketIterator<T>; + + bucket_iterator bucket_begin(unsigned hash) { + return bucket_iterator(Buckets + (hash & (NumBuckets-1))); + } + + bucket_iterator bucket_end(unsigned hash) { + return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); + } + + /// RemoveNode - Remove a node from the folding set, returning true if one + /// was removed or false if the node was not in the folding set. + bool RemoveNode(T *N) { return FoldingSetBase::RemoveNode(N); } + + /// GetOrInsertNode - If there is an existing simple Node exactly + /// equal to the specified node, return it. Otherwise, insert 'N' and + /// return it instead. + T *GetOrInsertNode(T *N) { + return static_cast<T *>(FoldingSetBase::GetOrInsertNode(N)); + } + + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, + /// return it. If not, return the insertion token that will make insertion + /// faster. + T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { + return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos(ID, InsertPos)); + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. InsertPos must be obtained from + /// FindNodeOrInsertPos. + void InsertNode(T *N, void *InsertPos) { + FoldingSetBase::InsertNode(N, InsertPos); + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. + void InsertNode(T *N) { + T *Inserted = GetOrInsertNode(N); + (void)Inserted; + assert(Inserted == N && "Node already inserted!"); + } +}; + +//===----------------------------------------------------------------------===// +/// FoldingSet - This template class is used to instantiate a specialized +/// implementation of the folding set to the node class T. T must be a +/// subclass of FoldingSetNode and implement a Profile function. +/// +/// Note that this set type is movable and move-assignable. However, its +/// moved-from state is not a valid state for anything other than +/// move-assigning and destroying. This is primarily to enable movable APIs +/// that incorporate these objects. +template <class T> class FoldingSet final : public FoldingSetImpl<T> { + using Super = FoldingSetImpl<T>; + using Node = typename Super::Node; + + /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a + /// way to convert nodes into a unique specifier. + void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { + T *TN = static_cast<T *>(N); + FoldingSetTrait<T>::Profile(*TN, ID); + } + + /// NodeEquals - Instantiations may optionally provide a way to compare a + /// node with a specified ID. + bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) const override { + T *TN = static_cast<T *>(N); + return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID); + } + + /// ComputeNodeHash - Instantiations may optionally provide a way to compute a + /// hash value directly from a node. + unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override { + T *TN = static_cast<T *>(N); + return FoldingSetTrait<T>::ComputeHash(*TN, TempID); + } + +public: + explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {} + FoldingSet(FoldingSet &&Arg) = default; + FoldingSet &operator=(FoldingSet &&RHS) = default; +}; + +//===----------------------------------------------------------------------===// +/// ContextualFoldingSet - This template class is a further refinement +/// of FoldingSet which provides a context argument when calling +/// Profile on its nodes. Currently, that argument is fixed at +/// initialization time. +/// +/// T must be a subclass of FoldingSetNode and implement a Profile +/// function with signature +/// void Profile(FoldingSetNodeID &, Ctx); +template <class T, class Ctx> +class ContextualFoldingSet final : public FoldingSetImpl<T> { + // Unfortunately, this can't derive from FoldingSet<T> because the + // construction of the vtable for FoldingSet<T> requires + // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn + // requires a single-argument T::Profile(). + + using Super = FoldingSetImpl<T>; + using Node = typename Super::Node; + + Ctx Context; + + /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a + /// way to convert nodes into a unique specifier. + void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { + T *TN = static_cast<T *>(N); + ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context); + } + + bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) const override { + T *TN = static_cast<T *>(N); + return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID, + Context); + } + + unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override { + T *TN = static_cast<T *>(N); + return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context); + } + +public: + explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6) + : Super(Log2InitSize), Context(Context) {} + + Ctx getContext() const { return Context; } +}; + +//===----------------------------------------------------------------------===// +/// FoldingSetVector - This template class combines a FoldingSet and a vector +/// to provide the interface of FoldingSet but with deterministic iteration +/// order based on the insertion order. T must be a subclass of FoldingSetNode +/// and implement a Profile function. +template <class T, class VectorT = SmallVector<T*, 8>> +class FoldingSetVector { + FoldingSet<T> Set; + VectorT Vector; + +public: + explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {} + + using iterator = pointee_iterator<typename VectorT::iterator>; + + iterator begin() { return Vector.begin(); } + iterator end() { return Vector.end(); } + + using const_iterator = pointee_iterator<typename VectorT::const_iterator>; + + const_iterator begin() const { return Vector.begin(); } + const_iterator end() const { return Vector.end(); } + + /// clear - Remove all nodes from the folding set. + void clear() { Set.clear(); Vector.clear(); } + + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, + /// return it. If not, return the insertion token that will make insertion + /// faster. + T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { + return Set.FindNodeOrInsertPos(ID, InsertPos); + } + + /// GetOrInsertNode - If there is an existing simple Node exactly + /// equal to the specified node, return it. Otherwise, insert 'N' and + /// return it instead. + T *GetOrInsertNode(T *N) { + T *Result = Set.GetOrInsertNode(N); + if (Result == N) Vector.push_back(N); + return Result; + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. InsertPos must be obtained from + /// FindNodeOrInsertPos. + void InsertNode(T *N, void *InsertPos) { + Set.InsertNode(N, InsertPos); + Vector.push_back(N); + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. + void InsertNode(T *N) { + Set.InsertNode(N); + Vector.push_back(N); + } + + /// size - Returns the number of nodes in the folding set. + unsigned size() const { return Set.size(); } + + /// empty - Returns true if there are no nodes in the folding set. + bool empty() const { return Set.empty(); } +}; + +//===----------------------------------------------------------------------===// +/// FoldingSetIteratorImpl - This is the common iterator support shared by all +/// folding sets, which knows how to walk the folding set hash table. +class FoldingSetIteratorImpl { +protected: + FoldingSetNode *NodePtr; + + FoldingSetIteratorImpl(void **Bucket); + + void advance(); + +public: + bool operator==(const FoldingSetIteratorImpl &RHS) const { + return NodePtr == RHS.NodePtr; + } + bool operator!=(const FoldingSetIteratorImpl &RHS) const { + return NodePtr != RHS.NodePtr; + } +}; + +template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl { +public: + explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {} + + T &operator*() const { + return *static_cast<T*>(NodePtr); + } + + T *operator->() const { + return static_cast<T*>(NodePtr); + } + + inline FoldingSetIterator &operator++() { // Preincrement + advance(); + return *this; + } + FoldingSetIterator operator++(int) { // Postincrement + FoldingSetIterator tmp = *this; ++*this; return tmp; + } +}; + +//===----------------------------------------------------------------------===// +/// FoldingSetBucketIteratorImpl - This is the common bucket iterator support +/// shared by all folding sets, which knows how to walk a particular bucket +/// of a folding set hash table. +class FoldingSetBucketIteratorImpl { +protected: + void *Ptr; + + explicit FoldingSetBucketIteratorImpl(void **Bucket); + + FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {} + + void advance() { + void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket(); + uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1; + Ptr = reinterpret_cast<void*>(x); + } + +public: + bool operator==(const FoldingSetBucketIteratorImpl &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const { + return Ptr != RHS.Ptr; + } +}; + +template <class T> +class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl { +public: + explicit FoldingSetBucketIterator(void **Bucket) : + FoldingSetBucketIteratorImpl(Bucket) {} + + FoldingSetBucketIterator(void **Bucket, bool) : + FoldingSetBucketIteratorImpl(Bucket, true) {} + + T &operator*() const { return *static_cast<T*>(Ptr); } + T *operator->() const { return static_cast<T*>(Ptr); } + + inline FoldingSetBucketIterator &operator++() { // Preincrement + advance(); + return *this; + } + FoldingSetBucketIterator operator++(int) { // Postincrement + FoldingSetBucketIterator tmp = *this; ++*this; return tmp; + } +}; + +//===----------------------------------------------------------------------===// +/// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary +/// types in an enclosing object so that they can be inserted into FoldingSets. +template <typename T> +class FoldingSetNodeWrapper : public FoldingSetNode { + T data; + +public: + template <typename... Ts> + explicit FoldingSetNodeWrapper(Ts &&... Args) + : data(std::forward<Ts>(Args)...) {} + + void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); } + + T &getValue() { return data; } + const T &getValue() const { return data; } + + operator T&() { return data; } + operator const T&() const { return data; } +}; + +//===----------------------------------------------------------------------===// +/// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores +/// a FoldingSetNodeID value rather than requiring the node to recompute it +/// each time it is needed. This trades space for speed (which can be +/// significant if the ID is long), and it also permits nodes to drop +/// information that would otherwise only be required for recomputing an ID. +class FastFoldingSetNode : public FoldingSetNode { + FoldingSetNodeID FastID; + +protected: + explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {} + +public: + void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); } +}; + +//===----------------------------------------------------------------------===// +// Partial specializations of FoldingSetTrait. + +template<typename T> struct FoldingSetTrait<T*> { + static inline void Profile(T *X, FoldingSetNodeID &ID) { + ID.AddPointer(X); + } +}; +template <typename T1, typename T2> +struct FoldingSetTrait<std::pair<T1, T2>> { + static inline void Profile(const std::pair<T1, T2> &P, + FoldingSetNodeID &ID) { + ID.Add(P.first); + ID.Add(P.second); + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_FOLDINGSET_H diff --git a/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h b/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h new file mode 100644 index 000000000..121aa527a --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h @@ -0,0 +1,292 @@ +//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file provides a collection of function (or more generally, callable) +/// type erasure utilities supplementing those provided by the standard library +/// in `<function>`. +/// +/// It provides `unique_function`, which works like `std::function` but supports +/// move-only callable objects. +/// +/// Future plans: +/// - Add a `function` that provides const, volatile, and ref-qualified support, +/// which doesn't work with `std::function`. +/// - Provide support for specifying multiple signatures to type erase callable +/// objects with an overload set, such as those produced by generic lambdas. +/// - Expand to include a copyable utility that directly replaces std::function +/// but brings the above improvements. +/// +/// Note that LLVM's utilities are greatly simplified by not supporting +/// allocators. +/// +/// If the standard library ever begins to provide comparable facilities we can +/// consider switching to those. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_FUNCTION_EXTRAS_H +#define LLVM_ADT_FUNCTION_EXTRAS_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/type_traits.h" +#include <memory> + +namespace llvm { + +template <typename FunctionT> class unique_function; + +template <typename ReturnT, typename... ParamTs> +class unique_function<ReturnT(ParamTs...)> { + static constexpr size_t InlineStorageSize = sizeof(void *) * 3; + + // MSVC has a bug and ICEs if we give it a particular dependent value + // expression as part of the `std::conditional` below. To work around this, + // we build that into a template struct's constexpr bool. + template <typename T> struct IsSizeLessThanThresholdT { + static constexpr bool value = sizeof(T) <= (2 * sizeof(void *)); + }; + + // Provide a type function to map parameters that won't observe extra copies + // or moves and which are small enough to likely pass in register to values + // and all other types to l-value reference types. We use this to compute the + // types used in our erased call utility to minimize copies and moves unless + // doing so would force things unnecessarily into memory. + // + // The heuristic used is related to common ABI register passing conventions. + // It doesn't have to be exact though, and in one way it is more strict + // because we want to still be able to observe either moves *or* copies. + template <typename T> + using AdjustedParamT = typename std::conditional< + !std::is_reference<T>::value && + llvm::is_trivially_copy_constructible<T>::value && + llvm::is_trivially_move_constructible<T>::value && + IsSizeLessThanThresholdT<T>::value, + T, T &>::type; + + // The type of the erased function pointer we use as a callback to dispatch to + // the stored callable when it is trivial to move and destroy. + using CallPtrT = ReturnT (*)(void *CallableAddr, + AdjustedParamT<ParamTs>... Params); + using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr); + using DestroyPtrT = void (*)(void *CallableAddr); + + /// A struct to hold a single trivial callback with sufficient alignment for + /// our bitpacking. + struct alignas(8) TrivialCallback { + CallPtrT CallPtr; + }; + + /// A struct we use to aggregate three callbacks when we need full set of + /// operations. + struct alignas(8) NonTrivialCallbacks { + CallPtrT CallPtr; + MovePtrT MovePtr; + DestroyPtrT DestroyPtr; + }; + + // Create a pointer union between either a pointer to a static trivial call + // pointer in a struct or a pointer to a static struct of the call, move, and + // destroy pointers. + using CallbackPointerUnionT = + PointerUnion<TrivialCallback *, NonTrivialCallbacks *>; + + // The main storage buffer. This will either have a pointer to out-of-line + // storage or an inline buffer storing the callable. + union StorageUnionT { + // For out-of-line storage we keep a pointer to the underlying storage and + // the size. This is enough to deallocate the memory. + struct OutOfLineStorageT { + void *StoragePtr; + size_t Size; + size_t Alignment; + } OutOfLineStorage; + static_assert( + sizeof(OutOfLineStorageT) <= InlineStorageSize, + "Should always use all of the out-of-line storage for inline storage!"); + + // For in-line storage, we just provide an aligned character buffer. We + // provide three pointers worth of storage here. + typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type + InlineStorage; + } StorageUnion; + + // A compressed pointer to either our dispatching callback or our table of + // dispatching callbacks and the flag for whether the callable itself is + // stored inline or not. + PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag; + + bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); } + + bool isTrivialCallback() const { + return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>(); + } + + CallPtrT getTrivialCallback() const { + return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr; + } + + NonTrivialCallbacks *getNonTrivialCallbacks() const { + return CallbackAndInlineFlag.getPointer() + .template get<NonTrivialCallbacks *>(); + } + + void *getInlineStorage() { return &StorageUnion.InlineStorage; } + + void *getOutOfLineStorage() { + return StorageUnion.OutOfLineStorage.StoragePtr; + } + size_t getOutOfLineStorageSize() const { + return StorageUnion.OutOfLineStorage.Size; + } + size_t getOutOfLineStorageAlignment() const { + return StorageUnion.OutOfLineStorage.Alignment; + } + + void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) { + StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment}; + } + + template <typename CallableT> + static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) { + return (*reinterpret_cast<CallableT *>(CallableAddr))( + std::forward<ParamTs>(Params)...); + } + + template <typename CallableT> + static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept { + new (LHSCallableAddr) + CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr))); + } + + template <typename CallableT> + static void DestroyImpl(void *CallableAddr) noexcept { + reinterpret_cast<CallableT *>(CallableAddr)->~CallableT(); + } + +public: + unique_function() = default; + unique_function(std::nullptr_t /*null_callable*/) {} + + ~unique_function() { + if (!CallbackAndInlineFlag.getPointer()) + return; + + // Cache this value so we don't re-check it after type-erased operations. + bool IsInlineStorage = isInlineStorage(); + + if (!isTrivialCallback()) + getNonTrivialCallbacks()->DestroyPtr( + IsInlineStorage ? getInlineStorage() : getOutOfLineStorage()); + + if (!IsInlineStorage) + deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(), + getOutOfLineStorageAlignment()); + } + + unique_function(unique_function &&RHS) noexcept { + // Copy the callback and inline flag. + CallbackAndInlineFlag = RHS.CallbackAndInlineFlag; + + // If the RHS is empty, just copying the above is sufficient. + if (!RHS) + return; + + if (!isInlineStorage()) { + // The out-of-line case is easiest to move. + StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage; + } else if (isTrivialCallback()) { + // Move is trivial, just memcpy the bytes across. + memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize); + } else { + // Non-trivial move, so dispatch to a type-erased implementation. + getNonTrivialCallbacks()->MovePtr(getInlineStorage(), + RHS.getInlineStorage()); + } + + // Clear the old callback and inline flag to get back to as-if-null. + RHS.CallbackAndInlineFlag = {}; + +#ifndef NDEBUG + // In debug builds, we also scribble across the rest of the storage. + memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); +#endif + } + + unique_function &operator=(unique_function &&RHS) noexcept { + if (this == &RHS) + return *this; + + // Because we don't try to provide any exception safety guarantees we can + // implement move assignment very simply by first destroying the current + // object and then move-constructing over top of it. + this->~unique_function(); + new (this) unique_function(std::move(RHS)); + return *this; + } + + template <typename CallableT> unique_function(CallableT Callable) { + bool IsInlineStorage = true; + void *CallableAddr = getInlineStorage(); + if (sizeof(CallableT) > InlineStorageSize || + alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) { + IsInlineStorage = false; + // Allocate out-of-line storage. FIXME: Use an explicit alignment + // parameter in C++17 mode. + auto Size = sizeof(CallableT); + auto Alignment = alignof(CallableT); + CallableAddr = allocate_buffer(Size, Alignment); + setOutOfLineStorage(CallableAddr, Size, Alignment); + } + + // Now move into the storage. + new (CallableAddr) CallableT(std::move(Callable)); + + // See if we can create a trivial callback. We need the callable to be + // trivially moved and trivially destroyed so that we don't have to store + // type erased callbacks for those operations. + // + // FIXME: We should use constexpr if here and below to avoid instantiating + // the non-trivial static objects when unnecessary. While the linker should + // remove them, it is still wasteful. + if (llvm::is_trivially_move_constructible<CallableT>::value && + std::is_trivially_destructible<CallableT>::value) { + // We need to create a nicely aligned object. We use a static variable + // for this because it is a trivial struct. + static TrivialCallback Callback = { &CallImpl<CallableT> }; + + CallbackAndInlineFlag = {&Callback, IsInlineStorage}; + return; + } + + // Otherwise, we need to point at an object that contains all the different + // type erased behaviors needed. Create a static instance of the struct type + // here and then use a pointer to that. + static NonTrivialCallbacks Callbacks = { + &CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>}; + + CallbackAndInlineFlag = {&Callbacks, IsInlineStorage}; + } + + ReturnT operator()(ParamTs... Params) { + void *CallableAddr = + isInlineStorage() ? getInlineStorage() : getOutOfLineStorage(); + + return (isTrivialCallback() + ? getTrivialCallback() + : getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...); + } + + explicit operator bool() const { + return (bool)CallbackAndInlineFlag.getPointer(); + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_FUNCTION_H diff --git a/third_party/llvm-project/include/llvm/ADT/Hashing.h b/third_party/llvm-project/include/llvm/ADT/Hashing.h new file mode 100644 index 000000000..adcc5cf54 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/Hashing.h @@ -0,0 +1,659 @@ +//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the newly proposed standard C++ interfaces for hashing +// arbitrary data and building hash functions for user-defined types. This +// interface was originally proposed in N3333[1] and is currently under review +// for inclusion in a future TR and/or standard. +// +// The primary interfaces provide are comprised of one type and three functions: +// +// -- 'hash_code' class is an opaque type representing the hash code for some +// data. It is the intended product of hashing, and can be used to implement +// hash tables, checksumming, and other common uses of hashes. It is not an +// integer type (although it can be converted to one) because it is risky +// to assume much about the internals of a hash_code. In particular, each +// execution of the program has a high probability of producing a different +// hash_code for a given input. Thus their values are not stable to save or +// persist, and should only be used during the execution for the +// construction of hashing datastructures. +// +// -- 'hash_value' is a function designed to be overloaded for each +// user-defined type which wishes to be used within a hashing context. It +// should be overloaded within the user-defined type's namespace and found +// via ADL. Overloads for primitive types are provided by this library. +// +// -- 'hash_combine' and 'hash_combine_range' are functions designed to aid +// programmers in easily and intuitively combining a set of data into +// a single hash_code for their object. They should only logically be used +// within the implementation of a 'hash_value' routine or similar context. +// +// Note that 'hash_combine_range' contains very special logic for hashing +// a contiguous array of integers or pointers. This logic is *extremely* fast, +// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were +// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys +// under 32-bytes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_HASHING_H +#define LLVM_ADT_HASHING_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/type_traits.h" +#include <algorithm> +#include <cassert> +#include <cstring> +#include <string> +#include <utility> + +namespace llvm { + +/// An opaque object representing a hash code. +/// +/// This object represents the result of hashing some entity. It is intended to +/// be used to implement hashtables or other hashing-based data structures. +/// While it wraps and exposes a numeric value, this value should not be +/// trusted to be stable or predictable across processes or executions. +/// +/// In order to obtain the hash_code for an object 'x': +/// \code +/// using llvm::hash_value; +/// llvm::hash_code code = hash_value(x); +/// \endcode +class hash_code { + size_t value; + +public: + /// Default construct a hash_code. + /// Note that this leaves the value uninitialized. + hash_code() = default; + + /// Form a hash code directly from a numerical value. + hash_code(size_t value) : value(value) {} + + /// Convert the hash code to its numerical value for use. + /*explicit*/ operator size_t() const { return value; } + + friend bool operator==(const hash_code &lhs, const hash_code &rhs) { + return lhs.value == rhs.value; + } + friend bool operator!=(const hash_code &lhs, const hash_code &rhs) { + return lhs.value != rhs.value; + } + + /// Allow a hash_code to be directly run through hash_value. + friend size_t hash_value(const hash_code &code) { return code.value; } +}; + +/// Compute a hash_code for any integer value. +/// +/// Note that this function is intended to compute the same hash_code for +/// a particular value without regard to the pre-promotion type. This is in +/// contrast to hash_combine which may produce different hash_codes for +/// differing argument types even if they would implicit promote to a common +/// type without changing the value. +template <typename T> +typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type +hash_value(T value); + +/// Compute a hash_code for a pointer's address. +/// +/// N.B.: This hashes the *address*. Not the value and not the type. +template <typename T> hash_code hash_value(const T *ptr); + +/// Compute a hash_code for a pair of objects. +template <typename T, typename U> +hash_code hash_value(const std::pair<T, U> &arg); + +/// Compute a hash_code for a standard string. +template <typename T> +hash_code hash_value(const std::basic_string<T> &arg); + + +/// Override the execution seed with a fixed value. +/// +/// This hashing library uses a per-execution seed designed to change on each +/// run with high probability in order to ensure that the hash codes are not +/// attackable and to ensure that output which is intended to be stable does +/// not rely on the particulars of the hash codes produced. +/// +/// That said, there are use cases where it is important to be able to +/// reproduce *exactly* a specific behavior. To that end, we provide a function +/// which will forcibly set the seed to a fixed value. This must be done at the +/// start of the program, before any hashes are computed. Also, it cannot be +/// undone. This makes it thread-hostile and very hard to use outside of +/// immediately on start of a simple program designed for reproducible +/// behavior. +void set_fixed_execution_hash_seed(uint64_t fixed_value); + + +// All of the implementation details of actually computing the various hash +// code values are held within this namespace. These routines are included in +// the header file mainly to allow inlining and constant propagation. +namespace hashing { +namespace detail { + +inline uint64_t fetch64(const char *p) { + uint64_t result; + memcpy(&result, p, sizeof(result)); + if (sys::IsBigEndianHost) + sys::swapByteOrder(result); + return result; +} + +inline uint32_t fetch32(const char *p) { + uint32_t result; + memcpy(&result, p, sizeof(result)); + if (sys::IsBigEndianHost) + sys::swapByteOrder(result); + return result; +} + +/// Some primes between 2^63 and 2^64 for various uses. +static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; +static const uint64_t k1 = 0xb492b66fbe98f273ULL; +static const uint64_t k2 = 0x9ae16a3b2f90404fULL; +static const uint64_t k3 = 0xc949d7c7509e6557ULL; + +/// Bitwise right rotate. +/// Normally this will compile to a single instruction, especially if the +/// shift is a manifest constant. +inline uint64_t rotate(uint64_t val, size_t shift) { + // Avoid shifting by 64: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); +} + +inline uint64_t shift_mix(uint64_t val) { + return val ^ (val >> 47); +} + +inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) { + // Murmur-inspired hashing. + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t a = (low ^ high) * kMul; + a ^= (a >> 47); + uint64_t b = (high ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + return b; +} + +inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) { + uint8_t a = s[0]; + uint8_t b = s[len >> 1]; + uint8_t c = s[len - 1]; + uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8); + uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2); + return shift_mix(y * k2 ^ z * k3 ^ seed) * k2; +} + +inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) { + uint64_t a = fetch32(s); + return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4)); +} + +inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) { + uint64_t a = fetch64(s); + uint64_t b = fetch64(s + len - 8); + return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b; +} + +inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) { + uint64_t a = fetch64(s) * k1; + uint64_t b = fetch64(s + 8); + uint64_t c = fetch64(s + len - 8) * k2; + uint64_t d = fetch64(s + len - 16) * k0; + return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d, + a + rotate(b ^ k3, 20) - c + len + seed); +} + +inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) { + uint64_t z = fetch64(s + 24); + uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0; + uint64_t b = rotate(a + z, 52); + uint64_t c = rotate(a, 37); + a += fetch64(s + 8); + c += rotate(a, 7); + a += fetch64(s + 16); + uint64_t vf = a + z; + uint64_t vs = b + rotate(a, 31) + c; + a = fetch64(s + 16) + fetch64(s + len - 32); + z = fetch64(s + len - 8); + b = rotate(a + z, 52); + c = rotate(a, 37); + a += fetch64(s + len - 24); + c += rotate(a, 7); + a += fetch64(s + len - 16); + uint64_t wf = a + z; + uint64_t ws = b + rotate(a, 31) + c; + uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0); + return shift_mix((seed ^ (r * k0)) + vs) * k2; +} + +inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) { + if (length >= 4 && length <= 8) + return hash_4to8_bytes(s, length, seed); + if (length > 8 && length <= 16) + return hash_9to16_bytes(s, length, seed); + if (length > 16 && length <= 32) + return hash_17to32_bytes(s, length, seed); + if (length > 32) + return hash_33to64_bytes(s, length, seed); + if (length != 0) + return hash_1to3_bytes(s, length, seed); + + return k2 ^ seed; +} + +/// The intermediate state used during hashing. +/// Currently, the algorithm for computing hash codes is based on CityHash and +/// keeps 56 bytes of arbitrary state. +struct hash_state { + uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0; + + /// Create a new hash_state structure and initialize it based on the + /// seed and the first 64-byte chunk. + /// This effectively performs the initial mix. + static hash_state create(const char *s, uint64_t seed) { + hash_state state = { + 0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49), + seed * k1, shift_mix(seed), 0 }; + state.h6 = hash_16_bytes(state.h4, state.h5); + state.mix(s); + return state; + } + + /// Mix 32-bytes from the input sequence into the 16-bytes of 'a' + /// and 'b', including whatever is already in 'a' and 'b'. + static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) { + a += fetch64(s); + uint64_t c = fetch64(s + 24); + b = rotate(b + a + c, 21); + uint64_t d = a; + a += fetch64(s + 8) + fetch64(s + 16); + b += rotate(a, 44) + d; + a += c; + } + + /// Mix in a 64-byte buffer of data. + /// We mix all 64 bytes even when the chunk length is smaller, but we + /// record the actual length. + void mix(const char *s) { + h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1; + h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1; + h0 ^= h6; + h1 += h3 + fetch64(s + 40); + h2 = rotate(h2 + h5, 33) * k1; + h3 = h4 * k1; + h4 = h0 + h5; + mix_32_bytes(s, h3, h4); + h5 = h2 + h6; + h6 = h1 + fetch64(s + 16); + mix_32_bytes(s + 32, h5, h6); + std::swap(h2, h0); + } + + /// Compute the final 64-bit hash code value based on the current + /// state and the length of bytes hashed. + uint64_t finalize(size_t length) { + return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2, + hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0); + } +}; + + +/// A global, fixed seed-override variable. +/// +/// This variable can be set using the \see llvm::set_fixed_execution_seed +/// function. See that function for details. Do not, under any circumstances, +/// set or read this variable. +extern uint64_t fixed_seed_override; + +inline uint64_t get_execution_seed() { + // FIXME: This needs to be a per-execution seed. This is just a placeholder + // implementation. Switching to a per-execution seed is likely to flush out + // instability bugs and so will happen as its own commit. + // + // However, if there is a fixed seed override set the first time this is + // called, return that instead of the per-execution seed. + const uint64_t seed_prime = 0xff51afd7ed558ccdULL; + static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime; + return seed; +} + + +/// Trait to indicate whether a type's bits can be hashed directly. +/// +/// A type trait which is true if we want to combine values for hashing by +/// reading the underlying data. It is false if values of this type must +/// first be passed to hash_value, and the resulting hash_codes combined. +// +// FIXME: We want to replace is_integral_or_enum and is_pointer here with +// a predicate which asserts that comparing the underlying storage of two +// values of the type for equality is equivalent to comparing the two values +// for equality. For all the platforms we care about, this holds for integers +// and pointers, but there are platforms where it doesn't and we would like to +// support user-defined types which happen to satisfy this property. +template <typename T> struct is_hashable_data + : std::integral_constant<bool, ((is_integral_or_enum<T>::value || + std::is_pointer<T>::value) && + 64 % sizeof(T) == 0)> {}; + +// Special case std::pair to detect when both types are viable and when there +// is no alignment-derived padding in the pair. This is a bit of a lie because +// std::pair isn't truly POD, but it's close enough in all reasonable +// implementations for our use case of hashing the underlying data. +template <typename T, typename U> struct is_hashable_data<std::pair<T, U> > + : std::integral_constant<bool, (is_hashable_data<T>::value && + is_hashable_data<U>::value && + (sizeof(T) + sizeof(U)) == + sizeof(std::pair<T, U>))> {}; + +/// Helper to get the hashable data representation for a type. +/// This variant is enabled when the type itself can be used. +template <typename T> +typename std::enable_if<is_hashable_data<T>::value, T>::type +get_hashable_data(const T &value) { + return value; +} +/// Helper to get the hashable data representation for a type. +/// This variant is enabled when we must first call hash_value and use the +/// result as our data. +template <typename T> +typename std::enable_if<!is_hashable_data<T>::value, size_t>::type +get_hashable_data(const T &value) { + using ::llvm::hash_value; + return hash_value(value); +} + +/// Helper to store data from a value into a buffer and advance the +/// pointer into that buffer. +/// +/// This routine first checks whether there is enough space in the provided +/// buffer, and if not immediately returns false. If there is space, it +/// copies the underlying bytes of value into the buffer, advances the +/// buffer_ptr past the copied bytes, and returns true. +template <typename T> +bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value, + size_t offset = 0) { + size_t store_size = sizeof(value) - offset; + if (buffer_ptr + store_size > buffer_end) + return false; + const char *value_data = reinterpret_cast<const char *>(&value); + memcpy(buffer_ptr, value_data + offset, store_size); + buffer_ptr += store_size; + return true; +} + +/// Implement the combining of integral values into a hash_code. +/// +/// This overload is selected when the value type of the iterator is +/// integral. Rather than computing a hash_code for each object and then +/// combining them, this (as an optimization) directly combines the integers. +template <typename InputIteratorT> +hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) { + const uint64_t seed = get_execution_seed(); + char buffer[64], *buffer_ptr = buffer; + char *const buffer_end = std::end(buffer); + while (first != last && store_and_advance(buffer_ptr, buffer_end, + get_hashable_data(*first))) + ++first; + if (first == last) + return hash_short(buffer, buffer_ptr - buffer, seed); + assert(buffer_ptr == buffer_end); + + hash_state state = state.create(buffer, seed); + size_t length = 64; + while (first != last) { + // Fill up the buffer. We don't clear it, which re-mixes the last round + // when only a partial 64-byte chunk is left. + buffer_ptr = buffer; + while (first != last && store_and_advance(buffer_ptr, buffer_end, + get_hashable_data(*first))) + ++first; + + // Rotate the buffer if we did a partial fill in order to simulate doing + // a mix of the last 64-bytes. That is how the algorithm works when we + // have a contiguous byte sequence, and we want to emulate that here. + std::rotate(buffer, buffer_ptr, buffer_end); + + // Mix this chunk into the current state. + state.mix(buffer); + length += buffer_ptr - buffer; + }; + + return state.finalize(length); +} + +/// Implement the combining of integral values into a hash_code. +/// +/// This overload is selected when the value type of the iterator is integral +/// and when the input iterator is actually a pointer. Rather than computing +/// a hash_code for each object and then combining them, this (as an +/// optimization) directly combines the integers. Also, because the integers +/// are stored in contiguous memory, this routine avoids copying each value +/// and directly reads from the underlying memory. +template <typename ValueT> +typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type +hash_combine_range_impl(ValueT *first, ValueT *last) { + const uint64_t seed = get_execution_seed(); + const char *s_begin = reinterpret_cast<const char *>(first); + const char *s_end = reinterpret_cast<const char *>(last); + const size_t length = std::distance(s_begin, s_end); + if (length <= 64) + return hash_short(s_begin, length, seed); + + const char *s_aligned_end = s_begin + (length & ~63); + hash_state state = state.create(s_begin, seed); + s_begin += 64; + while (s_begin != s_aligned_end) { + state.mix(s_begin); + s_begin += 64; + } + if (length & 63) + state.mix(s_end - 64); + + return state.finalize(length); +} + +} // namespace detail +} // namespace hashing + + +/// Compute a hash_code for a sequence of values. +/// +/// This hashes a sequence of values. It produces the same hash_code as +/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences +/// and is significantly faster given pointers and types which can be hashed as +/// a sequence of bytes. +template <typename InputIteratorT> +hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) { + return ::llvm::hashing::detail::hash_combine_range_impl(first, last); +} + + +// Implementation details for hash_combine. +namespace hashing { +namespace detail { + +/// Helper class to manage the recursive combining of hash_combine +/// arguments. +/// +/// This class exists to manage the state and various calls involved in the +/// recursive combining of arguments used in hash_combine. It is particularly +/// useful at minimizing the code in the recursive calls to ease the pain +/// caused by a lack of variadic functions. +struct hash_combine_recursive_helper { + char buffer[64] = {}; + hash_state state; + const uint64_t seed; + +public: + /// Construct a recursive hash combining helper. + /// + /// This sets up the state for a recursive hash combine, including getting + /// the seed and buffer setup. + hash_combine_recursive_helper() + : seed(get_execution_seed()) {} + + /// Combine one chunk of data into the current in-flight hash. + /// + /// This merges one chunk of data into the hash. First it tries to buffer + /// the data. If the buffer is full, it hashes the buffer into its + /// hash_state, empties it, and then merges the new chunk in. This also + /// handles cases where the data straddles the end of the buffer. + template <typename T> + char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) { + if (!store_and_advance(buffer_ptr, buffer_end, data)) { + // Check for skew which prevents the buffer from being packed, and do + // a partial store into the buffer to fill it. This is only a concern + // with the variadic combine because that formation can have varying + // argument types. + size_t partial_store_size = buffer_end - buffer_ptr; + memcpy(buffer_ptr, &data, partial_store_size); + + // If the store fails, our buffer is full and ready to hash. We have to + // either initialize the hash state (on the first full buffer) or mix + // this buffer into the existing hash state. Length tracks the *hashed* + // length, not the buffered length. + if (length == 0) { + state = state.create(buffer, seed); + length = 64; + } else { + // Mix this chunk into the current state and bump length up by 64. + state.mix(buffer); + length += 64; + } + // Reset the buffer_ptr to the head of the buffer for the next chunk of + // data. + buffer_ptr = buffer; + + // Try again to store into the buffer -- this cannot fail as we only + // store types smaller than the buffer. + if (!store_and_advance(buffer_ptr, buffer_end, data, + partial_store_size)) + llvm_unreachable("buffer smaller than stored type"); + } + return buffer_ptr; + } + + /// Recursive, variadic combining method. + /// + /// This function recurses through each argument, combining that argument + /// into a single hash. + template <typename T, typename ...Ts> + hash_code combine(size_t length, char *buffer_ptr, char *buffer_end, + const T &arg, const Ts &...args) { + buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg)); + + // Recurse to the next argument. + return combine(length, buffer_ptr, buffer_end, args...); + } + + /// Base case for recursive, variadic combining. + /// + /// The base case when combining arguments recursively is reached when all + /// arguments have been handled. It flushes the remaining buffer and + /// constructs a hash_code. + hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) { + // Check whether the entire set of values fit in the buffer. If so, we'll + // use the optimized short hashing routine and skip state entirely. + if (length == 0) + return hash_short(buffer, buffer_ptr - buffer, seed); + + // Mix the final buffer, rotating it if we did a partial fill in order to + // simulate doing a mix of the last 64-bytes. That is how the algorithm + // works when we have a contiguous byte sequence, and we want to emulate + // that here. + std::rotate(buffer, buffer_ptr, buffer_end); + + // Mix this chunk into the current state. + state.mix(buffer); + length += buffer_ptr - buffer; + + return state.finalize(length); + } +}; + +} // namespace detail +} // namespace hashing + +/// Combine values into a single hash_code. +/// +/// This routine accepts a varying number of arguments of any type. It will +/// attempt to combine them into a single hash_code. For user-defined types it +/// attempts to call a \see hash_value overload (via ADL) for the type. For +/// integer and pointer types it directly combines their data into the +/// resulting hash_code. +/// +/// The result is suitable for returning from a user's hash_value +/// *implementation* for their user-defined type. Consumers of a type should +/// *not* call this routine, they should instead call 'hash_value'. +template <typename ...Ts> hash_code hash_combine(const Ts &...args) { + // Recursively hash each argument using a helper class. + ::llvm::hashing::detail::hash_combine_recursive_helper helper; + return helper.combine(0, helper.buffer, helper.buffer + 64, args...); +} + +// Implementation details for implementations of hash_value overloads provided +// here. +namespace hashing { +namespace detail { + +/// Helper to hash the value of a single integer. +/// +/// Overloads for smaller integer types are not provided to ensure consistent +/// behavior in the presence of integral promotions. Essentially, +/// "hash_value('4')" and "hash_value('0' + 4)" should be the same. +inline hash_code hash_integer_value(uint64_t value) { + // Similar to hash_4to8_bytes but using a seed instead of length. + const uint64_t seed = get_execution_seed(); + const char *s = reinterpret_cast<const char *>(&value); + const uint64_t a = fetch32(s); + return hash_16_bytes(seed + (a << 3), fetch32(s + 4)); +} + +} // namespace detail +} // namespace hashing + +// Declared and documented above, but defined here so that any of the hashing +// infrastructure is available. +template <typename T> +typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type +hash_value(T value) { + return ::llvm::hashing::detail::hash_integer_value( + static_cast<uint64_t>(value)); +} + +// Declared and documented above, but defined here so that any of the hashing +// infrastructure is available. +template <typename T> hash_code hash_value(const T *ptr) { + return ::llvm::hashing::detail::hash_integer_value( + reinterpret_cast<uintptr_t>(ptr)); +} + +// Declared and documented above, but defined here so that any of the hashing +// infrastructure is available. +template <typename T, typename U> +hash_code hash_value(const std::pair<T, U> &arg) { + return hash_combine(arg.first, arg.second); +} + +// Declared and documented above, but defined here so that any of the hashing +// infrastructure is available. +template <typename T> +hash_code hash_value(const std::basic_string<T> &arg) { + return hash_combine_range(arg.begin(), arg.end()); +} + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/MapVector.h b/third_party/llvm-project/include/llvm/ADT/MapVector.h new file mode 100644 index 000000000..1de1124f4 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/MapVector.h @@ -0,0 +1,239 @@ +//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a map that provides insertion order iteration. The +// interface is purposefully minimal. The key is assumed to be cheap to copy +// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in +// a std::vector. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_MAPVECTOR_H +#define LLVM_ADT_MAPVECTOR_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <type_traits> +#include <utility> +#include <vector> + +namespace llvm { + +/// This class implements a map that also provides access to all stored values +/// in a deterministic order. The values are kept in a std::vector and the +/// mapping is done with DenseMap from Keys to indexes in that vector. +template<typename KeyT, typename ValueT, + typename MapType = DenseMap<KeyT, unsigned>, + typename VectorType = std::vector<std::pair<KeyT, ValueT>>> +class MapVector { + MapType Map; + VectorType Vector; + + static_assert( + std::is_integral<typename MapType::mapped_type>::value, + "The mapped_type of the specified Map must be an integral type"); + +public: + using value_type = typename VectorType::value_type; + using size_type = typename VectorType::size_type; + + using iterator = typename VectorType::iterator; + using const_iterator = typename VectorType::const_iterator; + using reverse_iterator = typename VectorType::reverse_iterator; + using const_reverse_iterator = typename VectorType::const_reverse_iterator; + + /// Clear the MapVector and return the underlying vector. + VectorType takeVector() { + Map.clear(); + return std::move(Vector); + } + + size_type size() const { return Vector.size(); } + + /// Grow the MapVector so that it can contain at least \p NumEntries items + /// before resizing again. + void reserve(size_type NumEntries) { + Map.reserve(NumEntries); + Vector.reserve(NumEntries); + } + + iterator begin() { return Vector.begin(); } + const_iterator begin() const { return Vector.begin(); } + iterator end() { return Vector.end(); } + const_iterator end() const { return Vector.end(); } + + reverse_iterator rbegin() { return Vector.rbegin(); } + const_reverse_iterator rbegin() const { return Vector.rbegin(); } + reverse_iterator rend() { return Vector.rend(); } + const_reverse_iterator rend() const { return Vector.rend(); } + + bool empty() const { + return Vector.empty(); + } + + std::pair<KeyT, ValueT> &front() { return Vector.front(); } + const std::pair<KeyT, ValueT> &front() const { return Vector.front(); } + std::pair<KeyT, ValueT> &back() { return Vector.back(); } + const std::pair<KeyT, ValueT> &back() const { return Vector.back(); } + + void clear() { + Map.clear(); + Vector.clear(); + } + + void swap(MapVector &RHS) { + std::swap(Map, RHS.Map); + std::swap(Vector, RHS.Vector); + } + + ValueT &operator[](const KeyT &Key) { + std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(Key, 0); + std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); + auto &I = Result.first->second; + if (Result.second) { + Vector.push_back(std::make_pair(Key, ValueT())); + I = Vector.size() - 1; + } + return Vector[I].second; + } + + // Returns a copy of the value. Only allowed if ValueT is copyable. + ValueT lookup(const KeyT &Key) const { + static_assert(std::is_copy_constructible<ValueT>::value, + "Cannot call lookup() if ValueT is not copyable."); + typename MapType::const_iterator Pos = Map.find(Key); + return Pos == Map.end()? ValueT() : Vector[Pos->second].second; + } + + std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) { + std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0); + std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); + auto &I = Result.first->second; + if (Result.second) { + Vector.push_back(std::make_pair(KV.first, KV.second)); + I = Vector.size() - 1; + return std::make_pair(std::prev(end()), true); + } + return std::make_pair(begin() + I, false); + } + + std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) { + // Copy KV.first into the map, then move it into the vector. + std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0); + std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); + auto &I = Result.first->second; + if (Result.second) { + Vector.push_back(std::move(KV)); + I = Vector.size() - 1; + return std::make_pair(std::prev(end()), true); + } + return std::make_pair(begin() + I, false); + } + + size_type count(const KeyT &Key) const { + typename MapType::const_iterator Pos = Map.find(Key); + return Pos == Map.end()? 0 : 1; + } + + iterator find(const KeyT &Key) { + typename MapType::const_iterator Pos = Map.find(Key); + return Pos == Map.end()? Vector.end() : + (Vector.begin() + Pos->second); + } + + const_iterator find(const KeyT &Key) const { + typename MapType::const_iterator Pos = Map.find(Key); + return Pos == Map.end()? Vector.end() : + (Vector.begin() + Pos->second); + } + + /// Remove the last element from the vector. + void pop_back() { + typename MapType::iterator Pos = Map.find(Vector.back().first); + Map.erase(Pos); + Vector.pop_back(); + } + + /// Remove the element given by Iterator. + /// + /// Returns an iterator to the element following the one which was removed, + /// which may be end(). + /// + /// \note This is a deceivingly expensive operation (linear time). It's + /// usually better to use \a remove_if() if possible. + typename VectorType::iterator erase(typename VectorType::iterator Iterator) { + Map.erase(Iterator->first); + auto Next = Vector.erase(Iterator); + if (Next == Vector.end()) + return Next; + + // Update indices in the map. + size_t Index = Next - Vector.begin(); + for (auto &I : Map) { + assert(I.second != Index && "Index was already erased!"); + if (I.second > Index) + --I.second; + } + return Next; + } + + /// Remove all elements with the key value Key. + /// + /// Returns the number of elements removed. + size_type erase(const KeyT &Key) { + auto Iterator = find(Key); + if (Iterator == end()) + return 0; + erase(Iterator); + return 1; + } + + /// Remove the elements that match the predicate. + /// + /// Erase all elements that match \c Pred in a single pass. Takes linear + /// time. + template <class Predicate> void remove_if(Predicate Pred); +}; + +template <typename KeyT, typename ValueT, typename MapType, typename VectorType> +template <class Function> +void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) { + auto O = Vector.begin(); + for (auto I = O, E = Vector.end(); I != E; ++I) { + if (Pred(*I)) { + // Erase from the map. + Map.erase(I->first); + continue; + } + + if (I != O) { + // Move the value and update the index in the map. + *O = std::move(*I); + Map[O->first] = O - Vector.begin(); + } + ++O; + } + // Erase trailing entries in the vector. + Vector.erase(O, Vector.end()); +} + +/// A MapVector that performs no allocations if smaller than a certain +/// size. +template <typename KeyT, typename ValueT, unsigned N> +struct SmallMapVector + : MapVector<KeyT, ValueT, SmallDenseMap<KeyT, unsigned, N>, + SmallVector<std::pair<KeyT, ValueT>, N>> { +}; + +} // end namespace llvm + +#endif // LLVM_ADT_MAPVECTOR_H diff --git a/third_party/llvm-project/include/llvm/ADT/None.h b/third_party/llvm-project/include/llvm/ADT/None.h new file mode 100644 index 000000000..004ca0ac5 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/None.h @@ -0,0 +1,26 @@ +//===-- None.h - Simple null value for implicit construction ------*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides None, an enumerator for use in implicit constructors +// of various (usually templated) types to make such construction more +// terse. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_NONE_H +#define LLVM_ADT_NONE_H + +namespace llvm { +/// A simple null object to allow implicit construction of Optional<T> +/// and similar types without having to spell out the specialization's name. +// (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/third_party/llvm-project/include/llvm/ADT/Optional.h b/third_party/llvm-project/include/llvm/ADT/Optional.h new file mode 100644 index 000000000..b45a74002 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/Optional.h @@ -0,0 +1,429 @@ +//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides Optional, a template class modeled in the spirit of +// OCaml's 'opt' variant. The idea is to strongly type whether or not +// a value can be optional. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_OPTIONAL_H +#define LLVM_ADT_OPTIONAL_H + +#include "llvm/ADT/None.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <memory> +#include <new> +#include <utility> + +namespace llvm { + +class raw_ostream; + +namespace optional_detail { + +struct in_place_t {}; + +/// Storage for any type. +template <typename T, bool = is_trivially_copyable<T>::value> +class OptionalStorage { + union { + char empty; + T value; + }; + bool hasVal; + +public: + ~OptionalStorage() { reset(); } + + OptionalStorage() noexcept : empty(), hasVal(false) {} + + OptionalStorage(OptionalStorage const &other) : OptionalStorage() { + if (other.hasValue()) { + emplace(other.value); + } + } + OptionalStorage(OptionalStorage &&other) : OptionalStorage() { + if (other.hasValue()) { + emplace(std::move(other.value)); + } + } + + template <class... Args> + explicit OptionalStorage(in_place_t, Args &&... args) + : value(std::forward<Args>(args)...), hasVal(true) {} + + void reset() noexcept { + if (hasVal) { + value.~T(); + hasVal = false; + } + } + + bool hasValue() const noexcept { return hasVal; } + + T &getValue() LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } + T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } +#if LLVM_HAS_RVALUE_REFERENCE_THIS + T &&getValue() && noexcept { + assert(hasVal); + return std::move(value); + } +#endif + + template <class... Args> void emplace(Args &&... args) { + reset(); + ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); + hasVal = true; + } + + OptionalStorage &operator=(T const &y) { + if (hasValue()) { + value = y; + } else { + ::new ((void *)std::addressof(value)) T(y); + hasVal = true; + } + return *this; + } + OptionalStorage &operator=(T &&y) { + if (hasValue()) { + value = std::move(y); + } else { + ::new ((void *)std::addressof(value)) T(std::move(y)); + hasVal = true; + } + return *this; + } + + OptionalStorage &operator=(OptionalStorage const &other) { + if (other.hasValue()) { + if (hasValue()) { + value = other.value; + } else { + ::new ((void *)std::addressof(value)) T(other.value); + hasVal = true; + } + } else { + reset(); + } + return *this; + } + + OptionalStorage &operator=(OptionalStorage &&other) { + if (other.hasValue()) { + if (hasValue()) { + value = std::move(other.value); + } else { + ::new ((void *)std::addressof(value)) T(std::move(other.value)); + hasVal = true; + } + } else { + reset(); + } + return *this; + } +}; + +template <typename T> class OptionalStorage<T, true> { + union { + char empty; + T value; + }; + bool hasVal = false; + +public: + ~OptionalStorage() = default; + + OptionalStorage() noexcept : empty{} {} + + OptionalStorage(OptionalStorage const &other) = default; + OptionalStorage(OptionalStorage &&other) = default; + + OptionalStorage &operator=(OptionalStorage const &other) = default; + OptionalStorage &operator=(OptionalStorage &&other) = default; + + template <class... Args> + explicit OptionalStorage(in_place_t, Args &&... args) + : value(std::forward<Args>(args)...), hasVal(true) {} + + void reset() noexcept { + if (hasVal) { + value.~T(); + hasVal = false; + } + } + + bool hasValue() const noexcept { return hasVal; } + + T &getValue() LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } + T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } +#if LLVM_HAS_RVALUE_REFERENCE_THIS + T &&getValue() && noexcept { + assert(hasVal); + return std::move(value); + } +#endif + + template <class... Args> void emplace(Args &&... args) { + reset(); + ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); + hasVal = true; + } + + OptionalStorage &operator=(T const &y) { + if (hasValue()) { + value = y; + } else { + ::new ((void *)std::addressof(value)) T(y); + hasVal = true; + } + return *this; + } + OptionalStorage &operator=(T &&y) { + if (hasValue()) { + value = std::move(y); + } else { + ::new ((void *)std::addressof(value)) T(std::move(y)); + hasVal = true; + } + return *this; + } +}; + +} // namespace optional_detail + +template <typename T> class Optional { + optional_detail::OptionalStorage<T> Storage; + +public: + using value_type = T; + + constexpr Optional() {} + constexpr Optional(NoneType) {} + + Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} + Optional(const Optional &O) = default; + + Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {} + Optional(Optional &&O) = default; + + Optional &operator=(T &&y) { + Storage = std::move(y); + return *this; + } + Optional &operator=(Optional &&O) = default; + + /// Create a new object by constructing it in place with the given arguments. + template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { + Storage.emplace(std::forward<ArgTypes>(Args)...); + } + + static inline Optional create(const T *y) { + return y ? Optional(*y) : Optional(); + } + + Optional &operator=(const T &y) { + Storage = y; + return *this; + } + Optional &operator=(const Optional &O) = default; + + void reset() { Storage.reset(); } + + const T *getPointer() const { return &Storage.getValue(); } + T *getPointer() { return &Storage.getValue(); } + const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } + T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } + + explicit operator bool() const { return hasValue(); } + bool hasValue() const { return Storage.hasValue(); } + const T *operator->() const { return getPointer(); } + T *operator->() { return getPointer(); } + const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } + T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } + + template <typename U> + constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { + return hasValue() ? getValue() : std::forward<U>(value); + } + +#if LLVM_HAS_RVALUE_REFERENCE_THIS + T &&getValue() && { return std::move(Storage.getValue()); } + T &&operator*() && { return std::move(Storage.getValue()); } + + template <typename U> + T getValueOr(U &&value) && { + return hasValue() ? std::move(getValue()) : std::forward<U>(value); + } +#endif +}; + +template <typename T, typename U> +bool operator==(const Optional<T> &X, const Optional<U> &Y) { + if (X && Y) + return *X == *Y; + return X.hasValue() == Y.hasValue(); +} + +template <typename T, typename U> +bool operator!=(const Optional<T> &X, const Optional<U> &Y) { + return !(X == Y); +} + +template <typename T, typename U> +bool operator<(const Optional<T> &X, const Optional<U> &Y) { + if (X && Y) + return *X < *Y; + return X.hasValue() < Y.hasValue(); +} + +template <typename T, typename U> +bool operator<=(const Optional<T> &X, const Optional<U> &Y) { + return !(Y < X); +} + +template <typename T, typename U> +bool operator>(const Optional<T> &X, const Optional<U> &Y) { + return Y < X; +} + +template <typename T, typename U> +bool operator>=(const Optional<T> &X, const Optional<U> &Y) { + return !(X < Y); +} + +template<typename T> +bool operator==(const Optional<T> &X, NoneType) { + return !X; +} + +template<typename T> +bool operator==(NoneType, const Optional<T> &X) { + return X == None; +} + +template<typename T> +bool operator!=(const Optional<T> &X, NoneType) { + return !(X == None); +} + +template<typename T> +bool operator!=(NoneType, const Optional<T> &X) { + return X != None; +} + +template <typename T> bool operator<(const Optional<T> &X, NoneType) { + return false; +} + +template <typename T> bool operator<(NoneType, const Optional<T> &X) { + return X.hasValue(); +} + +template <typename T> bool operator<=(const Optional<T> &X, NoneType) { + return !(None < X); +} + +template <typename T> bool operator<=(NoneType, const Optional<T> &X) { + return !(X < None); +} + +template <typename T> bool operator>(const Optional<T> &X, NoneType) { + return None < X; +} + +template <typename T> bool operator>(NoneType, const Optional<T> &X) { + return X < None; +} + +template <typename T> bool operator>=(const Optional<T> &X, NoneType) { + return None <= X; +} + +template <typename T> bool operator>=(NoneType, const Optional<T> &X) { + return X <= None; +} + +template <typename T> bool operator==(const Optional<T> &X, const T &Y) { + return X && *X == Y; +} + +template <typename T> bool operator==(const T &X, const Optional<T> &Y) { + return Y && X == *Y; +} + +template <typename T> bool operator!=(const Optional<T> &X, const T &Y) { + return !(X == Y); +} + +template <typename T> bool operator!=(const T &X, const Optional<T> &Y) { + return !(X == Y); +} + +template <typename T> bool operator<(const Optional<T> &X, const T &Y) { + return !X || *X < Y; +} + +template <typename T> bool operator<(const T &X, const Optional<T> &Y) { + return Y && X < *Y; +} + +template <typename T> bool operator<=(const Optional<T> &X, const T &Y) { + return !(Y < X); +} + +template <typename T> bool operator<=(const T &X, const Optional<T> &Y) { + return !(Y < X); +} + +template <typename T> bool operator>(const Optional<T> &X, const T &Y) { + return Y < X; +} + +template <typename T> bool operator>(const T &X, const Optional<T> &Y) { + return Y < X; +} + +template <typename T> bool operator>=(const Optional<T> &X, const T &Y) { + return !(X < Y); +} + +template <typename T> bool operator>=(const T &X, const Optional<T> &Y) { + return !(X < Y); +} + +raw_ostream &operator<<(raw_ostream &OS, NoneType); + +template <typename T, typename = decltype(std::declval<raw_ostream &>() + << std::declval<const T &>())> +raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) { + if (O) + OS << *O; + else + OS << None; + return OS; +} + +} // end namespace llvm + +#endif // LLVM_ADT_OPTIONAL_H diff --git a/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h b/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h new file mode 100644 index 000000000..fa6bf1504 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h @@ -0,0 +1,243 @@ +//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the PointerIntPair class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_POINTERINTPAIR_H +#define LLVM_ADT_POINTERINTPAIR_H + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstdint> +#include <limits> + +namespace llvm { + +template <typename T> struct DenseMapInfo; +template <typename PointerT, unsigned IntBits, typename PtrTraits> +struct PointerIntPairInfo; + +/// PointerIntPair - This class implements a pair of a pointer and small +/// integer. It is designed to represent this in the space required by one +/// pointer by bitmangling the integer into the low part of the pointer. This +/// can only be done for small integers: typically up to 3 bits, but it depends +/// on the number of bits available according to PointerLikeTypeTraits for the +/// type. +/// +/// Note that PointerIntPair always puts the IntVal part in the highest bits +/// possible. For example, PointerIntPair<void*, 1, bool> will put the bit for +/// the bool into bit #2, not bit #0, which allows the low two bits to be used +/// for something else. For example, this allows: +/// PointerIntPair<PointerIntPair<void*, 1, bool>, 1, bool> +/// ... and the two bools will land in different bits. +template <typename PointerTy, unsigned IntBits, typename IntType = unsigned, + typename PtrTraits = PointerLikeTypeTraits<PointerTy>, + typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>> +class PointerIntPair { + // Used by MSVC visualizer and generally helpful for debugging/visualizing. + using InfoTy = Info; + intptr_t Value = 0; + +public: + constexpr PointerIntPair() = default; + + PointerIntPair(PointerTy PtrVal, IntType IntVal) { + setPointerAndInt(PtrVal, IntVal); + } + + explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); } + + PointerTy getPointer() const { return Info::getPointer(Value); } + + IntType getInt() const { return (IntType)Info::getInt(Value); } + + void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION { + Value = Info::updatePointer(Value, PtrVal); + } + + void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION { + Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal)); + } + + void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION { + Value = Info::updatePointer(0, PtrVal); + } + + void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION { + Value = Info::updateInt(Info::updatePointer(0, PtrVal), + static_cast<intptr_t>(IntVal)); + } + + PointerTy const *getAddrOfPointer() const { + return const_cast<PointerIntPair *>(this)->getAddrOfPointer(); + } + + PointerTy *getAddrOfPointer() { + assert(Value == reinterpret_cast<intptr_t>(getPointer()) && + "Can only return the address if IntBits is cleared and " + "PtrTraits doesn't change the pointer"); + return reinterpret_cast<PointerTy *>(&Value); + } + + void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); } + + void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION { + Value = reinterpret_cast<intptr_t>(Val); + } + + static PointerIntPair getFromOpaqueValue(void *V) { + PointerIntPair P; + P.setFromOpaqueValue(V); + return P; + } + + // Allow PointerIntPairs to be created from const void * if and only if the + // pointer type could be created from a const void *. + static PointerIntPair getFromOpaqueValue(const void *V) { + (void)PtrTraits::getFromVoidPointer(V); + return getFromOpaqueValue(const_cast<void *>(V)); + } + + bool operator==(const PointerIntPair &RHS) const { + return Value == RHS.Value; + } + + bool operator!=(const PointerIntPair &RHS) const { + return Value != RHS.Value; + } + + bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; } + bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; } + + bool operator<=(const PointerIntPair &RHS) const { + return Value <= RHS.Value; + } + + bool operator>=(const PointerIntPair &RHS) const { + return Value >= RHS.Value; + } +}; + +// Specialize is_trivially_copyable to avoid limitation of llvm::is_trivially_copyable +// when compiled with gcc 4.9. +template <typename PointerTy, unsigned IntBits, typename IntType, + typename PtrTraits, + typename Info> +struct is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> : std::true_type { +#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE + static_assert(std::is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>::value, + "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable"); +#endif +}; + + +template <typename PointerT, unsigned IntBits, typename PtrTraits> +struct PointerIntPairInfo { + static_assert(PtrTraits::NumLowBitsAvailable < + std::numeric_limits<uintptr_t>::digits, + "cannot use a pointer type that has all bits free"); + static_assert(IntBits <= PtrTraits::NumLowBitsAvailable, + "PointerIntPair with integer size too large for pointer"); + enum : uintptr_t { + /// PointerBitMask - The bits that come from the pointer. + PointerBitMask = + ~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1), + + /// IntShift - The number of low bits that we reserve for other uses, and + /// keep zero. + IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits, + + /// IntMask - This is the unshifted mask for valid bits of the int type. + IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1), + + // ShiftedIntMask - This is the bits for the integer shifted in place. + ShiftedIntMask = (uintptr_t)(IntMask << IntShift) + }; + + static PointerT getPointer(intptr_t Value) { + return PtrTraits::getFromVoidPointer( + reinterpret_cast<void *>(Value & PointerBitMask)); + } + + static intptr_t getInt(intptr_t Value) { + return (Value >> IntShift) & IntMask; + } + + static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) { + intptr_t PtrWord = + reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr)); + assert((PtrWord & ~PointerBitMask) == 0 && + "Pointer is not sufficiently aligned"); + // Preserve all low bits, just update the pointer. + return PtrWord | (OrigValue & ~PointerBitMask); + } + + static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) { + intptr_t IntWord = static_cast<intptr_t>(Int); + assert((IntWord & ~IntMask) == 0 && "Integer too large for field"); + + // Preserve all bits other than the ones we are updating. + return (OrigValue & ~ShiftedIntMask) | IntWord << IntShift; + } +}; + +// Provide specialization of DenseMapInfo for PointerIntPair. +template <typename PointerTy, unsigned IntBits, typename IntType> +struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> { + using Ty = PointerIntPair<PointerTy, IntBits, IntType>; + + static Ty getEmptyKey() { + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable; + return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val)); + } + + static Ty getTombstoneKey() { + uintptr_t Val = static_cast<uintptr_t>(-2); + Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable; + return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val)); + } + + static unsigned getHashValue(Ty V) { + uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue()); + return unsigned(IV) ^ unsigned(IV >> 9); + } + + static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; } +}; + +// Teach SmallPtrSet that PointerIntPair is "basically a pointer". +template <typename PointerTy, unsigned IntBits, typename IntType, + typename PtrTraits> +struct PointerLikeTypeTraits< + PointerIntPair<PointerTy, IntBits, IntType, PtrTraits>> { + static inline void * + getAsVoidPointer(const PointerIntPair<PointerTy, IntBits, IntType> &P) { + return P.getOpaqueValue(); + } + + static inline PointerIntPair<PointerTy, IntBits, IntType> + getFromVoidPointer(void *P) { + return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P); + } + + static inline PointerIntPair<PointerTy, IntBits, IntType> + getFromVoidPointer(const void *P) { + return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P); + } + + enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits }; +}; + +} // end namespace llvm + +#endif // LLVM_ADT_POINTERINTPAIR_H diff --git a/third_party/llvm-project/include/llvm/ADT/PointerUnion.h b/third_party/llvm-project/include/llvm/ADT/PointerUnion.h new file mode 100644 index 000000000..98c905775 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/PointerUnion.h @@ -0,0 +1,309 @@ +//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the PointerUnion class, which is a discriminated union of +// pointer types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_POINTERUNION_H +#define LLVM_ADT_POINTERUNION_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> +#include <cstddef> +#include <cstdint> + +namespace llvm { + +template <typename T> struct PointerUnionTypeSelectorReturn { + using Return = T; +}; + +/// Get a type based on whether two types are the same or not. +/// +/// For: +/// +/// \code +/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return; +/// \endcode +/// +/// Ret will be EQ type if T1 is same as T2 or NE type otherwise. +template <typename T1, typename T2, typename RET_EQ, typename RET_NE> +struct PointerUnionTypeSelector { + using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return; +}; + +template <typename T, typename RET_EQ, typename RET_NE> +struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> { + using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return; +}; + +template <typename T1, typename T2, typename RET_EQ, typename RET_NE> +struct PointerUnionTypeSelectorReturn< + PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> { + using Return = + typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return; +}; + +namespace pointer_union_detail { + /// Determine the number of bits required to store integers with values < n. + /// This is ceil(log2(n)). + constexpr int bitsRequired(unsigned n) { + return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0; + } + + template <typename... Ts> constexpr int lowBitsAvailable() { + return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...}); + } + + /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index + /// is the index of T in Us, or sizeof...(Us) if T does not appear in the + /// list. + template <typename T, typename ...Us> struct TypeIndex; + template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> { + static constexpr int Index = 0; + }; + template <typename T, typename U, typename... Us> + struct TypeIndex<T, U, Us...> { + static constexpr int Index = 1 + TypeIndex<T, Us...>::Index; + }; + template <typename T> struct TypeIndex<T> { + static constexpr int Index = 0; + }; + + /// Find the first type in a list of types. + template <typename T, typename...> struct GetFirstType { + using type = T; + }; + + /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion + /// for the template arguments. + template <typename ...PTs> class PointerUnionUIntTraits { + public: + static inline void *getAsVoidPointer(void *P) { return P; } + static inline void *getFromVoidPointer(void *P) { return P; } + static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>(); + }; + + /// Implement assigment in terms of construction. + template <typename Derived, typename T> struct AssignableFrom { + Derived &operator=(T t) { + return static_cast<Derived &>(*this) = Derived(t); + } + }; + + template <typename Derived, typename ValTy, int I, typename ...Types> + class PointerUnionMembers; + + template <typename Derived, typename ValTy, int I> + class PointerUnionMembers<Derived, ValTy, I> { + protected: + ValTy Val; + PointerUnionMembers() = default; + PointerUnionMembers(ValTy Val) : Val(Val) {} + + friend struct PointerLikeTypeTraits<Derived>; + }; + + template <typename Derived, typename ValTy, int I, typename Type, + typename ...Types> + class PointerUnionMembers<Derived, ValTy, I, Type, Types...> + : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> { + using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>; + public: + using Base::Base; + PointerUnionMembers() = default; + PointerUnionMembers(Type V) + : Base(ValTy(const_cast<void *>( + PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), + I)) {} + + using Base::operator=; + Derived &operator=(Type V) { + this->Val = ValTy( + const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), + I); + return static_cast<Derived &>(*this); + }; + }; +} + +/// A discriminated union of two or more pointer types, with the discriminator +/// in the low bit of the pointer. +/// +/// This implementation is extremely efficient in space due to leveraging the +/// low bits of the pointer, while exposing a natural and type-safe API. +/// +/// Common use patterns would be something like this: +/// PointerUnion<int*, float*> P; +/// P = (int*)0; +/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0" +/// X = P.get<int*>(); // ok. +/// Y = P.get<float*>(); // runtime assertion failure. +/// Z = P.get<double*>(); // compile time failure. +/// P = (float*)0; +/// Y = P.get<float*>(); // ok. +/// X = P.get<int*>(); // runtime assertion failure. +template <typename... PTs> +class PointerUnion + : public pointer_union_detail::PointerUnionMembers< + PointerUnion<PTs...>, + PointerIntPair< + void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int, + pointer_union_detail::PointerUnionUIntTraits<PTs...>>, + 0, PTs...> { + // The first type is special because we want to directly cast a pointer to a + // default-initialized union to a pointer to the first type. But we don't + // want PointerUnion to be a 'template <typename First, typename ...Rest>' + // because it's much more convenient to have a name for the whole pack. So + // split off the first type here. + using First = typename pointer_union_detail::GetFirstType<PTs...>::type; + using Base = typename PointerUnion::PointerUnionMembers; + +public: + PointerUnion() = default; + + PointerUnion(std::nullptr_t) : PointerUnion() {} + using Base::Base; + + /// Test if the pointer held in the union is null, regardless of + /// which type it is. + bool isNull() const { return !this->Val.getPointer(); } + + explicit operator bool() const { return !isNull(); } + + /// Test if the Union currently holds the type matching T. + template <typename T> int is() const { + constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index; + static_assert(Index < sizeof...(PTs), + "PointerUnion::is<T> given type not in the union"); + return this->Val.getInt() == Index; + } + + /// Returns the value of the specified pointer type. + /// + /// If the specified pointer type is incorrect, assert. + template <typename T> T get() const { + assert(is<T>() && "Invalid accessor called"); + return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer()); + } + + /// Returns the current pointer if it is of the specified pointer type, + /// otherwises returns null. + template <typename T> T dyn_cast() const { + if (is<T>()) + return get<T>(); + return T(); + } + + /// If the union is set to the first pointer type get an address pointing to + /// it. + First const *getAddrOfPtr1() const { + return const_cast<PointerUnion *>(this)->getAddrOfPtr1(); + } + + /// If the union is set to the first pointer type get an address pointing to + /// it. + First *getAddrOfPtr1() { + assert(is<First>() && "Val is not the first pointer"); + assert( + PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == + this->Val.getPointer() && + "Can't get the address because PointerLikeTypeTraits changes the ptr"); + return const_cast<First *>( + reinterpret_cast<const First *>(this->Val.getAddrOfPointer())); + } + + /// Assignment from nullptr which just clears the union. + const PointerUnion &operator=(std::nullptr_t) { + this->Val.initWithPointer(nullptr); + return *this; + } + + /// Assignment from elements of the union. + using Base::operator=; + + void *getOpaqueValue() const { return this->Val.getOpaqueValue(); } + static inline PointerUnion getFromOpaqueValue(void *VP) { + PointerUnion V; + V.Val = decltype(V.Val)::getFromOpaqueValue(VP); + return V; + } +}; + +template <typename ...PTs> +bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { + return lhs.getOpaqueValue() == rhs.getOpaqueValue(); +} + +template <typename ...PTs> +bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { + return lhs.getOpaqueValue() != rhs.getOpaqueValue(); +} + +template <typename ...PTs> +bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { + return lhs.getOpaqueValue() < rhs.getOpaqueValue(); +} + +// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has +// # low bits available = min(PT1bits,PT2bits)-1. +template <typename ...PTs> +struct PointerLikeTypeTraits<PointerUnion<PTs...>> { + static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) { + return P.getOpaqueValue(); + } + + static inline PointerUnion<PTs...> getFromVoidPointer(void *P) { + return PointerUnion<PTs...>::getFromOpaqueValue(P); + } + + // The number of bits available are the min of the pointer types minus the + // bits needed for the discriminator. + static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype( + PointerUnion<PTs...>::Val)>::NumLowBitsAvailable; +}; + +/// A pointer union of three pointer types. See documentation for PointerUnion +/// for usage. +template <typename PT1, typename PT2, typename PT3> +using PointerUnion3 = PointerUnion<PT1, PT2, PT3>; + +/// A pointer union of four pointer types. See documentation for PointerUnion +/// for usage. +template <typename PT1, typename PT2, typename PT3, typename PT4> +using PointerUnion4 = PointerUnion<PT1, PT2, PT3, PT4>; + +// Teach DenseMap how to use PointerUnions as keys. +template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> { + using Union = PointerUnion<PTs...>; + using FirstInfo = + DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>; + + static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); } + + static inline Union getTombstoneKey() { + return Union(FirstInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const Union &UnionVal) { + intptr_t key = (intptr_t)UnionVal.getOpaqueValue(); + return DenseMapInfo<intptr_t>::getHashValue(key); + } + + static bool isEqual(const Union &LHS, const Union &RHS) { + return LHS == RHS; + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_POINTERUNION_H diff --git a/third_party/llvm-project/include/llvm/ADT/STLExtras.h b/third_party/llvm-project/include/llvm/ADT/STLExtras.h new file mode 100644 index 000000000..274933bc5 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/STLExtras.h @@ -0,0 +1,1578 @@ +//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains some templates that are useful if you are working with the +// STL at all. +// +// No library is required when using these functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STLEXTRAS_H +#define LLVM_ADT_STLEXTRAS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Config/abi-breaking.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <functional> +#include <initializer_list> +#include <iterator> +#include <limits> +#include <memory> +#include <tuple> +#include <type_traits> +#include <utility> + +#ifdef EXPENSIVE_CHECKS +#include <random> // for std::mt19937 +#endif + +namespace llvm { + +// Only used by compiler if both template types are the same. Useful when +// using SFINAE to test for the existence of member functions. +template <typename T, T> struct SameType; + +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 namespace detail + +//===----------------------------------------------------------------------===// +// Extra additions to <type_traits> +//===----------------------------------------------------------------------===// + +template <typename T> +struct negation : std::integral_constant<bool, !bool(T::value)> {}; + +template <typename...> struct conjunction : std::true_type {}; +template <typename B1> struct conjunction<B1> : B1 {}; +template <typename B1, typename... Bn> +struct conjunction<B1, Bn...> + : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; + +template <typename T> struct make_const_ptr { + using type = + typename std::add_pointer<typename std::add_const<T>::type>::type; +}; + +template <typename T> struct make_const_ref { + using type = typename std::add_lvalue_reference< + typename std::add_const<T>::type>::type; +}; + +//===----------------------------------------------------------------------===// +// Extra additions to <functional> +//===----------------------------------------------------------------------===// + +template <class Ty> struct identity { + using argument_type = Ty; + + Ty &operator()(Ty &self) const { + return self; + } + const Ty &operator()(const Ty &self) const { + return self; + } +}; + +/// An efficient, type-erasing, non-owning reference to a callable. This is +/// intended for use as the type of a function parameter that is not used +/// after the function in question returns. +/// +/// This class does not own the callable, so it is not in general safe to store +/// a function_ref. +template<typename Fn> class function_ref; + +template<typename Ret, typename ...Params> +class function_ref<Ret(Params...)> { + Ret (*callback)(intptr_t callable, Params ...params) = nullptr; + intptr_t callable; + + template<typename Callable> + static Ret callback_fn(intptr_t callable, Params ...params) { + return (*reinterpret_cast<Callable*>(callable))( + std::forward<Params>(params)...); + } + +public: + function_ref() = default; + function_ref(std::nullptr_t) {} + + template <typename Callable> + function_ref(Callable &&callable, + typename std::enable_if< + !std::is_same<typename std::remove_reference<Callable>::type, + function_ref>::value>::type * = nullptr) + : callback(callback_fn<typename std::remove_reference<Callable>::type>), + callable(reinterpret_cast<intptr_t>(&callable)) {} + + Ret operator()(Params ...params) const { + return callback(callable, std::forward<Params>(params)...); + } + + operator bool() const { return callback; } +}; + +// deleter - Very very very simple method that is used to invoke operator +// delete on something. It is used like this: +// +// for_each(V.begin(), B.end(), deleter<Interval>); +template <class T> +inline void deleter(T *Ptr) { + delete Ptr; +} + +//===----------------------------------------------------------------------===// +// Extra additions to <iterator> +//===----------------------------------------------------------------------===// + +namespace adl_detail { + +using std::begin; + +template <typename ContainerTy> +auto adl_begin(ContainerTy &&container) + -> decltype(begin(std::forward<ContainerTy>(container))) { + return begin(std::forward<ContainerTy>(container)); +} + +using std::end; + +template <typename ContainerTy> +auto adl_end(ContainerTy &&container) + -> decltype(end(std::forward<ContainerTy>(container))) { + return end(std::forward<ContainerTy>(container)); +} + +using std::swap; + +template <typename T> +void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval<T>(), + std::declval<T>()))) { + swap(std::forward<T>(lhs), std::forward<T>(rhs)); +} + +} // end namespace adl_detail + +template <typename ContainerTy> +auto adl_begin(ContainerTy &&container) + -> decltype(adl_detail::adl_begin(std::forward<ContainerTy>(container))) { + return adl_detail::adl_begin(std::forward<ContainerTy>(container)); +} + +template <typename ContainerTy> +auto adl_end(ContainerTy &&container) + -> decltype(adl_detail::adl_end(std::forward<ContainerTy>(container))) { + return adl_detail::adl_end(std::forward<ContainerTy>(container)); +} + +template <typename T> +void adl_swap(T &&lhs, T &&rhs) noexcept( + noexcept(adl_detail::adl_swap(std::declval<T>(), std::declval<T>()))) { + adl_detail::adl_swap(std::forward<T>(lhs), std::forward<T>(rhs)); +} + +/// Test whether \p RangeOrContainer is empty. Similar to C++17 std::empty. +template <typename T> +constexpr bool empty(const T &RangeOrContainer) { + return adl_begin(RangeOrContainer) == adl_end(RangeOrContainer); +} + +// mapped_iterator - This is a simple iterator adapter that causes a function to +// be applied whenever operator* is invoked on the iterator. + +template <typename ItTy, typename FuncTy, + typename FuncReturnTy = + decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))> +class mapped_iterator + : public iterator_adaptor_base< + mapped_iterator<ItTy, FuncTy>, ItTy, + typename std::iterator_traits<ItTy>::iterator_category, + typename std::remove_reference<FuncReturnTy>::type> { +public: + mapped_iterator(ItTy U, FuncTy F) + : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {} + + ItTy getCurrent() { return this->I; } + + FuncReturnTy operator*() { return F(*this->I); } + +private: + FuncTy F; +}; + +// map_iterator - Provide a convenient way to create mapped_iterators, just like +// make_pair is useful for creating pairs... +template <class ItTy, class FuncTy> +inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) { + return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F)); +} + +template <class ContainerTy, class FuncTy> +auto map_range(ContainerTy &&C, FuncTy F) + -> decltype(make_range(map_iterator(C.begin(), F), + map_iterator(C.end(), F))) { + return make_range(map_iterator(C.begin(), F), map_iterator(C.end(), F)); +} + +/// Helper to determine if type T has a member called rbegin(). +template <typename Ty> class has_rbegin_impl { + using yes = char[1]; + using no = char[2]; + + template <typename Inner> + static yes& test(Inner *I, decltype(I->rbegin()) * = nullptr); + + template <typename> + static no& test(...); + +public: + static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes); +}; + +/// Metafunction to determine if T& or T has a member called rbegin(). +template <typename Ty> +struct has_rbegin : has_rbegin_impl<typename std::remove_reference<Ty>::type> { +}; + +// Returns an iterator_range over the given container which iterates in reverse. +// Note that the container must have rbegin()/rend() methods for this to work. +template <typename ContainerTy> +auto reverse(ContainerTy &&C, + typename std::enable_if<has_rbegin<ContainerTy>::value>::type * = + nullptr) -> decltype(make_range(C.rbegin(), C.rend())) { + return make_range(C.rbegin(), C.rend()); +} + +// Returns a std::reverse_iterator wrapped around the given iterator. +template <typename IteratorTy> +std::reverse_iterator<IteratorTy> make_reverse_iterator(IteratorTy It) { + return std::reverse_iterator<IteratorTy>(It); +} + +// Returns an iterator_range over the given container which iterates in reverse. +// Note that the container must have begin()/end() methods which return +// bidirectional iterators for this to work. +template <typename ContainerTy> +auto reverse( + ContainerTy &&C, + typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * = nullptr) + -> decltype(make_range(llvm::make_reverse_iterator(std::end(C)), + llvm::make_reverse_iterator(std::begin(C)))) { + return make_range(llvm::make_reverse_iterator(std::end(C)), + llvm::make_reverse_iterator(std::begin(C))); +} + +/// An iterator adaptor that filters the elements of given inner iterators. +/// +/// The predicate parameter should be a callable object that accepts the wrapped +/// iterator's reference type and returns a bool. When incrementing or +/// decrementing the iterator, it will call the predicate on each element and +/// skip any where it returns false. +/// +/// \code +/// int A[] = { 1, 2, 3, 4 }; +/// auto R = make_filter_range(A, [](int N) { return N % 2 == 1; }); +/// // R contains { 1, 3 }. +/// \endcode +/// +/// Note: filter_iterator_base implements support for forward iteration. +/// filter_iterator_impl exists to provide support for bidirectional iteration, +/// conditional on whether the wrapped iterator supports it. +template <typename WrappedIteratorT, typename PredicateT, typename IterTag> +class filter_iterator_base + : public iterator_adaptor_base< + filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>, + WrappedIteratorT, + typename std::common_type< + IterTag, typename std::iterator_traits< + WrappedIteratorT>::iterator_category>::type> { + using BaseT = iterator_adaptor_base< + filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>, + WrappedIteratorT, + typename std::common_type< + IterTag, typename std::iterator_traits< + WrappedIteratorT>::iterator_category>::type>; + +protected: + WrappedIteratorT End; + PredicateT Pred; + + void findNextValid() { + while (this->I != End && !Pred(*this->I)) + BaseT::operator++(); + } + + // Construct the iterator. The begin iterator needs to know where the end + // is, so that it can properly stop when it gets there. The end iterator only + // needs the predicate to support bidirectional iteration. + filter_iterator_base(WrappedIteratorT Begin, WrappedIteratorT End, + PredicateT Pred) + : BaseT(Begin), End(End), Pred(Pred) { + findNextValid(); + } + +public: + using BaseT::operator++; + + filter_iterator_base &operator++() { + BaseT::operator++(); + findNextValid(); + return *this; + } +}; + +/// Specialization of filter_iterator_base for forward iteration only. +template <typename WrappedIteratorT, typename PredicateT, + typename IterTag = std::forward_iterator_tag> +class filter_iterator_impl + : public filter_iterator_base<WrappedIteratorT, PredicateT, IterTag> { + using BaseT = filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>; + +public: + filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, + PredicateT Pred) + : BaseT(Begin, End, Pred) {} +}; + +/// Specialization of filter_iterator_base for bidirectional iteration. +template <typename WrappedIteratorT, typename PredicateT> +class filter_iterator_impl<WrappedIteratorT, PredicateT, + std::bidirectional_iterator_tag> + : public filter_iterator_base<WrappedIteratorT, PredicateT, + std::bidirectional_iterator_tag> { + using BaseT = filter_iterator_base<WrappedIteratorT, PredicateT, + std::bidirectional_iterator_tag>; + void findPrevValid() { + while (!this->Pred(*this->I)) + BaseT::operator--(); + } + +public: + using BaseT::operator--; + + filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, + PredicateT Pred) + : BaseT(Begin, End, Pred) {} + + filter_iterator_impl &operator--() { + BaseT::operator--(); + findPrevValid(); + return *this; + } +}; + +namespace detail { + +template <bool is_bidirectional> struct fwd_or_bidi_tag_impl { + using type = std::forward_iterator_tag; +}; + +template <> struct fwd_or_bidi_tag_impl<true> { + using type = std::bidirectional_iterator_tag; +}; + +/// Helper which sets its type member to forward_iterator_tag if the category +/// of \p IterT does not derive from bidirectional_iterator_tag, and to +/// bidirectional_iterator_tag otherwise. +template <typename IterT> struct fwd_or_bidi_tag { + using type = typename fwd_or_bidi_tag_impl<std::is_base_of< + std::bidirectional_iterator_tag, + typename std::iterator_traits<IterT>::iterator_category>::value>::type; +}; + +} // namespace detail + +/// Defines filter_iterator to a suitable specialization of +/// filter_iterator_impl, based on the underlying iterator's category. +template <typename WrappedIteratorT, typename PredicateT> +using filter_iterator = filter_iterator_impl< + WrappedIteratorT, PredicateT, + typename detail::fwd_or_bidi_tag<WrappedIteratorT>::type>; + +/// Convenience function that takes a range of elements and a predicate, +/// and return a new filter_iterator range. +/// +/// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the +/// lifetime of that temporary is not kept by the returned range object, and the +/// temporary is going to be dropped on the floor after the make_iterator_range +/// full expression that contains this function call. +template <typename RangeT, typename PredicateT> +iterator_range<filter_iterator<detail::IterOfRange<RangeT>, PredicateT>> +make_filter_range(RangeT &&Range, PredicateT Pred) { + using FilterIteratorT = + filter_iterator<detail::IterOfRange<RangeT>, PredicateT>; + return make_range( + FilterIteratorT(std::begin(std::forward<RangeT>(Range)), + std::end(std::forward<RangeT>(Range)), Pred), + FilterIteratorT(std::end(std::forward<RangeT>(Range)), + std::end(std::forward<RangeT>(Range)), Pred)); +} + +/// A pseudo-iterator adaptor that is designed to implement "early increment" +/// style loops. +/// +/// This is *not a normal iterator* and should almost never be used directly. It +/// is intended primarily to be used with range based for loops and some range +/// algorithms. +/// +/// The iterator isn't quite an `OutputIterator` or an `InputIterator` but +/// somewhere between them. The constraints of these iterators are: +/// +/// - On construction or after being incremented, it is comparable and +/// dereferencable. It is *not* incrementable. +/// - After being dereferenced, it is neither comparable nor dereferencable, it +/// is only incrementable. +/// +/// This means you can only dereference the iterator once, and you can only +/// increment it once between dereferences. +template <typename WrappedIteratorT> +class early_inc_iterator_impl + : public iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>, + WrappedIteratorT, std::input_iterator_tag> { + using BaseT = + iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>, + WrappedIteratorT, std::input_iterator_tag>; + + using PointerT = typename std::iterator_traits<WrappedIteratorT>::pointer; + +protected: +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + bool IsEarlyIncremented = false; +#endif + +public: + early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {} + + using BaseT::operator*; + typename BaseT::reference operator*() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + assert(!IsEarlyIncremented && "Cannot dereference twice!"); + IsEarlyIncremented = true; +#endif + return *(this->I)++; + } + + using BaseT::operator++; + early_inc_iterator_impl &operator++() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + assert(IsEarlyIncremented && "Cannot increment before dereferencing!"); + IsEarlyIncremented = false; +#endif + return *this; + } + + using BaseT::operator==; + bool operator==(const early_inc_iterator_impl &RHS) const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + assert(!IsEarlyIncremented && "Cannot compare after dereferencing!"); +#endif + return BaseT::operator==(RHS); + } +}; + +/// Make a range that does early increment to allow mutation of the underlying +/// range without disrupting iteration. +/// +/// The underlying iterator will be incremented immediately after it is +/// dereferenced, allowing deletion of the current node or insertion of nodes to +/// not disrupt iteration provided they do not invalidate the *next* iterator -- +/// the current iterator can be invalidated. +/// +/// This requires a very exact pattern of use that is only really suitable to +/// range based for loops and other range algorithms that explicitly guarantee +/// to dereference exactly once each element, and to increment exactly once each +/// element. +template <typename RangeT> +iterator_range<early_inc_iterator_impl<detail::IterOfRange<RangeT>>> +make_early_inc_range(RangeT &&Range) { + using EarlyIncIteratorT = + early_inc_iterator_impl<detail::IterOfRange<RangeT>>; + return make_range(EarlyIncIteratorT(std::begin(std::forward<RangeT>(Range))), + EarlyIncIteratorT(std::end(std::forward<RangeT>(Range)))); +} + +// forward declarations required by zip_shortest/zip_first/zip_longest +template <typename R, typename UnaryPredicate> +bool all_of(R &&range, UnaryPredicate P); +template <typename R, typename UnaryPredicate> +bool any_of(R &&range, UnaryPredicate P); + +namespace detail { + +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 { + using type = std::tuple<decltype(*declval<Iters>())...>; +}; + +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; + +protected: + template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const { + return value_type(*std::get<Ns>(iterators)...); + } + + template <size_t... Ns> + decltype(iterators) tup_inc(std::index_sequence<Ns...>) const { + return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...); + } + + template <size_t... Ns> + decltype(iterators) tup_dec(std::index_sequence<Ns...>) const { + return std::tuple<Iters...>(std::prev(std::get<Ns>(iterators))...); + } + +public: + zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {} + + value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); } + + const value_type operator*() const { + return deref(std::index_sequence_for<Iters...>{}); + } + + ZipType &operator++() { + iterators = tup_inc(std::index_sequence_for<Iters...>{}); + return *reinterpret_cast<ZipType *>(this); + } + + ZipType &operator--() { + static_assert(Base::IsBidirectional, + "All inner iterators must be at least bidirectional."); + iterators = tup_dec(std::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_common<zip_shortest<Iters...>, Iters...> { + template <size_t... Ns> + bool test(const zip_shortest<Iters...> &other, + std::index_sequence<Ns...>) const { + return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) != + std::get<Ns>(other.iterators)...}, + identity<bool>{}); + } + +public: + using Base = zip_common<zip_shortest<Iters...>, Iters...>; + + zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {} + + bool operator==(const zip_shortest<Iters...> &other) const { + return !test(other, std::index_sequence_for<Iters...>{}); + } +}; + +template <template <typename...> class ItType, typename... Args> class zippy { +public: + 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(std::index_sequence<Ns...>) const { + return iterator(std::begin(std::get<Ns>(ts))...); + } + template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const { + return iterator(std::end(std::get<Ns>(ts))...); + } + +public: + zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {} + + iterator begin() const { + return begin_impl(std::index_sequence_for<Args...>{}); + } + iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); } +}; + +} // end namespace detail + +/// zip iterator for two or more iteratable types. +template <typename T, typename U, typename... Args> +detail::zippy<detail::zip_shortest, T, U, Args...> zip(T &&t, U &&u, + Args &&... args) { + return detail::zippy<detail::zip_shortest, T, U, Args...>( + std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); +} + +/// zip iterator that, for the sake of efficiency, assumes the first iteratee to +/// be the shortest. +template <typename T, typename U, typename... Args> +detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u, + Args &&... args) { + return detail::zippy<detail::zip_first, T, U, Args...>( + std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); +} + +namespace detail { +template <typename Iter> +static Iter next_or_end(const Iter &I, const Iter &End) { + if (I == End) + return End; + return std::next(I); +} + +template <typename Iter> +static auto deref_or_none(const Iter &I, const Iter &End) + -> llvm::Optional<typename std::remove_const< + typename std::remove_reference<decltype(*I)>::type>::type> { + if (I == End) + return None; + return *I; +} + +template <typename Iter> struct ZipLongestItemType { + using type = + llvm::Optional<typename std::remove_const<typename std::remove_reference< + decltype(*std::declval<Iter>())>::type>::type>; +}; + +template <typename... Iters> struct ZipLongestTupleType { + using type = std::tuple<typename ZipLongestItemType<Iters>::type...>; +}; + +template <typename... Iters> +class zip_longest_iterator + : public iterator_facade_base< + zip_longest_iterator<Iters...>, + typename std::common_type< + std::forward_iterator_tag, + typename std::iterator_traits<Iters>::iterator_category...>::type, + typename ZipLongestTupleType<Iters...>::type, + typename std::iterator_traits<typename std::tuple_element< + 0, std::tuple<Iters...>>::type>::difference_type, + typename ZipLongestTupleType<Iters...>::type *, + typename ZipLongestTupleType<Iters...>::type> { +public: + using value_type = typename ZipLongestTupleType<Iters...>::type; + +private: + std::tuple<Iters...> iterators; + std::tuple<Iters...> end_iterators; + + template <size_t... Ns> + bool test(const zip_longest_iterator<Iters...> &other, + std::index_sequence<Ns...>) const { + return llvm::any_of( + std::initializer_list<bool>{std::get<Ns>(this->iterators) != + std::get<Ns>(other.iterators)...}, + identity<bool>{}); + } + + template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const { + return value_type( + deref_or_none(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...); + } + + template <size_t... Ns> + decltype(iterators) tup_inc(std::index_sequence<Ns...>) const { + return std::tuple<Iters...>( + next_or_end(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...); + } + +public: + zip_longest_iterator(std::pair<Iters &&, Iters &&>... ts) + : iterators(std::forward<Iters>(ts.first)...), + end_iterators(std::forward<Iters>(ts.second)...) {} + + value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); } + + value_type operator*() const { + return deref(std::index_sequence_for<Iters...>{}); + } + + zip_longest_iterator<Iters...> &operator++() { + iterators = tup_inc(std::index_sequence_for<Iters...>{}); + return *this; + } + + bool operator==(const zip_longest_iterator<Iters...> &other) const { + return !test(other, std::index_sequence_for<Iters...>{}); + } +}; + +template <typename... Args> class zip_longest_range { +public: + using iterator = + zip_longest_iterator<decltype(adl_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(std::index_sequence<Ns...>) const { + return iterator(std::make_pair(adl_begin(std::get<Ns>(ts)), + adl_end(std::get<Ns>(ts)))...); + } + + template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const { + return iterator(std::make_pair(adl_end(std::get<Ns>(ts)), + adl_end(std::get<Ns>(ts)))...); + } + +public: + zip_longest_range(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {} + + iterator begin() const { + return begin_impl(std::index_sequence_for<Args...>{}); + } + iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); } +}; +} // namespace detail + +/// Iterate over two or more iterators at the same time. Iteration continues +/// until all iterators reach the end. The llvm::Optional only contains a value +/// if the iterator has not reached the end. +template <typename T, typename U, typename... Args> +detail::zip_longest_range<T, U, Args...> zip_longest(T &&t, U &&u, + Args &&... args) { + return detail::zip_longest_range<T, U, Args...>( + std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); +} + +/// Iterator wrapper that concatenates sequences together. +/// +/// This can concatenate different iterators, even with different types, into +/// a single iterator provided the value types of all the concatenated +/// iterators expose `reference` and `pointer` types that can be converted to +/// `ValueT &` and `ValueT *` respectively. It doesn't support more +/// interesting/customized pointer or reference types. +/// +/// Currently this only supports forward or higher iterator categories as +/// inputs and always exposes a forward iterator interface. +template <typename ValueT, typename... IterTs> +class concat_iterator + : public iterator_facade_base<concat_iterator<ValueT, IterTs...>, + std::forward_iterator_tag, ValueT> { + using BaseT = typename concat_iterator::iterator_facade_base; + + /// We store both the current and end iterators for each concatenated + /// sequence in a tuple of pairs. + /// + /// Note that something like iterator_range seems nice at first here, but the + /// range properties are of little benefit and end up getting in the way + /// because we need to do mutation on the current iterators. + std::tuple<IterTs...> Begins; + std::tuple<IterTs...> Ends; + + /// Attempts to increment a specific iterator. + /// + /// Returns true if it was able to increment the iterator. Returns false if + /// the iterator is already at the end iterator. + template <size_t Index> bool incrementHelper() { + auto &Begin = std::get<Index>(Begins); + auto &End = std::get<Index>(Ends); + if (Begin == End) + return false; + + ++Begin; + return true; + } + + /// Increments the first non-end iterator. + /// + /// It is an error to call this with all iterators at the end. + template <size_t... Ns> void increment(std::index_sequence<Ns...>) { + // Build a sequence of functions to increment each iterator if possible. + bool (concat_iterator::*IncrementHelperFns[])() = { + &concat_iterator::incrementHelper<Ns>...}; + + // Loop over them, and stop as soon as we succeed at incrementing one. + for (auto &IncrementHelperFn : IncrementHelperFns) + if ((this->*IncrementHelperFn)()) + return; + + llvm_unreachable("Attempted to increment an end concat iterator!"); + } + + /// Returns null if the specified iterator is at the end. Otherwise, + /// dereferences the iterator and returns the address of the resulting + /// reference. + template <size_t Index> ValueT *getHelper() const { + auto &Begin = std::get<Index>(Begins); + auto &End = std::get<Index>(Ends); + if (Begin == End) + return nullptr; + + return &*Begin; + } + + /// Finds the first non-end iterator, dereferences, and returns the resulting + /// reference. + /// + /// It is an error to call this with all iterators at the end. + template <size_t... Ns> ValueT &get(std::index_sequence<Ns...>) const { + // Build a sequence of functions to get from iterator if possible. + ValueT *(concat_iterator::*GetHelperFns[])() const = { + &concat_iterator::getHelper<Ns>...}; + + // Loop over them, and return the first result we find. + for (auto &GetHelperFn : GetHelperFns) + if (ValueT *P = (this->*GetHelperFn)()) + return *P; + + llvm_unreachable("Attempted to get a pointer from an end concat iterator!"); + } + +public: + /// Constructs an iterator from a squence of ranges. + /// + /// We need the full range to know how to switch between each of the + /// iterators. + template <typename... RangeTs> + explicit concat_iterator(RangeTs &&... Ranges) + : Begins(std::begin(Ranges)...), Ends(std::end(Ranges)...) {} + + using BaseT::operator++; + + concat_iterator &operator++() { + increment(std::index_sequence_for<IterTs...>()); + return *this; + } + + ValueT &operator*() const { + return get(std::index_sequence_for<IterTs...>()); + } + + bool operator==(const concat_iterator &RHS) const { + return Begins == RHS.Begins && Ends == RHS.Ends; + } +}; + +namespace detail { + +/// Helper to store a sequence of ranges being concatenated and access them. +/// +/// This is designed to facilitate providing actual storage when temporaries +/// are passed into the constructor such that we can use it as part of range +/// based for loops. +template <typename ValueT, typename... RangeTs> class concat_range { +public: + using iterator = + concat_iterator<ValueT, + decltype(std::begin(std::declval<RangeTs &>()))...>; + +private: + std::tuple<RangeTs...> Ranges; + + template <size_t... Ns> iterator begin_impl(std::index_sequence<Ns...>) { + return iterator(std::get<Ns>(Ranges)...); + } + template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) { + return iterator(make_range(std::end(std::get<Ns>(Ranges)), + std::end(std::get<Ns>(Ranges)))...); + } + +public: + concat_range(RangeTs &&... Ranges) + : Ranges(std::forward<RangeTs>(Ranges)...) {} + + iterator begin() { return begin_impl(std::index_sequence_for<RangeTs...>{}); } + iterator end() { return end_impl(std::index_sequence_for<RangeTs...>{}); } +}; + +} // end namespace detail + +/// Concatenated range across two or more ranges. +/// +/// The desired value type must be explicitly specified. +template <typename ValueT, typename... RangeTs> +detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) { + static_assert(sizeof...(RangeTs) > 1, + "Need more than one range to concatenate!"); + return detail::concat_range<ValueT, RangeTs...>( + std::forward<RangeTs>(Ranges)...); +} + +//===----------------------------------------------------------------------===// +// Extra additions to <utility> +//===----------------------------------------------------------------------===// + +/// Function object to check whether the first component of a std::pair +/// compares less than the first component of another std::pair. +struct less_first { + template <typename T> bool operator()(const T &lhs, const T &rhs) const { + return lhs.first < rhs.first; + } +}; + +/// Function object to check whether the second component of a std::pair +/// compares less than the second component of another std::pair. +struct less_second { + template <typename T> bool operator()(const T &lhs, const T &rhs) const { + return lhs.second < rhs.second; + } +}; + +/// \brief Function object to apply a binary function to the first component of +/// a std::pair. +template<typename FuncTy> +struct on_first { + FuncTy func; + + template <typename T> + auto operator()(const T &lhs, const T &rhs) const + -> decltype(func(lhs.first, rhs.first)) { + return func(lhs.first, rhs.first); + } +}; + +/// Utility type to build an inheritance chain that makes it easy to rank +/// overload candidates. +template <int N> struct rank : rank<N - 1> {}; +template <> struct rank<0> {}; + +/// traits class for checking whether type T is one of any of the given +/// types in the variadic list. +template <typename T, typename... Ts> struct is_one_of { + static const bool value = false; +}; + +template <typename T, typename U, typename... Ts> +struct is_one_of<T, U, Ts...> { + static const bool value = + std::is_same<T, U>::value || is_one_of<T, Ts...>::value; +}; + +/// traits class for checking whether type T is a base class for all +/// the given types in the variadic list. +template <typename T, typename... Ts> struct are_base_of { + static const bool value = true; +}; + +template <typename T, typename U, typename... Ts> +struct are_base_of<T, U, Ts...> { + static const bool value = + std::is_base_of<T, U>::value && are_base_of<T, Ts...>::value; +}; + +//===----------------------------------------------------------------------===// +// Extra additions for arrays +//===----------------------------------------------------------------------===// + +/// Find the length of an array. +template <class T, std::size_t N> +constexpr inline size_t array_lengthof(T (&)[N]) { + return N; +} + +/// Adapt std::less<T> for array_pod_sort. +template<typename T> +inline int array_pod_sort_comparator(const void *P1, const void *P2) { + if (std::less<T>()(*reinterpret_cast<const T*>(P1), + *reinterpret_cast<const T*>(P2))) + return -1; + if (std::less<T>()(*reinterpret_cast<const T*>(P2), + *reinterpret_cast<const T*>(P1))) + return 1; + return 0; +} + +/// get_array_pod_sort_comparator - This is an internal helper function used to +/// get type deduction of T right. +template<typename T> +inline int (*get_array_pod_sort_comparator(const T &)) + (const void*, const void*) { + return array_pod_sort_comparator<T>; +} + +/// array_pod_sort - This sorts an array with the specified start and end +/// extent. This is just like std::sort, except that it calls qsort instead of +/// using an inlined template. qsort is slightly slower than std::sort, but +/// most sorts are not performance critical in LLVM and std::sort has to be +/// template instantiated for each type, leading to significant measured code +/// bloat. This function should generally be used instead of std::sort where +/// possible. +/// +/// This function assumes that you have simple POD-like types that can be +/// compared with std::less and can be moved with memcpy. If this isn't true, +/// you should use std::sort. +/// +/// NOTE: If qsort_r were portable, we could allow a custom comparator and +/// default to std::less. +template<class IteratorTy> +inline void array_pod_sort(IteratorTy Start, IteratorTy End) { + // Don't inefficiently call qsort with one element or trigger undefined + // behavior with an empty sequence. + auto NElts = End - Start; + if (NElts <= 1) return; +#ifdef EXPENSIVE_CHECKS + std::mt19937 Generator(std::random_device{}()); + std::shuffle(Start, End, Generator); +#endif + qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start)); +} + +template <class IteratorTy> +inline void array_pod_sort( + IteratorTy Start, IteratorTy End, + int (*Compare)( + const typename std::iterator_traits<IteratorTy>::value_type *, + const typename std::iterator_traits<IteratorTy>::value_type *)) { + // Don't inefficiently call qsort with one element or trigger undefined + // behavior with an empty sequence. + auto NElts = End - Start; + if (NElts <= 1) return; +#ifdef EXPENSIVE_CHECKS + std::mt19937 Generator(std::random_device{}()); + std::shuffle(Start, End, Generator); +#endif + qsort(&*Start, NElts, sizeof(*Start), + reinterpret_cast<int (*)(const void *, const void *)>(Compare)); +} + +// Provide wrappers to std::sort which shuffle the elements before sorting +// to help uncover non-deterministic behavior (PR35135). +template <typename IteratorTy> +inline void sort(IteratorTy Start, IteratorTy End) { +#ifdef EXPENSIVE_CHECKS + std::mt19937 Generator(std::random_device{}()); + std::shuffle(Start, End, Generator); +#endif + std::sort(Start, End); +} + +template <typename Container> inline void sort(Container &&C) { + llvm::sort(adl_begin(C), adl_end(C)); +} + +template <typename IteratorTy, typename Compare> +inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) { +#ifdef EXPENSIVE_CHECKS + std::mt19937 Generator(std::random_device{}()); + std::shuffle(Start, End, Generator); +#endif + std::sort(Start, End, Comp); +} + +template <typename Container, typename Compare> +inline void sort(Container &&C, Compare Comp) { + llvm::sort(adl_begin(C), adl_end(C), Comp); +} + +//===----------------------------------------------------------------------===// +// Extra additions to <algorithm> +//===----------------------------------------------------------------------===// + +/// For a container of pointers, deletes the pointers and then clears the +/// container. +template<typename Container> +void DeleteContainerPointers(Container &C) { + for (auto V : C) + delete V; + C.clear(); +} + +/// In a container of pairs (usually a map) whose second element is a pointer, +/// deletes the second elements and then clears the container. +template<typename Container> +void DeleteContainerSeconds(Container &C) { + for (auto &V : C) + delete V.second; + C.clear(); +} + +/// Get the size of a range. This is a wrapper function around std::distance +/// which is only enabled when the operation is O(1). +template <typename R> +auto size(R &&Range, typename std::enable_if< + std::is_same<typename std::iterator_traits<decltype( + Range.begin())>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) + -> decltype(std::distance(Range.begin(), Range.end())) { + return std::distance(Range.begin(), Range.end()); +} + +/// Provide wrappers to std::for_each which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename UnaryPredicate> +UnaryPredicate for_each(R &&Range, UnaryPredicate P) { + return std::for_each(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::all_of which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, typename UnaryPredicate> +bool all_of(R &&Range, UnaryPredicate P) { + return std::all_of(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::any_of which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, typename UnaryPredicate> +bool any_of(R &&Range, UnaryPredicate P) { + return std::any_of(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::none_of which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, typename UnaryPredicate> +bool none_of(R &&Range, UnaryPredicate P) { + return std::none_of(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::find which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, typename T> +auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) { + return std::find(adl_begin(Range), adl_end(Range), Val); +} + +/// Provide wrappers to std::find_if which take ranges instead of having to pass +/// begin/end explicitly. +template <typename R, typename UnaryPredicate> +auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::find_if(adl_begin(Range), adl_end(Range), P); +} + +template <typename R, typename UnaryPredicate> +auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::find_if_not(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::remove_if which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename UnaryPredicate> +auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::remove_if(adl_begin(Range), adl_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(adl_begin(Range), adl_end(Range), Out, P); +} + +template <typename R, typename OutputIt> +OutputIt copy(R &&Range, OutputIt Out) { + return std::copy(adl_begin(Range), adl_end(Range), Out); +} + +/// Wrapper function around std::find to detect if an element exists +/// in a container. +template <typename R, typename E> +bool is_contained(R &&Range, const E &Element) { + return std::find(adl_begin(Range), adl_end(Range), Element) != adl_end(Range); +} + +/// Wrapper function around std::count to count the number of times an element +/// \p Element occurs in the given range \p Range. +template <typename R, typename E> +auto count(R &&Range, const E &Element) -> + typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type { + return std::count(adl_begin(Range), adl_end(Range), Element); +} + +/// Wrapper function around std::count_if to count the number of times an +/// element satisfying a given predicate occurs in a range. +template <typename R, typename UnaryPredicate> +auto count_if(R &&Range, UnaryPredicate P) -> + typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type { + return std::count_if(adl_begin(Range), adl_end(Range), P); +} + +/// Wrapper function around std::transform to apply a function to a range and +/// store the result elsewhere. +template <typename R, typename OutputIt, typename UnaryPredicate> +OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) { + return std::transform(adl_begin(Range), adl_end(Range), d_first, P); +} + +/// Provide wrappers to std::partition which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename UnaryPredicate> +auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::partition(adl_begin(Range), adl_end(Range), P); +} + +/// Provide wrappers to std::lower_bound which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename T> +auto lower_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) { + return std::lower_bound(adl_begin(Range), adl_end(Range), + std::forward<T>(Value)); +} + +template <typename R, typename T, typename Compare> +auto lower_bound(R &&Range, T &&Value, Compare C) + -> decltype(adl_begin(Range)) { + return std::lower_bound(adl_begin(Range), adl_end(Range), + std::forward<T>(Value), C); +} + +/// Provide wrappers to std::upper_bound which take ranges instead of having to +/// pass begin/end explicitly. +template <typename R, typename T> +auto upper_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) { + return std::upper_bound(adl_begin(Range), adl_end(Range), + std::forward<T>(Value)); +} + +template <typename R, typename T, typename Compare> +auto upper_bound(R &&Range, T &&Value, Compare C) + -> decltype(adl_begin(Range)) { + return std::upper_bound(adl_begin(Range), adl_end(Range), + std::forward<T>(Value), C); +} + +template <typename R> +void stable_sort(R &&Range) { + std::stable_sort(adl_begin(Range), adl_end(Range)); +} + +template <typename R, typename Compare> +void stable_sort(R &&Range, Compare C) { + std::stable_sort(adl_begin(Range), adl_end(Range), C); +} + +/// Binary search for the first iterator in a range where a predicate is false. +/// Requires that C is always true below some limit, and always false above it. +template <typename R, typename Predicate, + typename Val = decltype(*adl_begin(std::declval<R>()))> +auto partition_point(R &&Range, Predicate P) -> decltype(adl_begin(Range)) { + return std::partition_point(adl_begin(Range), adl_end(Range), P); +} + +/// Wrapper function around std::equal to detect if all elements +/// in a container are same. +template <typename R> +bool is_splat(R &&Range) { + size_t range_size = size(Range); + return range_size != 0 && (range_size == 1 || + std::equal(adl_begin(Range) + 1, adl_end(Range), adl_begin(Range))); +} + +/// 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 {adl_begin(Range), adl_end(Range)}; +} + +/// Provide a container algorithm similar to C++ Library Fundamentals v2's +/// `erase_if` which is equivalent to: +/// +/// C.erase(remove_if(C, pred), C.end()); +/// +/// This version works for any container with an erase method call accepting +/// two iterators. +template <typename Container, typename UnaryPredicate> +void erase_if(Container &C, UnaryPredicate P) { + C.erase(remove_if(C, P), C.end()); +} + +/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with +/// the range [ValIt, ValEnd) (which is not from the same container). +template<typename Container, typename RandomAccessIterator> +void replace(Container &Cont, typename Container::iterator ContIt, + typename Container::iterator ContEnd, RandomAccessIterator ValIt, + RandomAccessIterator ValEnd) { + while (true) { + if (ValIt == ValEnd) { + Cont.erase(ContIt, ContEnd); + return; + } else if (ContIt == ContEnd) { + Cont.insert(ContIt, ValIt, ValEnd); + return; + } + *ContIt++ = *ValIt++; + } +} + +/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with +/// the range R. +template<typename Container, typename Range = std::initializer_list< + typename Container::value_type>> +void replace(Container &Cont, typename Container::iterator ContIt, + typename Container::iterator ContEnd, Range R) { + replace(Cont, ContIt, ContEnd, R.begin(), R.end()); +} + +//===----------------------------------------------------------------------===// +// Extra additions to <memory> +//===----------------------------------------------------------------------===// + +struct FreeDeleter { + void operator()(void* v) { + ::free(v); + } +}; + +template<typename First, typename Second> +struct pair_hash { + size_t operator()(const std::pair<First, Second> &P) const { + return std::hash<First>()(P.first) * 31 + std::hash<Second>()(P.second); + } +}; + +/// Binary functor that adapts to any other binary functor after dereferencing +/// operands. +template <typename T> struct deref { + T func; + + // Could be further improved to cope with non-derivable functors and + // non-binary functors (should be a variadic template member function + // operator()). + template <typename A, typename B> + auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) { + assert(lhs); + assert(rhs); + return func(*lhs, *rhs); + } +}; + +namespace detail { + +template <typename R> class enumerator_iter; + +template <typename R> struct result_pair { + using value_reference = + typename std::iterator_traits<IterOfRange<R>>::reference; + + friend class enumerator_iter<R>; + + result_pair() = default; + result_pair(std::size_t Index, IterOfRange<R> Iter) + : Index(Index), Iter(Iter) {} + + result_pair<R> &operator=(const result_pair<R> &Other) { + Index = Other.Index; + Iter = Other.Iter; + return *this; + } + + std::size_t index() const { return Index; } + const value_reference value() const { return *Iter; } + value_reference value() { return *Iter; } + +private: + std::size_t Index = std::numeric_limits<std::size_t>::max(); + IterOfRange<R> Iter; +}; + +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>; + +public: + explicit enumerator_iter(IterOfRange<R> EndIter) + : Result(std::numeric_limits<size_t>::max(), EndIter) {} + + 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(R &&Range) : TheRange(std::forward<R>(Range)) {} + + 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 TheRange; +}; + +} // end namespace detail + +/// Given an input range, returns a new range whose values are are pair (A,B) +/// such that A is the 0-based index of the item in the sequence, and B is +/// the value from the original sequence. Example: +/// +/// std::vector<char> Items = {'A', 'B', 'C', 'D'}; +/// for (auto X : enumerate(Items)) { +/// printf("Item %d - %c\n", X.index(), X.value()); +/// } +/// +/// Output: +/// Item 0 - A +/// Item 1 - B +/// Item 2 - C +/// Item 3 - D +/// +template <typename R> detail::enumerator<R> enumerate(R &&TheRange) { + return detail::enumerator<R>(std::forward<R>(TheRange)); +} + +namespace detail { + +template <typename F, typename Tuple, std::size_t... I> +auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>) + -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) { + return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...); +} + +} // end namespace detail + +/// Given an input tuple (a1, a2, ..., an), pass the arguments of the +/// tuple variadically to f as if by calling f(a1, a2, ..., an) and +/// return the result. +template <typename F, typename Tuple> +auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl( + std::forward<F>(f), std::forward<Tuple>(t), + std::make_index_sequence< + std::tuple_size<typename std::decay<Tuple>::type>::value>{})) { + using Indices = std::make_index_sequence< + std::tuple_size<typename std::decay<Tuple>::type>::value>; + + return detail::apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t), + Indices{}); +} + +/// Return true if the sequence [Begin, End) has exactly N items. Runs in O(N) +/// time. Not meant for use with random-access iterators. +template <typename IterTy> +bool hasNItems( + IterTy &&Begin, IterTy &&End, unsigned N, + typename std::enable_if< + !std::is_same< + typename std::iterator_traits<typename std::remove_reference< + decltype(Begin)>::type>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) { + for (; N; --N, ++Begin) + if (Begin == End) + return false; // Too few. + return Begin == End; +} + +/// Return true if the sequence [Begin, End) has N or more items. Runs in O(N) +/// time. Not meant for use with random-access iterators. +template <typename IterTy> +bool hasNItemsOrMore( + IterTy &&Begin, IterTy &&End, unsigned N, + typename std::enable_if< + !std::is_same< + typename std::iterator_traits<typename std::remove_reference< + decltype(Begin)>::type>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) { + for (; N; --N, ++Begin) + if (Begin == End) + return false; // Too few. + return true; +} + +/// Returns a raw pointer that represents the same address as the argument. +/// +/// The late bound return should be removed once we move to C++14 to better +/// align with the C++20 declaration. Also, this implementation can be removed +/// once we move to C++20 where it's defined as std::to_addres() +/// +/// The std::pointer_traits<>::to_address(p) variations of these overloads has +/// not been implemented. +template <class Ptr> auto to_address(const Ptr &P) -> decltype(P.operator->()) { + return P.operator->(); +} +template <class T> constexpr T *to_address(T *P) { return P; } + +} // end namespace llvm + +#endif // LLVM_ADT_STLEXTRAS_H diff --git a/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h b/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h new file mode 100644 index 000000000..1d8280063 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h @@ -0,0 +1,511 @@ +//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallPtrSet class. See the doxygen comment for +// SmallPtrSetImplBase for more details on the algorithm used. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLPTRSET_H +#define LLVM_ADT_SMALLPTRSET_H + +#include "llvm/ADT/EpochTracker.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ReverseIteration.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <iterator> +#include <utility> + +namespace llvm { + +/// SmallPtrSetImplBase - This is the common code shared among all the +/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one +/// for small and one for large sets. +/// +/// Small sets use an array of pointers allocated in the SmallPtrSet object, +/// which is treated as a simple array of pointers. When a pointer is added to +/// the set, the array is scanned to see if the element already exists, if not +/// the element is 'pushed back' onto the array. If we run out of space in the +/// array, we grow into the 'large set' case. SmallSet should be used when the +/// sets are often small. In this case, no memory allocation is used, and only +/// light-weight and cache-efficient scanning is used. +/// +/// Large sets use a classic exponentially-probed hash table. Empty buckets are +/// represented with an illegal pointer value (-1) to allow null pointers to be +/// inserted. Tombstones are represented with another illegal pointer value +/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or +/// more. When this happens, the table is doubled in size. +/// +class SmallPtrSetImplBase : public DebugEpochBase { + friend class SmallPtrSetIteratorImpl; + +protected: + /// SmallArray - Points to a fixed size set of buckets, used in 'small mode'. + const void **SmallArray; + /// CurArray - This is the current set of buckets. If equal to SmallArray, + /// then the set is in 'small mode'. + const void **CurArray; + /// CurArraySize - The allocated size of CurArray, always a power of two. + unsigned CurArraySize; + + /// Number of elements in CurArray that contain a value or are a tombstone. + /// If small, all these elements are at the beginning of CurArray and the rest + /// is uninitialized. + unsigned NumNonEmpty; + /// Number of tombstones in CurArray. + unsigned NumTombstones; + + // Helpers to copy and move construct a SmallPtrSet. + SmallPtrSetImplBase(const void **SmallStorage, + const SmallPtrSetImplBase &that); + SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize, + SmallPtrSetImplBase &&that); + + explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) + : SmallArray(SmallStorage), CurArray(SmallStorage), + CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) { + assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 && + "Initial size must be a power of two!"); + } + + ~SmallPtrSetImplBase() { + if (!isSmall()) + free(CurArray); + } + +public: + using size_type = unsigned; + + SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete; + + LLVM_NODISCARD bool empty() const { return size() == 0; } + size_type size() const { return NumNonEmpty - NumTombstones; } + + void clear() { + incrementEpoch(); + // If the capacity of the array is huge, and the # elements used is small, + // shrink the array. + if (!isSmall()) { + if (size() * 4 < CurArraySize && CurArraySize > 32) + return shrink_and_clear(); + // Fill the array with empty markers. + memset(CurArray, -1, CurArraySize * sizeof(void *)); + } + + NumNonEmpty = 0; + NumTombstones = 0; + } + +protected: + static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); } + + static void *getEmptyMarker() { + // Note that -1 is chosen to make clear() efficiently implementable with + // memset and because it's not a valid pointer value. + return reinterpret_cast<void*>(-1); + } + + const void **EndPointer() const { + return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize; + } + + /// insert_imp - This returns true if the pointer was new to the set, false if + /// it was already in the set. This is hidden from the client so that the + /// derived class can check that the right type of pointer is passed in. + std::pair<const void *const *, bool> insert_imp(const void *Ptr) { + if (isSmall()) { + // Check to see if it is already in the set. + const void **LastTombstone = nullptr; + for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty; + APtr != E; ++APtr) { + const void *Value = *APtr; + if (Value == Ptr) + return std::make_pair(APtr, false); + if (Value == getTombstoneMarker()) + LastTombstone = APtr; + } + + // Did we find any tombstone marker? + if (LastTombstone != nullptr) { + *LastTombstone = Ptr; + --NumTombstones; + incrementEpoch(); + return std::make_pair(LastTombstone, true); + } + + // Nope, there isn't. If we stay small, just 'pushback' now. + if (NumNonEmpty < CurArraySize) { + SmallArray[NumNonEmpty++] = Ptr; + incrementEpoch(); + return std::make_pair(SmallArray + (NumNonEmpty - 1), true); + } + // Otherwise, hit the big set case, which will call grow. + } + return insert_imp_big(Ptr); + } + + /// erase_imp - If the set contains the specified pointer, remove it and + /// return true, otherwise return false. This is hidden from the client so + /// that the derived class can check that the right type of pointer is passed + /// in. + bool erase_imp(const void * Ptr) { + const void *const *P = find_imp(Ptr); + if (P == EndPointer()) + return false; + + const void **Loc = const_cast<const void **>(P); + assert(*Loc == Ptr && "broken find!"); + *Loc = getTombstoneMarker(); + NumTombstones++; + return true; + } + + /// Returns the raw pointer needed to construct an iterator. If element not + /// found, this will be EndPointer. Otherwise, it will be a pointer to the + /// slot which stores Ptr; + const void *const * find_imp(const void * Ptr) const { + if (isSmall()) { + // Linear search for the item. + for (const void *const *APtr = SmallArray, + *const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr) + if (*APtr == Ptr) + return APtr; + return EndPointer(); + } + + // Big set case. + auto *Bucket = FindBucketFor(Ptr); + if (*Bucket == Ptr) + return Bucket; + return EndPointer(); + } + +private: + bool isSmall() const { return CurArray == SmallArray; } + + std::pair<const void *const *, bool> insert_imp_big(const void *Ptr); + + const void * const *FindBucketFor(const void *Ptr) const; + void shrink_and_clear(); + + /// Grow - Allocate a larger backing store for the buckets and move it over. + void Grow(unsigned NewSize); + +protected: + /// swap - Swaps the elements of two sets. + /// Note: This method assumes that both sets have the same small size. + void swap(SmallPtrSetImplBase &RHS); + + void CopyFrom(const SmallPtrSetImplBase &RHS); + void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS); + +private: + /// Code shared by MoveFrom() and move constructor. + void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS); + /// Code shared by CopyFrom() and copy constructor. + void CopyHelper(const SmallPtrSetImplBase &RHS); +}; + +/// SmallPtrSetIteratorImpl - This is the common base class shared between all +/// instances of SmallPtrSetIterator. +class SmallPtrSetIteratorImpl { +protected: + const void *const *Bucket; + const void *const *End; + +public: + explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E) + : Bucket(BP), End(E) { + if (shouldReverseIterate()) { + RetreatIfNotValid(); + return; + } + AdvanceIfNotValid(); + } + + bool operator==(const SmallPtrSetIteratorImpl &RHS) const { + return Bucket == RHS.Bucket; + } + bool operator!=(const SmallPtrSetIteratorImpl &RHS) const { + return Bucket != RHS.Bucket; + } + +protected: + /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket + /// that is. This is guaranteed to stop because the end() bucket is marked + /// valid. + void AdvanceIfNotValid() { + assert(Bucket <= End); + while (Bucket != End && + (*Bucket == SmallPtrSetImplBase::getEmptyMarker() || + *Bucket == SmallPtrSetImplBase::getTombstoneMarker())) + ++Bucket; + } + void RetreatIfNotValid() { + assert(Bucket >= End); + while (Bucket != End && + (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() || + Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) { + --Bucket; + } + } +}; + +/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet. +template <typename PtrTy> +class SmallPtrSetIterator : public SmallPtrSetIteratorImpl, + DebugEpochBase::HandleBase { + using PtrTraits = PointerLikeTypeTraits<PtrTy>; + +public: + using value_type = PtrTy; + using reference = PtrTy; + using pointer = PtrTy; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + explicit SmallPtrSetIterator(const void *const *BP, const void *const *E, + const DebugEpochBase &Epoch) + : SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {} + + // Most methods provided by baseclass. + + const PtrTy operator*() const { + assert(isHandleInSync() && "invalid iterator access!"); + if (shouldReverseIterate()) { + assert(Bucket > End); + return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1])); + } + assert(Bucket < End); + return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket)); + } + + inline SmallPtrSetIterator& operator++() { // Preincrement + assert(isHandleInSync() && "invalid iterator access!"); + if (shouldReverseIterate()) { + --Bucket; + RetreatIfNotValid(); + return *this; + } + ++Bucket; + AdvanceIfNotValid(); + return *this; + } + + SmallPtrSetIterator operator++(int) { // Postincrement + SmallPtrSetIterator tmp = *this; + ++*this; + return tmp; + } +}; + +/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next +/// power of two (which means N itself if N is already a power of two). +template<unsigned N> +struct RoundUpToPowerOfTwo; + +/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a +/// helper template used to implement RoundUpToPowerOfTwo. +template<unsigned N, bool isPowerTwo> +struct RoundUpToPowerOfTwoH { + enum { Val = N }; +}; +template<unsigned N> +struct RoundUpToPowerOfTwoH<N, false> { + enum { + // We could just use NextVal = N+1, but this converges faster. N|(N-1) sets + // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111. + Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val + }; +}; + +template<unsigned N> +struct RoundUpToPowerOfTwo { + enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val }; +}; + +/// A templated base class for \c SmallPtrSet which provides the +/// typesafe interface that is common across all small sizes. +/// +/// This is particularly useful for passing around between interface boundaries +/// 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; + using PtrTraits = PointerLikeTypeTraits<PtrType>; + using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>; + +protected: + // Constructors that forward to the base. + SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that) + : SmallPtrSetImplBase(SmallStorage, that) {} + SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize, + SmallPtrSetImpl &&that) + : SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {} + explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize) + : SmallPtrSetImplBase(SmallStorage, SmallSize) {} + +public: + using iterator = SmallPtrSetIterator<PtrType>; + using const_iterator = SmallPtrSetIterator<PtrType>; + using key_type = ConstPtrType; + using value_type = PtrType; + + SmallPtrSetImpl(const SmallPtrSetImpl &) = delete; + + /// Inserts Ptr if and only if there is no element in the container equal to + /// Ptr. The bool component of the returned pair is true if and only if the + /// insertion takes place, and the iterator component of the pair points to + /// the element equal to Ptr. + std::pair<iterator, bool> insert(PtrType Ptr) { + auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr)); + return std::make_pair(makeIterator(p.first), p.second); + } + + /// erase - If the set contains the specified pointer, remove it and return + /// true, otherwise return false. + 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(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; } + iterator find(ConstPtrType Ptr) const { + return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr))); + } + + template <typename IterT> + void insert(IterT I, IterT E) { + for (; I != E; ++I) + insert(*I); + } + + void insert(std::initializer_list<PtrType> IL) { + insert(IL.begin(), IL.end()); + } + + iterator begin() const { + if (shouldReverseIterate()) + return makeIterator(EndPointer() - 1); + return makeIterator(CurArray); + } + 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 (shouldReverseIterate()) + return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this); + return iterator(P, EndPointer(), *this); + } +}; + +/// Equality comparison for SmallPtrSet. +/// +/// Iterates over elements of LHS confirming that each value from LHS is also in +/// RHS, and that no additional values are in RHS. +template <typename PtrType> +bool operator==(const SmallPtrSetImpl<PtrType> &LHS, + const SmallPtrSetImpl<PtrType> &RHS) { + if (LHS.size() != RHS.size()) + return false; + + for (const auto *KV : LHS) + if (!RHS.count(KV)) + return false; + + return true; +} + +/// Inequality comparison for SmallPtrSet. +/// +/// Equivalent to !(LHS == RHS). +template <typename PtrType> +bool operator!=(const SmallPtrSetImpl<PtrType> &LHS, + const SmallPtrSetImpl<PtrType> &RHS) { + return !(LHS == RHS); +} + +/// SmallPtrSet - This class implements a set which is optimized for holding +/// SmallSize or less elements. This internally rounds up SmallSize to the next +/// power of two if it is not already a power of two. See the comments above +/// SmallPtrSetImplBase for details of the algorithm. +template<class PtrType, unsigned SmallSize> +class SmallPtrSet : public SmallPtrSetImpl<PtrType> { + // In small mode SmallPtrSet uses linear search for the elements, so it is + // not a good idea to choose this value too high. You may consider using a + // DenseSet<> instead if you expect many elements in the set. + static_assert(SmallSize <= 32, "SmallSize should be small"); + + using BaseT = SmallPtrSetImpl<PtrType>; + + // Make sure that SmallSize is a power of two, round up if not. + enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val }; + /// SmallStorage - Fixed size storage used in 'small mode'. + const void *SmallStorage[SmallSizePowTwo]; + +public: + SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {} + SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {} + SmallPtrSet(SmallPtrSet &&that) + : BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {} + + template<typename It> + SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) { + this->insert(I, E); + } + + SmallPtrSet(std::initializer_list<PtrType> IL) + : BaseT(SmallStorage, SmallSizePowTwo) { + this->insert(IL.begin(), IL.end()); + } + + SmallPtrSet<PtrType, SmallSize> & + operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) { + if (&RHS != this) + this->CopyFrom(RHS); + return *this; + } + + SmallPtrSet<PtrType, SmallSize> & + operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) { + if (&RHS != this) + this->MoveFrom(SmallSizePowTwo, std::move(RHS)); + return *this; + } + + SmallPtrSet<PtrType, SmallSize> & + operator=(std::initializer_list<PtrType> IL) { + this->clear(); + this->insert(IL.begin(), IL.end()); + return *this; + } + + /// swap - Swaps the elements of two sets. + void swap(SmallPtrSet<PtrType, SmallSize> &RHS) { + SmallPtrSetImplBase::swap(RHS); + } +}; + +} // end namespace llvm + +namespace std { + + /// Implement std::swap in terms of SmallPtrSet swap. + template<class T, unsigned N> + inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) { + LHS.swap(RHS); + } + +} // end namespace std + +#endif // LLVM_ADT_SMALLPTRSET_H diff --git a/third_party/llvm-project/include/llvm/ADT/SmallSet.h b/third_party/llvm-project/include/llvm/ADT/SmallSet.h new file mode 100644 index 000000000..a03fa7dd8 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/SmallSet.h @@ -0,0 +1,278 @@ +//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallSet class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLSET_H +#define LLVM_ADT_SMALLSET_H + +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/type_traits.h" +#include <cstddef> +#include <functional> +#include <set> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// SmallSetIterator - This class implements a const_iterator for SmallSet by +/// delegating to the underlying SmallVector or Set iterators. +template <typename T, unsigned N, typename C> +class SmallSetIterator + : public iterator_facade_base<SmallSetIterator<T, N, C>, + std::forward_iterator_tag, T> { +private: + using SetIterTy = typename std::set<T, C>::const_iterator; + using VecIterTy = typename SmallVector<T, N>::const_iterator; + using SelfTy = SmallSetIterator<T, N, C>; + + /// Iterators to the parts of the SmallSet containing the data. They are set + /// depending on isSmall. + union { + SetIterTy SetIter; + VecIterTy VecIter; + }; + + bool isSmall; + +public: + SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {} + + SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), isSmall(true) {} + + // Spell out destructor, copy/move constructor and assignment operators for + // MSVC STL, where set<T>::const_iterator is not trivially copy constructible. + ~SmallSetIterator() { + if (isSmall) + VecIter.~VecIterTy(); + else + SetIter.~SetIterTy(); + } + + SmallSetIterator(const SmallSetIterator &Other) : isSmall(Other.isSmall) { + if (isSmall) + VecIter = Other.VecIter; + else + // Use placement new, to make sure SetIter is properly constructed, even + // if it is not trivially copy-able (e.g. in MSVC). + new (&SetIter) SetIterTy(Other.SetIter); + } + + SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) { + if (isSmall) + VecIter = std::move(Other.VecIter); + else + // Use placement new, to make sure SetIter is properly constructed, even + // if it is not trivially copy-able (e.g. in MSVC). + new (&SetIter) SetIterTy(std::move(Other.SetIter)); + } + + SmallSetIterator& operator=(const SmallSetIterator& Other) { + // Call destructor for SetIter, so it gets properly destroyed if it is + // not trivially destructible in case we are setting VecIter. + if (!isSmall) + SetIter.~SetIterTy(); + + isSmall = Other.isSmall; + if (isSmall) + VecIter = Other.VecIter; + else + new (&SetIter) SetIterTy(Other.SetIter); + return *this; + } + + SmallSetIterator& operator=(SmallSetIterator&& Other) { + // Call destructor for SetIter, so it gets properly destroyed if it is + // not trivially destructible in case we are setting VecIter. + if (!isSmall) + SetIter.~SetIterTy(); + + isSmall = Other.isSmall; + if (isSmall) + VecIter = std::move(Other.VecIter); + else + new (&SetIter) SetIterTy(std::move(Other.SetIter)); + return *this; + } + + bool operator==(const SmallSetIterator &RHS) const { + if (isSmall != RHS.isSmall) + return false; + if (isSmall) + return VecIter == RHS.VecIter; + return SetIter == RHS.SetIter; + } + + SmallSetIterator &operator++() { // Preincrement + if (isSmall) + VecIter++; + else + SetIter++; + return *this; + } + + const T &operator*() const { return isSmall ? *VecIter : *SetIter; } +}; + +/// SmallSet - This maintains a set of unique values, optimizing for the case +/// when the set is small (less than N). In this case, the set can be +/// maintained with no mallocs. If the set gets large, we expand to using an +/// std::set to maintain reasonable lookup times. +template <typename T, unsigned N, typename C = std::less<T>> +class SmallSet { + /// Use a SmallVector to hold the elements here (even though it will never + /// reach its 'large' stage) to avoid calling the default ctors of elements + /// we will never use. + SmallVector<T, N> Vector; + std::set<T, C> Set; + + using VIterator = typename SmallVector<T, N>::const_iterator; + using mutable_iterator = typename SmallVector<T, N>::iterator; + + // In small mode SmallPtrSet uses linear search for the elements, so it is + // not a good idea to choose this value too high. You may consider using a + // DenseSet<> instead if you expect many elements in the set. + static_assert(N <= 32, "N should be small"); + +public: + using size_type = size_t; + using const_iterator = SmallSetIterator<T, N, C>; + + SmallSet() = default; + + LLVM_NODISCARD bool empty() const { + return Vector.empty() && Set.empty(); + } + + size_type size() const { + return isSmall() ? Vector.size() : Set.size(); + } + + /// count - Return 1 if the element is in the set, 0 otherwise. + size_type count(const T &V) const { + if (isSmall()) { + // Since the collection is small, just do a linear search. + return vfind(V) == Vector.end() ? 0 : 1; + } else { + return Set.count(V); + } + } + + /// insert - Insert an element into the set if it isn't already there. + /// Returns true if the element is inserted (it was not in the set before). + /// The first value of the returned pair is unused and provided for + /// partial compatibility with the standard library self-associative container + /// concept. + // FIXME: Add iterators that abstract over the small and large form, and then + // return those here. + std::pair<NoneType, bool> insert(const T &V) { + if (!isSmall()) + return std::make_pair(None, Set.insert(V).second); + + VIterator I = vfind(V); + if (I != Vector.end()) // Don't reinsert if it already exists. + return std::make_pair(None, false); + if (Vector.size() < N) { + Vector.push_back(V); + return std::make_pair(None, true); + } + + // Otherwise, grow from vector to set. + while (!Vector.empty()) { + Set.insert(Vector.back()); + Vector.pop_back(); + } + Set.insert(V); + return std::make_pair(None, true); + } + + template <typename IterT> + void insert(IterT I, IterT E) { + for (; I != E; ++I) + insert(*I); + } + + bool erase(const T &V) { + if (!isSmall()) + return Set.erase(V); + for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I) + if (*I == V) { + Vector.erase(I); + return true; + } + return false; + } + + void clear() { + Vector.clear(); + Set.clear(); + } + + const_iterator begin() const { + if (isSmall()) + return {Vector.begin()}; + return {Set.begin()}; + } + + const_iterator end() const { + if (isSmall()) + return {Vector.end()}; + return {Set.end()}; + } + +private: + bool isSmall() const { return Set.empty(); } + + VIterator vfind(const T &V) const { + for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I) + if (*I == V) + return I; + return Vector.end(); + } +}; + +/// If this set is of pointer values, transparently switch over to using +/// SmallPtrSet for performance. +template <typename PointeeType, unsigned N> +class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {}; + +/// Equality comparison for SmallSet. +/// +/// Iterates over elements of LHS confirming that each element is also a member +/// of RHS, and that RHS contains no additional values. +/// Equivalent to N calls to RHS.count. +/// For small-set mode amortized complexity is O(N^2) +/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if +/// every hash collides). +template <typename T, unsigned LN, unsigned RN, typename C> +bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) { + if (LHS.size() != RHS.size()) + return false; + + // All elements in LHS must also be in RHS + return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); }); +} + +/// Inequality comparison for SmallSet. +/// +/// Equivalent to !(LHS == RHS). See operator== for performance notes. +template <typename T, unsigned LN, unsigned RN, typename C> +bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) { + return !(LHS == RHS); +} + +} // end namespace llvm + +#endif // LLVM_ADT_SMALLSET_H diff --git a/third_party/llvm-project/include/llvm/ADT/SmallString.h b/third_party/llvm-project/include/llvm/ADT/SmallString.h new file mode 100644 index 000000000..898be80d0 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/SmallString.h @@ -0,0 +1,296 @@ +//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallString class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLSTRING_H +#define LLVM_ADT_SMALLSTRING_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <cstddef> + +namespace llvm { + +/// SmallString - A SmallString is just a SmallVector with methods and accessors +/// that make it work better as a string (e.g. operator+ etc). +template<unsigned InternalLen> +class SmallString : public SmallVector<char, InternalLen> { +public: + /// Default ctor - Initialize to empty. + SmallString() = default; + + /// Initialize from a StringRef. + SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {} + + /// Initialize with a range. + template<typename ItTy> + SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {} + + // Note that in order to add new overloads for append & assign, we have to + // duplicate the inherited versions so as not to inadvertently hide them. + + /// @} + /// @name String Assignment + /// @{ + + /// Assign from a repeated element. + void assign(size_t NumElts, char Elt) { + this->SmallVectorImpl<char>::assign(NumElts, Elt); + } + + /// Assign from an iterator pair. + template<typename in_iter> + void assign(in_iter S, in_iter E) { + this->clear(); + SmallVectorImpl<char>::append(S, E); + } + + /// Assign from a StringRef. + void assign(StringRef RHS) { + this->clear(); + SmallVectorImpl<char>::append(RHS.begin(), RHS.end()); + } + + /// Assign from a SmallVector. + void assign(const SmallVectorImpl<char> &RHS) { + this->clear(); + SmallVectorImpl<char>::append(RHS.begin(), RHS.end()); + } + + /// @} + /// @name String Concatenation + /// @{ + + /// Append from an iterator pair. + template<typename in_iter> + void append(in_iter S, in_iter E) { + SmallVectorImpl<char>::append(S, E); + } + + void append(size_t NumInputs, char Elt) { + SmallVectorImpl<char>::append(NumInputs, Elt); + } + + /// Append from a StringRef. + void append(StringRef RHS) { + SmallVectorImpl<char>::append(RHS.begin(), RHS.end()); + } + + /// Append from a SmallVector. + void append(const SmallVectorImpl<char> &RHS) { + SmallVectorImpl<char>::append(RHS.begin(), RHS.end()); + } + + /// @} + /// @name String Comparison + /// @{ + + /// Check for string equality. This is more efficient than compare() when + /// the relative ordering of inequal strings isn't needed. + bool equals(StringRef RHS) const { + return str().equals(RHS); + } + + /// Check for string equality, ignoring case. + bool equals_lower(StringRef RHS) const { + return str().equals_lower(RHS); + } + + /// Compare two strings; the result is -1, 0, or 1 if this string is + /// lexicographically less than, equal to, or greater than the \p RHS. + int compare(StringRef RHS) const { + return str().compare(RHS); + } + + /// compare_lower - Compare two strings, ignoring case. + int compare_lower(StringRef RHS) const { + return str().compare_lower(RHS); + } + + /// compare_numeric - Compare two strings, treating sequences of digits as + /// numbers. + int compare_numeric(StringRef RHS) const { + return str().compare_numeric(RHS); + } + + /// @} + /// @name String Predicates + /// @{ + + /// startswith - Check if this string starts with the given \p Prefix. + bool startswith(StringRef Prefix) const { + return str().startswith(Prefix); + } + + /// endswith - Check if this string ends with the given \p Suffix. + bool endswith(StringRef Suffix) const { + return str().endswith(Suffix); + } + + /// @} + /// @name String Searching + /// @{ + + /// find - Search for the first character \p C in the string. + /// + /// \return - The index of the first occurrence of \p C, or npos if not + /// found. + size_t find(char C, size_t From = 0) const { + return str().find(C, From); + } + + /// Search for the first string \p Str in the string. + /// + /// \returns The index of the first occurrence of \p Str, or npos if not + /// found. + size_t find(StringRef Str, size_t From = 0) const { + return str().find(Str, From); + } + + /// Search for the last character \p C in the string. + /// + /// \returns The index of the last occurrence of \p C, or npos if not + /// found. + size_t rfind(char C, size_t From = StringRef::npos) const { + return str().rfind(C, From); + } + + /// Search for the last string \p Str in the string. + /// + /// \returns The index of the last occurrence of \p Str, or npos if not + /// found. + size_t rfind(StringRef Str) const { + return str().rfind(Str); + } + + /// Find the first character in the string that is \p C, or npos if not + /// found. Same as find. + size_t find_first_of(char C, size_t From = 0) const { + return str().find_first_of(C, From); + } + + /// Find the first character in the string that is in \p Chars, or npos if + /// not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_of(StringRef Chars, size_t From = 0) const { + return str().find_first_of(Chars, From); + } + + /// Find the first character in the string that is not \p C or npos if not + /// found. + size_t find_first_not_of(char C, size_t From = 0) const { + return str().find_first_not_of(C, From); + } + + /// Find the first character in the string that is not in the string + /// \p Chars, or npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_not_of(StringRef Chars, size_t From = 0) const { + return str().find_first_not_of(Chars, From); + } + + /// Find the last character in the string that is \p C, or npos if not + /// found. + size_t find_last_of(char C, size_t From = StringRef::npos) const { + return str().find_last_of(C, From); + } + + /// Find the last character in the string that is in \p C, or npos if not + /// found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_last_of( + StringRef Chars, size_t From = StringRef::npos) const { + return str().find_last_of(Chars, From); + } + + /// @} + /// @name Helpful Algorithms + /// @{ + + /// Return the number of occurrences of \p C in the string. + size_t count(char C) const { + return str().count(C); + } + + /// Return the number of non-overlapped occurrences of \p Str in the + /// string. + size_t count(StringRef Str) const { + return str().count(Str); + } + + /// @} + /// @name Substring Operations + /// @{ + + /// Return a reference to the substring from [Start, Start + N). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param N The number of characters to included in the substring. If \p N + /// exceeds the number of characters remaining in the string, the string + /// suffix (starting with \p Start) will be returned. + StringRef substr(size_t Start, size_t N = StringRef::npos) const { + return str().substr(Start, N); + } + + /// Return a reference to the substring from [Start, End). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param End The index following the last character to include in the + /// substring. If this is npos, or less than \p Start, or exceeds the + /// number of characters remaining in the string, the string suffix + /// (starting with \p Start) will be returned. + StringRef slice(size_t Start, size_t End) const { + return str().slice(Start, End); + } + + // Extra methods. + + /// Explicit conversion to StringRef. + StringRef str() const { return StringRef(this->begin(), this->size()); } + + // TODO: Make this const, if it's safe... + const char* c_str() { + this->push_back(0); + this->pop_back(); + return this->data(); + } + + /// Implicit conversion to StringRef. + operator StringRef() const { return str(); } + + // Extra operators. + const SmallString &operator=(StringRef RHS) { + this->clear(); + return *this += RHS; + } + + SmallString &operator+=(StringRef RHS) { + this->append(RHS.begin(), RHS.end()); + return *this; + } + SmallString &operator+=(char C) { + this->push_back(C); + return *this; + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_SMALLSTRING_H diff --git a/third_party/llvm-project/include/llvm/ADT/SmallVector.h b/third_party/llvm-project/include/llvm/ADT/SmallVector.h new file mode 100644 index 000000000..17586904d --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/SmallVector.h @@ -0,0 +1,930 @@ +//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallVector class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLVECTOR_H +#define LLVM_ADT_SMALLVECTOR_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemAlloc.h" +#include "llvm/Support/type_traits.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <iterator> +#include <memory> +#include <new> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// This is all the non-templated stuff common to all SmallVectors. +class SmallVectorBase { +protected: + void *BeginX; + unsigned Size = 0, Capacity; + + SmallVectorBase() = delete; + SmallVectorBase(void *FirstEl, size_t TotalCapacity) + : BeginX(FirstEl), Capacity(TotalCapacity) {} + + /// This is an implementation of the grow() method which only works + /// on POD-like data types and is out of line to reduce code duplication. + void grow_pod(void *FirstEl, size_t MinCapacity, size_t TSize); + +public: + size_t size() const { return Size; } + size_t capacity() const { return Capacity; } + + LLVM_NODISCARD bool empty() const { return !Size; } + + /// Set the array size to \p N, which the current array must have enough + /// capacity for. + /// + /// This does not construct or destroy any elements in the vector. + /// + /// Clients can use this in conjunction with capacity() to write past the end + /// of the buffer when they know that more elements are available, and only + /// update the size later. This avoids the cost of value initializing elements + /// which will only be overwritten. + void set_size(size_t N) { + assert(N <= capacity()); + Size = N; + } +}; + +/// Figure out the offset of the first element. +template <class T, typename = void> struct SmallVectorAlignmentAndSize { + AlignedCharArrayUnion<SmallVectorBase> Base; + AlignedCharArrayUnion<T> FirstEl; +}; + +/// This is the part of SmallVectorTemplateBase which does not depend on whether +/// the type T is a POD. The extra dummy template argument is used by ArrayRef +/// to avoid unnecessarily requiring T to be complete. +template <typename T, typename = void> +class SmallVectorTemplateCommon : public SmallVectorBase { + /// Find the address of the first element. For this pointer math to be valid + /// with small-size of 0 for T with lots of alignment, it's important that + /// SmallVectorStorage is properly-aligned even for small-size of 0. + void *getFirstEl() const { + return const_cast<void *>(reinterpret_cast<const void *>( + reinterpret_cast<const char *>(this) + + offsetof(SmallVectorAlignmentAndSize<T>, FirstEl))); + } + // Space after 'FirstEl' is clobbered, do not add any instance vars after it. + +protected: + SmallVectorTemplateCommon(size_t Size) + : SmallVectorBase(getFirstEl(), Size) {} + + void grow_pod(size_t MinCapacity, size_t TSize) { + SmallVectorBase::grow_pod(getFirstEl(), MinCapacity, TSize); + } + + /// Return true if this is a smallvector which has not had dynamic + /// memory allocated for it. + bool isSmall() const { return BeginX == getFirstEl(); } + + /// Put this vector in a state of being small. + void resetToSmall() { + BeginX = getFirstEl(); + Size = Capacity = 0; // FIXME: Setting Capacity to 0 is suspect. + } + +public: + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = T; + using iterator = T *; + using const_iterator = const T *; + + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = std::reverse_iterator<iterator>; + + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; + + // forward iterator creation methods. + iterator begin() { return (iterator)this->BeginX; } + const_iterator begin() const { return (const_iterator)this->BeginX; } + iterator end() { return begin() + size(); } + const_iterator end() const { return begin() + size(); } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + size_type size_in_bytes() const { return size() * sizeof(T); } + size_type max_size() const { return size_type(-1) / sizeof(T); } + + size_t capacity_in_bytes() const { return capacity() * sizeof(T); } + + /// Return a pointer to the vector's buffer, even if empty(). + pointer data() { return pointer(begin()); } + /// Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { return const_pointer(begin()); } + + reference operator[](size_type idx) { + assert(idx < size()); + return begin()[idx]; + } + const_reference operator[](size_type idx) const { + assert(idx < size()); + return begin()[idx]; + } + + reference front() { + assert(!empty()); + return begin()[0]; + } + const_reference front() const { + assert(!empty()); + return begin()[0]; + } + + reference back() { + assert(!empty()); + return end()[-1]; + } + const_reference back() const { + assert(!empty()); + return end()[-1]; + } +}; + +/// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put method +/// implementations that are designed to work with non-POD-like T's. +template <typename T, bool = is_trivially_copyable<T>::value> +class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> { +protected: + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {} + + static void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + + /// Move the range [I, E) into the uninitialized memory starting with "Dest", + /// constructing elements as needed. + template<typename It1, typename It2> + static void uninitialized_move(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(std::make_move_iterator(I), + std::make_move_iterator(E), Dest); + } + + /// Copy the range [I, E) onto the uninitialized memory starting with "Dest", + /// constructing elements as needed. + template<typename It1, typename It2> + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(I, E, Dest); + } + + /// Grow the allocated memory (without initializing new elements), doubling + /// the size of the allocated memory. Guarantees space for at least one more + /// element, or MinSize more elements if specified. + void grow(size_t MinSize = 0); + +public: + void push_back(const T &Elt) { + if (LLVM_UNLIKELY(this->size() >= this->capacity())) + this->grow(); + ::new ((void*) this->end()) T(Elt); + this->set_size(this->size() + 1); + } + + void push_back(T &&Elt) { + if (LLVM_UNLIKELY(this->size() >= this->capacity())) + this->grow(); + ::new ((void*) this->end()) T(::std::move(Elt)); + this->set_size(this->size() + 1); + } + + void pop_back() { + this->set_size(this->size() - 1); + this->end()->~T(); + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T, bool TriviallyCopyable> +void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) { + if (MinSize > UINT32_MAX) + report_bad_alloc_error("SmallVector capacity overflow during allocation"); + + // Always grow, even from zero. + size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2)); + NewCapacity = std::min(std::max(NewCapacity, MinSize), size_t(UINT32_MAX)); + T *NewElts = static_cast<T*>(llvm::safe_malloc(NewCapacity*sizeof(T))); + + // Move the elements over. + this->uninitialized_move(this->begin(), this->end(), NewElts); + + // Destroy the original elements. + destroy_range(this->begin(), this->end()); + + // If this wasn't grown from the inline copy, deallocate the old space. + if (!this->isSmall()) + free(this->begin()); + + this->BeginX = NewElts; + this->Capacity = NewCapacity; +} + +/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put +/// method implementations that are designed to work with POD-like T's. +template <typename T> +class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> { +protected: + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {} + + // No need to do a destroy loop for POD's. + static void destroy_range(T *, T *) {} + + /// Move the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template<typename It1, typename It2> + static void uninitialized_move(It1 I, It1 E, It2 Dest) { + // Just do a copy. + uninitialized_copy(I, E, Dest); + } + + /// Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template<typename It1, typename It2> + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + // Arbitrary iterator types; just use the basic implementation. + std::uninitialized_copy(I, E, Dest); + } + + /// Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template <typename T1, typename T2> + static void uninitialized_copy( + T1 *I, T1 *E, T2 *Dest, + typename std::enable_if<std::is_same<typename std::remove_const<T1>::type, + T2>::value>::type * = nullptr) { + // Use memcpy for PODs iterated by pointers (which includes SmallVector + // iterators): std::uninitialized_copy optimizes to memmove, but we can + // use memcpy here. Note that I and E are iterators and thus might be + // invalid for memcpy if they are equal. + if (I != E) + memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T)); + } + + /// Double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); } + +public: + void push_back(const T &Elt) { + if (LLVM_UNLIKELY(this->size() >= this->capacity())) + this->grow(); + memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T)); + this->set_size(this->size() + 1); + } + + void pop_back() { this->set_size(this->size() - 1); } +}; + +/// This class consists of common code factored out of the SmallVector class to +/// reduce code duplication based on the SmallVector 'N' template parameter. +template <typename T> +class SmallVectorImpl : public SmallVectorTemplateBase<T> { + using SuperClass = SmallVectorTemplateBase<T>; + +public: + using iterator = typename SuperClass::iterator; + using const_iterator = typename SuperClass::const_iterator; + using reference = typename SuperClass::reference; + using size_type = typename SuperClass::size_type; + +protected: + // Default ctor - Initialize to empty. + explicit SmallVectorImpl(unsigned N) + : SmallVectorTemplateBase<T>(N) {} + +public: + SmallVectorImpl(const SmallVectorImpl &) = delete; + + ~SmallVectorImpl() { + // Subclass has already destructed this vector's elements. + // If this wasn't grown from the inline copy, deallocate the old space. + if (!this->isSmall()) + free(this->begin()); + } + + void clear() { + this->destroy_range(this->begin(), this->end()); + this->Size = 0; + } + + void resize(size_type N) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->set_size(N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(N); + for (auto I = this->end(), E = this->begin() + N; I != E; ++I) + new (&*I) T(); + this->set_size(N); + } + } + + void resize(size_type N, const T &NV) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->set_size(N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(N); + std::uninitialized_fill(this->end(), this->begin()+N, NV); + this->set_size(N); + } + } + + void reserve(size_type N) { + if (this->capacity() < N) + this->grow(N); + } + + LLVM_NODISCARD T pop_back_val() { + T Result = ::std::move(this->back()); + this->pop_back(); + return Result; + } + + void swap(SmallVectorImpl &RHS); + + /// Add the specified range to the end of the SmallVector. + template <typename in_iter, + typename = typename std::enable_if<std::is_convertible< + typename std::iterator_traits<in_iter>::iterator_category, + std::input_iterator_tag>::value>::type> + void append(in_iter in_start, in_iter in_end) { + size_type NumInputs = std::distance(in_start, in_end); + if (NumInputs > this->capacity() - this->size()) + this->grow(this->size()+NumInputs); + + this->uninitialized_copy(in_start, in_end, this->end()); + this->set_size(this->size() + NumInputs); + } + + /// Append \p NumInputs copies of \p Elt to the end. + void append(size_type NumInputs, const T &Elt) { + if (NumInputs > this->capacity() - this->size()) + this->grow(this->size()+NumInputs); + + std::uninitialized_fill_n(this->end(), NumInputs, Elt); + this->set_size(this->size() + NumInputs); + } + + void append(std::initializer_list<T> IL) { + append(IL.begin(), IL.end()); + } + + // FIXME: Consider assigning over existing elements, rather than clearing & + // re-initializing them - for all assign(...) variants. + + void assign(size_type NumElts, const T &Elt) { + clear(); + if (this->capacity() < NumElts) + this->grow(NumElts); + this->set_size(NumElts); + std::uninitialized_fill(this->begin(), this->end(), Elt); + } + + template <typename in_iter, + typename = typename std::enable_if<std::is_convertible< + typename std::iterator_traits<in_iter>::iterator_category, + std::input_iterator_tag>::value>::type> + void assign(in_iter in_start, in_iter in_end) { + clear(); + append(in_start, in_end); + } + + void assign(std::initializer_list<T> IL) { + clear(); + append(IL); + } + + iterator erase(const_iterator CI) { + // Just cast away constness because this is a non-const member function. + iterator I = const_cast<iterator>(CI); + + assert(I >= this->begin() && "Iterator to erase is out of bounds."); + assert(I < this->end() && "Erasing at past-the-end iterator."); + + iterator N = I; + // Shift all elts down one. + std::move(I+1, this->end(), I); + // Drop the last elt. + this->pop_back(); + return(N); + } + + iterator erase(const_iterator CS, const_iterator CE) { + // Just cast away constness because this is a non-const member function. + iterator S = const_cast<iterator>(CS); + iterator E = const_cast<iterator>(CE); + + assert(S >= this->begin() && "Range to erase is out of bounds."); + assert(S <= E && "Trying to erase invalid range."); + assert(E <= this->end() && "Trying to erase past the end."); + + iterator N = S; + // Shift all elts down. + iterator I = std::move(E, this->end(), S); + // Drop the last elts. + this->destroy_range(I, this->end()); + this->set_size(I - this->begin()); + return(N); + } + + iterator insert(iterator I, T &&Elt) { + if (I == this->end()) { // Important special case for empty vector. + this->push_back(::std::move(Elt)); + return this->end()-1; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + if (this->size() >= this->capacity()) { + size_t EltNo = I-this->begin(); + this->grow(); + I = this->begin()+EltNo; + } + + ::new ((void*) this->end()) T(::std::move(this->back())); + // Push everything else over. + std::move_backward(I, this->end()-1, this->end()); + this->set_size(this->size() + 1); + + // If we just moved the element we're inserting, be sure to update + // the reference. + T *EltPtr = &Elt; + if (I <= EltPtr && EltPtr < this->end()) + ++EltPtr; + + *I = ::std::move(*EltPtr); + return I; + } + + iterator insert(iterator I, const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + this->push_back(Elt); + return this->end()-1; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + if (this->size() >= this->capacity()) { + size_t EltNo = I-this->begin(); + this->grow(); + I = this->begin()+EltNo; + } + ::new ((void*) this->end()) T(std::move(this->back())); + // Push everything else over. + std::move_backward(I, this->end()-1, this->end()); + this->set_size(this->size() + 1); + + // If we just moved the element we're inserting, be sure to update + // the reference. + const T *EltPtr = &Elt; + if (I <= EltPtr && EltPtr < this->end()) + ++EltPtr; + + *I = *EltPtr; + return I; + } + + iterator insert(iterator I, size_type NumToInsert, const T &Elt) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(NumToInsert, Elt); + return this->begin()+InsertElt; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + // Ensure there is enough space. + reserve(this->size() + NumToInsert); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(std::move_iterator<iterator>(this->end() - NumToInsert), + std::move_iterator<iterator>(this->end())); + + // Copy the existing elements that get replaced. + std::move_backward(I, OldEnd-NumToInsert, OldEnd); + + std::fill_n(I, NumToInsert, Elt); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Move over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->set_size(this->size() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + std::fill_n(I, NumOverwritten, Elt); + + // Insert the non-overwritten middle part. + std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt); + return I; + } + + template <typename ItTy, + typename = typename std::enable_if<std::is_convertible< + typename std::iterator_traits<ItTy>::iterator_category, + std::input_iterator_tag>::value>::type> + iterator insert(iterator I, ItTy From, ItTy To) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(From, To); + return this->begin()+InsertElt; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + size_t NumToInsert = std::distance(From, To); + + // Ensure there is enough space. + reserve(this->size() + NumToInsert); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(std::move_iterator<iterator>(this->end() - NumToInsert), + std::move_iterator<iterator>(this->end())); + + // Copy the existing elements that get replaced. + std::move_backward(I, OldEnd-NumToInsert, OldEnd); + + std::copy(From, To, I); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Move over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->set_size(this->size() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + for (T *J = I; NumOverwritten > 0; --NumOverwritten) { + *J = *From; + ++J; ++From; + } + + // Insert the non-overwritten middle part. + this->uninitialized_copy(From, To, OldEnd); + return I; + } + + void insert(iterator I, std::initializer_list<T> IL) { + insert(I, IL.begin(), IL.end()); + } + + template <typename... ArgTypes> reference emplace_back(ArgTypes &&... Args) { + if (LLVM_UNLIKELY(this->size() >= this->capacity())) + this->grow(); + ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...); + this->set_size(this->size() + 1); + return this->back(); + } + + SmallVectorImpl &operator=(const SmallVectorImpl &RHS); + + SmallVectorImpl &operator=(SmallVectorImpl &&RHS); + + bool operator==(const SmallVectorImpl &RHS) const { + if (this->size() != RHS.size()) return false; + return std::equal(this->begin(), this->end(), RHS.begin()); + } + bool operator!=(const SmallVectorImpl &RHS) const { + return !(*this == RHS); + } + + bool operator<(const SmallVectorImpl &RHS) const { + return std::lexicographical_compare(this->begin(), this->end(), + RHS.begin(), RHS.end()); + } +}; + +template <typename T> +void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) { + if (this == &RHS) return; + + // We can only avoid copying elements if neither vector is small. + if (!this->isSmall() && !RHS.isSmall()) { + std::swap(this->BeginX, RHS.BeginX); + std::swap(this->Size, RHS.Size); + std::swap(this->Capacity, RHS.Capacity); + return; + } + if (RHS.size() > this->capacity()) + this->grow(RHS.size()); + if (this->size() > RHS.capacity()) + RHS.grow(this->size()); + + // Swap the shared elements. + size_t NumShared = this->size(); + if (NumShared > RHS.size()) NumShared = RHS.size(); + for (size_type i = 0; i != NumShared; ++i) + std::swap((*this)[i], RHS[i]); + + // Copy over the extra elts. + if (this->size() > RHS.size()) { + size_t EltDiff = this->size() - RHS.size(); + this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end()); + RHS.set_size(RHS.size() + EltDiff); + this->destroy_range(this->begin()+NumShared, this->end()); + this->set_size(NumShared); + } else if (RHS.size() > this->size()) { + size_t EltDiff = RHS.size() - this->size(); + this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end()); + this->set_size(this->size() + EltDiff); + this->destroy_range(RHS.begin()+NumShared, RHS.end()); + RHS.set_size(NumShared); + } +} + +template <typename T> +SmallVectorImpl<T> &SmallVectorImpl<T>:: + operator=(const SmallVectorImpl<T> &RHS) { + // Avoid self-assignment. + if (this == &RHS) return *this; + + // If we already have sufficient space, assign the common elements, then + // destroy any excess. + size_t RHSSize = RHS.size(); + size_t CurSize = this->size(); + if (CurSize >= RHSSize) { + // Assign common elements. + iterator NewEnd; + if (RHSSize) + NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin()); + else + NewEnd = this->begin(); + + // Destroy excess elements. + this->destroy_range(NewEnd, this->end()); + + // Trim. + this->set_size(RHSSize); + return *this; + } + + // If we have to grow to have enough elements, destroy the current elements. + // This allows us to avoid copying them during the grow. + // FIXME: don't do this if they're efficiently moveable. + if (this->capacity() < RHSSize) { + // Destroy current elements. + this->destroy_range(this->begin(), this->end()); + this->set_size(0); + CurSize = 0; + this->grow(RHSSize); + } else if (CurSize) { + // Otherwise, use assignment for the already-constructed elements. + std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin()); + } + + // Copy construct the new elements in place. + this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(), + this->begin()+CurSize); + + // Set end. + this->set_size(RHSSize); + return *this; +} + +template <typename T> +SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) { + // Avoid self-assignment. + if (this == &RHS) return *this; + + // If the RHS isn't small, clear this vector and then steal its buffer. + if (!RHS.isSmall()) { + this->destroy_range(this->begin(), this->end()); + if (!this->isSmall()) free(this->begin()); + this->BeginX = RHS.BeginX; + this->Size = RHS.Size; + this->Capacity = RHS.Capacity; + RHS.resetToSmall(); + return *this; + } + + // If we already have sufficient space, assign the common elements, then + // destroy any excess. + size_t RHSSize = RHS.size(); + size_t CurSize = this->size(); + if (CurSize >= RHSSize) { + // Assign common elements. + iterator NewEnd = this->begin(); + if (RHSSize) + NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd); + + // Destroy excess elements and trim the bounds. + this->destroy_range(NewEnd, this->end()); + this->set_size(RHSSize); + + // Clear the RHS. + RHS.clear(); + + return *this; + } + + // If we have to grow to have enough elements, destroy the current elements. + // This allows us to avoid copying them during the grow. + // FIXME: this may not actually make any sense if we can efficiently move + // elements. + if (this->capacity() < RHSSize) { + // Destroy current elements. + this->destroy_range(this->begin(), this->end()); + this->set_size(0); + CurSize = 0; + this->grow(RHSSize); + } else if (CurSize) { + // Otherwise, use assignment for the already-constructed elements. + std::move(RHS.begin(), RHS.begin()+CurSize, this->begin()); + } + + // Move-construct the new elements in place. + this->uninitialized_move(RHS.begin()+CurSize, RHS.end(), + this->begin()+CurSize); + + // Set end. + this->set_size(RHSSize); + + RHS.clear(); + return *this; +} + +/// Storage for the SmallVector elements. This is specialized for the N=0 case +/// to avoid allocating unnecessary storage. +template <typename T, unsigned N> +struct SmallVectorStorage { + AlignedCharArrayUnion<T> InlineElts[N]; +}; + +/// We need the storage to be properly aligned even for small-size of 0 so that +/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is +/// well-defined. +template <typename T> struct alignas(alignof(T)) SmallVectorStorage<T, 0> {}; + +/// This is a 'vector' (really, a variable-sized array), optimized +/// for the case when the array is small. It contains some number of elements +/// in-place, which allows it to avoid heap allocation when the actual number of +/// elements is below that threshold. This allows normal "small" cases to be +/// fast without losing generality for large inputs. +/// +/// Note that this does not attempt to be exception safe. +/// +template <typename T, unsigned N> +class SmallVector : public SmallVectorImpl<T>, SmallVectorStorage<T, N> { +public: + SmallVector() : SmallVectorImpl<T>(N) {} + + ~SmallVector() { + // Destroy the constructed elements in the vector. + this->destroy_range(this->begin(), this->end()); + } + + explicit SmallVector(size_t Size, const T &Value = T()) + : SmallVectorImpl<T>(N) { + this->assign(Size, Value); + } + + template <typename ItTy, + typename = typename std::enable_if<std::is_convertible< + typename std::iterator_traits<ItTy>::iterator_category, + std::input_iterator_tag>::value>::type> + SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) { + this->append(S, E); + } + + template <typename RangeTy> + explicit SmallVector(const iterator_range<RangeTy> &R) + : SmallVectorImpl<T>(N) { + this->append(R.begin(), R.end()); + } + + SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) { + this->assign(IL); + } + + SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) { + if (!RHS.empty()) + SmallVectorImpl<T>::operator=(RHS); + } + + const SmallVector &operator=(const SmallVector &RHS) { + SmallVectorImpl<T>::operator=(RHS); + return *this; + } + + SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) { + if (!RHS.empty()) + SmallVectorImpl<T>::operator=(::std::move(RHS)); + } + + SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) { + if (!RHS.empty()) + SmallVectorImpl<T>::operator=(::std::move(RHS)); + } + + const SmallVector &operator=(SmallVector &&RHS) { + SmallVectorImpl<T>::operator=(::std::move(RHS)); + return *this; + } + + const SmallVector &operator=(SmallVectorImpl<T> &&RHS) { + SmallVectorImpl<T>::operator=(::std::move(RHS)); + return *this; + } + + const SmallVector &operator=(std::initializer_list<T> IL) { + this->assign(IL); + return *this; + } +}; + +template <typename T, unsigned N> +inline size_t capacity_in_bytes(const SmallVector<T, N> &X) { + return X.capacity_in_bytes(); +} + +} // end namespace llvm + +namespace std { + + /// Implement std::swap in terms of SmallVector swap. + template<typename T> + inline void + swap(llvm::SmallVectorImpl<T> &LHS, llvm::SmallVectorImpl<T> &RHS) { + LHS.swap(RHS); + } + + /// Implement std::swap in terms of SmallVector swap. + template<typename T, unsigned N> + inline void + swap(llvm::SmallVector<T, N> &LHS, llvm::SmallVector<T, N> &RHS) { + LHS.swap(RHS); + } + +} // end namespace std + +#endif // LLVM_ADT_SMALLVECTOR_H diff --git a/third_party/llvm-project/include/llvm/ADT/StringExtras.h b/third_party/llvm-project/include/llvm/ADT/StringExtras.h new file mode 100644 index 000000000..ef1a11e06 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/StringExtras.h @@ -0,0 +1,401 @@ +//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains some functions that are useful when dealing with strings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGEXTRAS_H +#define LLVM_ADT_STRINGEXTRAS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <iterator> +#include <string> +#include <utility> + +namespace llvm { + +template<typename T> class SmallVectorImpl; +class raw_ostream; + +/// hexdigit - Return the hexadecimal character for the +/// given number \p X (which should be less than 16). +inline char hexdigit(unsigned X, bool LowerCase = false) { + const char HexChar = LowerCase ? 'a' : 'A'; + return X < 10 ? '0' + X : HexChar + X - 10; +} + +/// Given an array of c-style strings terminated by a null pointer, construct +/// a vector of StringRefs representing the same strings without the terminating +/// null string. +inline std::vector<StringRef> toStringRefArray(const char *const *Strings) { + std::vector<StringRef> Result; + while (*Strings) + Result.push_back(*Strings++); + return Result; +} + +/// Construct a string ref from a boolean. +inline StringRef toStringRef(bool B) { return StringRef(B ? "true" : "false"); } + +/// Construct a string ref from an array ref of unsigned chars. +inline StringRef toStringRef(ArrayRef<uint8_t> Input) { + return StringRef(reinterpret_cast<const char *>(Input.begin()), Input.size()); +} + +/// Construct a string ref from an array ref of unsigned chars. +inline ArrayRef<uint8_t> arrayRefFromStringRef(StringRef Input) { + return {Input.bytes_begin(), Input.bytes_end()}; +} + +/// Interpret the given character \p C as a hexadecimal digit and return its +/// value. +/// +/// If \p C is not a valid hex digit, -1U is returned. +inline unsigned hexDigitValue(char C) { + if (C >= '0' && C <= '9') return C-'0'; + if (C >= 'a' && C <= 'f') return C-'a'+10U; + if (C >= 'A' && C <= 'F') return C-'A'+10U; + return -1U; +} + +/// Checks if character \p C is one of the 10 decimal digits. +inline bool isDigit(char C) { return C >= '0' && C <= '9'; } + +/// Checks if character \p C is a hexadecimal numeric character. +inline bool isHexDigit(char C) { return hexDigitValue(C) != -1U; } + +/// Checks if character \p C is a valid letter as classified by "C" locale. +inline bool isAlpha(char C) { + return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z'); +} + +/// Checks whether character \p C is either a decimal digit or an uppercase or +/// lowercase letter as classified by "C" locale. +inline bool isAlnum(char C) { return isAlpha(C) || isDigit(C); } + +/// Checks whether character \p C is valid ASCII (high bit is zero). +inline bool isASCII(char C) { return static_cast<unsigned char>(C) <= 127; } + +/// Checks whether all characters in S are ASCII. +inline bool isASCII(llvm::StringRef S) { + for (char C : S) + if (LLVM_UNLIKELY(!isASCII(C))) + return false; + return true; +} + +/// Checks whether character \p C is printable. +/// +/// Locale-independent version of the C standard library isprint whose results +/// may differ on different platforms. +inline bool isPrint(char C) { + unsigned char UC = static_cast<unsigned char>(C); + return (0x20 <= UC) && (UC <= 0x7E); +} + +/// Returns the corresponding lowercase character if \p x is uppercase. +inline char toLower(char x) { + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + return x; +} + +/// Returns the corresponding uppercase character if \p x is lowercase. +inline char toUpper(char x) { + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + return x; +} + +inline std::string utohexstr(uint64_t X, bool LowerCase = false) { + char Buffer[17]; + char *BufPtr = std::end(Buffer); + + if (X == 0) *--BufPtr = '0'; + + while (X) { + unsigned char Mod = static_cast<unsigned char>(X) & 15; + *--BufPtr = hexdigit(Mod, LowerCase); + X >>= 4; + } + + return std::string(BufPtr, std::end(Buffer)); +} + +/// Convert buffer \p Input to its hexadecimal representation. +/// The returned string is double the size of \p Input. +inline std::string toHex(StringRef Input, bool LowerCase = false) { + static const char *const LUT = "0123456789ABCDEF"; + const uint8_t Offset = LowerCase ? 32 : 0; + size_t Length = Input.size(); + + std::string Output; + Output.reserve(2 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Input[i]; + Output.push_back(LUT[c >> 4] | Offset); + Output.push_back(LUT[c & 15] | Offset); + } + return Output; +} + +inline std::string toHex(ArrayRef<uint8_t> Input, bool LowerCase = false) { + return toHex(toStringRef(Input), LowerCase); +} + +inline uint8_t hexFromNibbles(char MSB, char LSB) { + unsigned U1 = hexDigitValue(MSB); + unsigned U2 = hexDigitValue(LSB); + assert(U1 != -1U && U2 != -1U); + + return static_cast<uint8_t>((U1 << 4) | U2); +} + +/// Convert hexadecimal string \p Input to its binary representation. +/// The return string is half the size of \p Input. +inline std::string fromHex(StringRef Input) { + if (Input.empty()) + return std::string(); + + std::string Output; + Output.reserve((Input.size() + 1) / 2); + if (Input.size() % 2 == 1) { + Output.push_back(hexFromNibbles('0', Input.front())); + Input = Input.drop_front(); + } + + assert(Input.size() % 2 == 0); + while (!Input.empty()) { + uint8_t Hex = hexFromNibbles(Input[0], Input[1]); + Output.push_back(Hex); + Input = Input.drop_front(2); + } + return Output; +} + +/// Convert the string \p S to an integer of the specified type using +/// the radix \p Base. If \p Base is 0, auto-detects the radix. +/// Returns true if the number was successfully converted, false otherwise. +template <typename N> bool to_integer(StringRef S, N &Num, unsigned Base = 0) { + return !S.getAsInteger(Base, Num); +} + +namespace detail { +template <typename N> +inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) { + SmallString<32> Storage; + StringRef S = T.toNullTerminatedStringRef(Storage); + char *End; + N Temp = StrTo(S.data(), &End); + if (*End != '\0') + return false; + Num = Temp; + return true; +} +} + +inline bool to_float(const Twine &T, float &Num) { + return detail::to_float(T, Num, strtof); +} + +inline bool to_float(const Twine &T, double &Num) { + return detail::to_float(T, Num, strtod); +} + +inline bool to_float(const Twine &T, long double &Num) { + return detail::to_float(T, Num, strtold); +} + +inline std::string utostr(uint64_t X, bool isNeg = false) { + char Buffer[21]; + char *BufPtr = std::end(Buffer); + + if (X == 0) *--BufPtr = '0'; // Handle special case... + + while (X) { + *--BufPtr = '0' + char(X % 10); + X /= 10; + } + + if (isNeg) *--BufPtr = '-'; // Add negative sign... + return std::string(BufPtr, std::end(Buffer)); +} + +inline std::string itostr(int64_t X) { + if (X < 0) + return utostr(static_cast<uint64_t>(-X), true); + else + return utostr(static_cast<uint64_t>(X)); +} + +/// StrInStrNoCase - Portable version of strcasestr. Locates the first +/// occurrence of string 's1' in string 's2', ignoring case. Returns +/// the offset of s2 in s1 or npos if s2 cannot be found. +StringRef::size_type StrInStrNoCase(StringRef s1, StringRef s2); + +/// getToken - This function extracts one token from source, ignoring any +/// leading characters that appear in the Delimiters string, and ending the +/// token at any of the characters that appear in the Delimiters string. If +/// there are no tokens in the source string, an empty string is returned. +/// The function returns a pair containing the extracted token and the +/// remaining tail string. +std::pair<StringRef, StringRef> getToken(StringRef Source, + StringRef Delimiters = " \t\n\v\f\r"); + +/// SplitString - Split up the specified string according to the specified +/// delimiters, appending the result fragments to the output list. +void SplitString(StringRef Source, + SmallVectorImpl<StringRef> &OutFragments, + StringRef Delimiters = " \t\n\v\f\r"); + +/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th). +inline StringRef getOrdinalSuffix(unsigned Val) { + // It is critically important that we do this perfectly for + // user-written sequences with over 100 elements. + switch (Val % 100) { + case 11: + case 12: + case 13: + return "th"; + default: + switch (Val % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } + } +} + +/// Print each character of the specified string, escaping it if it is not +/// printable or if it is an escape char. +void printEscapedString(StringRef Name, raw_ostream &Out); + +/// Print each character of the specified string, escaping HTML special +/// characters. +void printHTMLEscaped(StringRef String, raw_ostream &Out); + +/// printLowerCase - Print each character as lowercase if it is uppercase. +void printLowerCase(StringRef String, raw_ostream &Out); + +namespace detail { + +template <typename IteratorT> +inline std::string join_impl(IteratorT Begin, IteratorT End, + StringRef Separator, std::input_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + return S; +} + +template <typename IteratorT> +inline std::string join_impl(IteratorT Begin, IteratorT End, + StringRef Separator, std::forward_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + size_t Len = (std::distance(Begin, End) - 1) * Separator.size(); + for (IteratorT I = Begin; I != End; ++I) + Len += (*Begin).size(); + S.reserve(Len); + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + return S; +} + +template <typename Sep> +inline void join_items_impl(std::string &Result, Sep Separator) {} + +template <typename Sep, typename Arg> +inline void join_items_impl(std::string &Result, Sep Separator, + const Arg &Item) { + Result += Item; +} + +template <typename Sep, typename Arg1, typename... Args> +inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1, + Args &&... Items) { + Result += A1; + Result += Separator; + join_items_impl(Result, Separator, std::forward<Args>(Items)...); +} + +inline size_t join_one_item_size(char) { return 1; } +inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; } + +template <typename T> inline size_t join_one_item_size(const T &Str) { + return Str.size(); +} + +inline size_t join_items_size() { return 0; } + +template <typename A1> inline size_t join_items_size(const A1 &A) { + return join_one_item_size(A); +} +template <typename A1, typename... Args> +inline size_t join_items_size(const A1 &A, Args &&... Items) { + return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...); +} + +} // end namespace detail + +/// Joins the strings in the range [Begin, End), adding Separator between +/// the elements. +template <typename IteratorT> +inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) { + using tag = typename std::iterator_traits<IteratorT>::iterator_category; + 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+=() +/// that accepts the argument explicitly. +template <typename Sep, typename... Args> +inline std::string join_items(Sep Separator, Args &&... Items) { + std::string Result; + if (sizeof...(Items) == 0) + return Result; + + size_t NS = detail::join_one_item_size(Separator); + size_t NI = detail::join_items_size(std::forward<Args>(Items)...); + Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1); + detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...); + return Result; +} + +} // end namespace llvm + +#endif // LLVM_ADT_STRINGEXTRAS_H diff --git a/third_party/llvm-project/include/llvm/ADT/StringMap.h b/third_party/llvm-project/include/llvm/ADT/StringMap.h new file mode 100644 index 000000000..108185bd0 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/StringMap.h @@ -0,0 +1,593 @@ +//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the StringMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGMAP_H +#define LLVM_ADT_STRINGMAP_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <iterator> +#include <utility> + +namespace llvm { + +template<typename ValueTy> class StringMapConstIterator; +template<typename ValueTy> class StringMapIterator; +template<typename ValueTy> class StringMapKeyIterator; + +/// StringMapEntryBase - Shared base class of StringMapEntry instances. +class StringMapEntryBase { + size_t StrLen; + +public: + explicit StringMapEntryBase(size_t Len) : StrLen(Len) {} + + size_t getKeyLength() const { return StrLen; } +}; + +/// StringMapImpl - This is the base class of StringMap that is shared among +/// all of its instantiations. +class StringMapImpl { +protected: + // Array of NumBuckets pointers to entries, null pointers are holes. + // TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed + // by an array of the actual hash values as unsigned integers. + StringMapEntryBase **TheTable = nullptr; + unsigned NumBuckets = 0; + unsigned NumItems = 0; + unsigned NumTombstones = 0; + unsigned ItemSize; + +protected: + explicit StringMapImpl(unsigned itemSize) + : ItemSize(itemSize) {} + StringMapImpl(StringMapImpl &&RHS) + : TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets), + NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones), + ItemSize(RHS.ItemSize) { + RHS.TheTable = nullptr; + RHS.NumBuckets = 0; + RHS.NumItems = 0; + RHS.NumTombstones = 0; + } + + StringMapImpl(unsigned InitSize, unsigned ItemSize); + unsigned RehashTable(unsigned BucketNo = 0); + + /// LookupBucketFor - Look up the bucket that the specified string should end + /// up in. If it already exists as a key in the map, the Item pointer for the + /// specified bucket will be non-null. Otherwise, it will be null. In either + /// case, the FullHashValue field of the bucket will be set to the hash value + /// of the string. + unsigned LookupBucketFor(StringRef Key); + + /// FindKey - Look up the bucket that contains the specified key. If it exists + /// in the map, return the bucket number of the key. Otherwise return -1. + /// This does not modify the map. + int FindKey(StringRef Key) const; + + /// RemoveKey - Remove the specified StringMapEntry from the table, but do not + /// delete it. This aborts if the value isn't in the table. + void RemoveKey(StringMapEntryBase *V); + + /// RemoveKey - Remove the StringMapEntry for the specified key from the + /// table, returning it. If the key is not in the table, this returns null. + StringMapEntryBase *RemoveKey(StringRef Key); + + /// Allocate the table with the specified number of buckets and otherwise + /// setup the map as empty. + void init(unsigned Size); + +public: + static StringMapEntryBase *getTombstoneVal() { + uintptr_t Val = static_cast<uintptr_t>(-1); + Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable; + return reinterpret_cast<StringMapEntryBase *>(Val); + } + + unsigned getNumBuckets() const { return NumBuckets; } + unsigned getNumItems() const { return NumItems; } + + bool empty() const { return NumItems == 0; } + unsigned size() const { return NumItems; } + + void swap(StringMapImpl &Other) { + std::swap(TheTable, Other.TheTable); + std::swap(NumBuckets, Other.NumBuckets); + std::swap(NumItems, Other.NumItems); + std::swap(NumTombstones, Other.NumTombstones); + } +}; + +/// StringMapEntryStorage - Holds the value in a StringMapEntry. +/// +/// Factored out into a separate base class to make it easier to specialize. +/// This is primarily intended to support StringSet, which doesn't need a value +/// stored at all. +template<typename ValueTy> +class StringMapEntryStorage : public StringMapEntryBase { +public: + ValueTy second; + + explicit StringMapEntryStorage(size_t strLen) + : StringMapEntryBase(strLen), second() {} + template <typename... InitTy> + StringMapEntryStorage(size_t strLen, InitTy &&... InitVals) + : StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {} + StringMapEntryStorage(StringMapEntryStorage &E) = delete; + + const ValueTy &getValue() const { return second; } + ValueTy &getValue() { return second; } + + void setValue(const ValueTy &V) { second = V; } +}; + +template<> +class StringMapEntryStorage<NoneType> : public StringMapEntryBase { +public: + explicit StringMapEntryStorage(size_t strLen, NoneType none = None) + : StringMapEntryBase(strLen) {} + StringMapEntryStorage(StringMapEntryStorage &E) = delete; + + NoneType getValue() const { return None; } +}; + +/// StringMapEntry - This is used to represent one value that is inserted into +/// a StringMap. It contains the Value itself and the key: the string length +/// and data. +template<typename ValueTy> +class StringMapEntry final : public StringMapEntryStorage<ValueTy> { +public: + using StringMapEntryStorage<ValueTy>::StringMapEntryStorage; + + StringRef getKey() const { + return StringRef(getKeyData(), this->getKeyLength()); + } + + /// getKeyData - Return the start of the string data that is the key for this + /// value. The string data is always stored immediately after the + /// StringMapEntry object. + const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);} + + StringRef first() const { + return StringRef(getKeyData(), this->getKeyLength()); + } + + /// Create a StringMapEntry for the specified key construct the value using + /// \p InitiVals. + template <typename AllocatorTy, typename... InitTy> + static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator, + InitTy &&... InitVals) { + size_t KeyLength = Key.size(); + + // Allocate a new item with space for the string at the end and a null + // terminator. + size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1; + size_t Alignment = alignof(StringMapEntry); + + StringMapEntry *NewItem = + static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment)); + assert(NewItem && "Unhandled out-of-memory"); + + // Construct the value. + new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...); + + // Copy the string information. + char *StrBuffer = const_cast<char*>(NewItem->getKeyData()); + if (KeyLength > 0) + memcpy(StrBuffer, Key.data(), KeyLength); + StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients. + return NewItem; + } + + /// Create - Create a StringMapEntry with normal malloc/free. + template <typename... InitType> + static StringMapEntry *Create(StringRef Key, InitType &&... InitVal) { + MallocAllocator A; + return Create(Key, A, std::forward<InitType>(InitVal)...); + } + + static StringMapEntry *Create(StringRef Key) { + return Create(Key, ValueTy()); + } + + /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded + /// into a StringMapEntry, return the StringMapEntry itself. + static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) { + char *Ptr = const_cast<char*>(KeyData) - sizeof(StringMapEntry<ValueTy>); + return *reinterpret_cast<StringMapEntry*>(Ptr); + } + + /// Destroy - Destroy this StringMapEntry, releasing memory back to the + /// specified allocator. + template<typename AllocatorTy> + void Destroy(AllocatorTy &Allocator) { + // Free memory referenced by the item. + size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1; + this->~StringMapEntry(); + Allocator.Deallocate(static_cast<void *>(this), AllocSize); + } + + /// Destroy this object, releasing memory back to the malloc allocator. + void Destroy() { + MallocAllocator A; + Destroy(A); + } +}; + +/// StringMap - This is an unconventional map that is specialized for handling +/// keys that are "strings", which are basically ranges of bytes. This does some +/// funky memory allocation and hashing things to make it extremely efficient, +/// storing the string data *after* the value in the map. +template<typename ValueTy, typename AllocatorTy = MallocAllocator> +class StringMap : public StringMapImpl { + AllocatorTy Allocator; + +public: + using MapEntryTy = StringMapEntry<ValueTy>; + + StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {} + + explicit StringMap(unsigned InitialSize) + : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {} + + explicit StringMap(AllocatorTy A) + : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {} + + StringMap(unsigned InitialSize, AllocatorTy A) + : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))), + Allocator(A) {} + + StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List) + : StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) { + for (const auto &P : List) { + insert(P); + } + } + + StringMap(StringMap &&RHS) + : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {} + + StringMap(const StringMap &RHS) : + StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), + Allocator(RHS.Allocator) { + if (RHS.empty()) + return; + + // Allocate TheTable of the same size as RHS's TheTable, and set the + // sentinel appropriately (and NumBuckets). + init(RHS.NumBuckets); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1), + *RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1); + + NumItems = RHS.NumItems; + NumTombstones = RHS.NumTombstones; + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = RHS.TheTable[I]; + if (!Bucket || Bucket == getTombstoneVal()) { + TheTable[I] = Bucket; + continue; + } + + TheTable[I] = MapEntryTy::Create( + static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator, + static_cast<MapEntryTy *>(Bucket)->getValue()); + HashTable[I] = RHSHashTable[I]; + } + + // Note that here we've copied everything from the RHS into this object, + // tombstones included. We could, instead, have re-probed for each key to + // instantiate this new object without any tombstone buckets. The + // assumption here is that items are rarely deleted from most StringMaps, + // and so tombstones are rare, so the cost of re-probing for all inputs is + // not worthwhile. + } + + StringMap &operator=(StringMap RHS) { + StringMapImpl::swap(RHS); + std::swap(Allocator, RHS.Allocator); + return *this; + } + + ~StringMap() { + // Delete all the elements in the map, but don't reset the elements + // to default values. This is a copy of clear(), but avoids unnecessary + // work not required in the destructor. + if (!empty()) { + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator); + } + } + } + free(TheTable); + } + + AllocatorTy &getAllocator() { return Allocator; } + const AllocatorTy &getAllocator() const { return Allocator; } + + using key_type = const char*; + using mapped_type = ValueTy; + using value_type = StringMapEntry<ValueTy>; + using size_type = size_t; + + using const_iterator = StringMapConstIterator<ValueTy>; + using iterator = StringMapIterator<ValueTy>; + + iterator begin() { + return iterator(TheTable, NumBuckets == 0); + } + iterator end() { + return iterator(TheTable+NumBuckets, true); + } + const_iterator begin() const { + return const_iterator(TheTable, NumBuckets == 0); + } + const_iterator end() const { + return const_iterator(TheTable+NumBuckets, true); + } + + 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(); + return iterator(TheTable+Bucket, true); + } + + const_iterator find(StringRef Key) const { + int Bucket = FindKey(Key); + if (Bucket == -1) return end(); + return const_iterator(TheTable+Bucket, true); + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueTy lookup(StringRef Key) const { + const_iterator it = find(Key); + if (it != end()) + return it->second; + return ValueTy(); + } + + /// Lookup the ValueTy for the \p Key, or create a default constructed value + /// if the key is not in the map. + ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; } + + /// count - Return 1 if the element is in the map, 0 otherwise. + size_type count(StringRef Key) const { + return find(Key) == end() ? 0 : 1; + } + + template <typename InputTy> + size_type count(const StringMapEntry<InputTy> &MapEntry) const { + return count(MapEntry.getKey()); + } + + /// insert - Insert the specified key/value pair into the map. If the key + /// already exists in the map, return false and ignore the request, otherwise + /// insert it and return true. + bool insert(MapEntryTy *KeyValue) { + unsigned BucketNo = LookupBucketFor(KeyValue->getKey()); + StringMapEntryBase *&Bucket = TheTable[BucketNo]; + if (Bucket && Bucket != getTombstoneVal()) + return false; // Already exists in map. + + if (Bucket == getTombstoneVal()) + --NumTombstones; + Bucket = KeyValue; + ++NumItems; + assert(NumItems + NumTombstones <= NumBuckets); + + RehashTable(); + return true; + } + + /// insert - Inserts the specified key/value pair into the map if the key + /// isn't already in the map. The bool component of the returned pair is true + /// if and only if the insertion takes place, and the iterator component of + /// the pair points to the element with key equivalent to the key of the pair. + std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) { + return try_emplace(KV.first, std::move(KV.second)); + } + + /// Inserts an element or assigns to the current element if the key already + /// exists. The return type is the same as try_emplace. + template <typename V> + std::pair<iterator, bool> insert_or_assign(StringRef Key, V &&Val) { + auto Ret = try_emplace(Key, std::forward<V>(Val)); + if (!Ret.second) + Ret.first->second = std::forward<V>(Val); + return Ret; + } + + /// Emplace a new element for the specified key into the map if the key isn't + /// already in the map. The bool component of the returned pair is true + /// if and only if the insertion takes place, and the iterator component of + /// the pair points to the element with key equivalent to the key of the pair. + template <typename... ArgsTy> + std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) { + unsigned BucketNo = LookupBucketFor(Key); + StringMapEntryBase *&Bucket = TheTable[BucketNo]; + if (Bucket && Bucket != getTombstoneVal()) + return std::make_pair(iterator(TheTable + BucketNo, false), + false); // Already exists in map. + + if (Bucket == getTombstoneVal()) + --NumTombstones; + Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...); + ++NumItems; + assert(NumItems + NumTombstones <= NumBuckets); + + BucketNo = RehashTable(BucketNo); + return std::make_pair(iterator(TheTable + BucketNo, false), true); + } + + // clear - Empties out the StringMap + void clear() { + if (empty()) return; + + // Zap all values, resetting the keys back to non-present (not tombstone), + // which is safe because we're removing all elements. + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *&Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator); + } + Bucket = nullptr; + } + + NumItems = 0; + NumTombstones = 0; + } + + /// remove - Remove the specified key/value pair from the map, but do not + /// erase it. This aborts if the key is not in the map. + void remove(MapEntryTy *KeyValue) { + RemoveKey(KeyValue); + } + + void erase(iterator I) { + MapEntryTy &V = *I; + remove(&V); + V.Destroy(Allocator); + } + + bool erase(StringRef Key) { + iterator I = find(Key); + if (I == end()) return false; + erase(I); + return true; + } +}; + +template <typename DerivedTy, typename ValueTy> +class StringMapIterBase + : public iterator_facade_base<DerivedTy, std::forward_iterator_tag, + ValueTy> { +protected: + StringMapEntryBase **Ptr = nullptr; + +public: + StringMapIterBase() = default; + + explicit StringMapIterBase(StringMapEntryBase **Bucket, + bool NoAdvance = false) + : Ptr(Bucket) { + if (!NoAdvance) AdvancePastEmptyBuckets(); + } + + DerivedTy &operator=(const DerivedTy &Other) { + Ptr = Other.Ptr; + return static_cast<DerivedTy &>(*this); + } + + bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; } + + DerivedTy &operator++() { // Preincrement + ++Ptr; + AdvancePastEmptyBuckets(); + return static_cast<DerivedTy &>(*this); + } + + DerivedTy operator++(int) { // Post-increment + DerivedTy Tmp(Ptr); + ++*this; + return Tmp; + } + +private: + void AdvancePastEmptyBuckets() { + while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal()) + ++Ptr; + } +}; + +template <typename ValueTy> +class StringMapConstIterator + : public StringMapIterBase<StringMapConstIterator<ValueTy>, + const StringMapEntry<ValueTy>> { + using base = StringMapIterBase<StringMapConstIterator<ValueTy>, + const StringMapEntry<ValueTy>>; + +public: + 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) + : base(Bucket, NoAdvance) {} + + StringMapEntry<ValueTy> &operator*() const { + return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr); + } + + operator StringMapConstIterator<ValueTy>() const { + return StringMapConstIterator<ValueTy>(this->Ptr, true); + } +}; + +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 + +#endif // LLVM_ADT_STRINGMAP_H diff --git a/third_party/llvm-project/include/llvm/ADT/StringRef.h b/third_party/llvm-project/include/llvm/ADT/StringRef.h new file mode 100644 index 000000000..e87a08f7e --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/StringRef.h @@ -0,0 +1,920 @@ +//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGREF_H +#define LLVM_ADT_STRINGREF_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compiler.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <limits> +#include <string> +#include <type_traits> +#include <utility> + +// Declare the __builtin_strlen intrinsic for MSVC so it can be used in +// constexpr context. +#if defined(_MSC_VER) +extern "C" size_t __builtin_strlen(const char *); +#endif + +namespace llvm { + + class APInt; + class hash_code; + template <typename T> class SmallVectorImpl; + class StringRef; + + /// Helper functions for StringRef::getAsInteger. + bool getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result); + + bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result); + + bool consumeUnsignedInteger(StringRef &Str, unsigned Radix, + unsigned long long &Result); + bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result); + + /// StringRef - Represent a constant reference to a string, i.e. a character + /// array and a length, which need not be null terminated. + /// + /// This class does not own the string data, it is expected to be used in + /// situations where the character data resides in some other buffer, whose + /// lifetime extends past that of the StringRef. For this reason, it is not in + /// general safe to store a StringRef. + class StringRef { + public: + static const size_t npos = ~size_t(0); + + using iterator = const char *; + using const_iterator = const char *; + using size_type = size_t; + + private: + /// The start of the string, in an external buffer. + const char *Data = nullptr; + + /// The length of the string. + size_t Length = 0; + + // Workaround memcmp issue with null pointers (undefined behavior) + // by providing a specialized version + static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { + if (Length == 0) { return 0; } + return ::memcmp(Lhs,Rhs,Length); + } + + // Constexpr version of std::strlen. + static constexpr size_t strLen(const char *Str) { +#if __cplusplus > 201402L + return std::char_traits<char>::length(Str); +#elif __has_builtin(__builtin_strlen) || defined(__GNUC__) || defined(_MSC_VER) + return __builtin_strlen(Str); +#else + const char *Begin = Str; + while (*Str != '\0') + ++Str; + return Str - Begin; +#endif + } + + public: + /// @name Constructors + /// @{ + + /// Construct an empty string ref. + /*implicit*/ StringRef() = default; + + /// Disable conversion from nullptr. This prevents things like + /// if (S == nullptr) + StringRef(std::nullptr_t) = delete; + + /// Construct a string ref from a cstring. + /*implicit*/ constexpr StringRef(const char *Str) + : Data(Str), Length(Str ? strLen(Str) : 0) {} + + /// Construct a string ref from a pointer and length. + /*implicit*/ constexpr StringRef(const char *data, size_t length) + : Data(data), Length(length) {} + + /// Construct a string ref from an std::string. + /*implicit*/ StringRef(const std::string &Str) + : Data(Str.data()), Length(Str.length()) {} + + static StringRef withNullAsEmpty(const char *data) { + return StringRef(data ? data : ""); + } + + /// @} + /// @name Iterators + /// @{ + + iterator begin() const { return Data; } + + iterator end() const { return Data + Length; } + + const unsigned char *bytes_begin() const { + return reinterpret_cast<const unsigned char *>(begin()); + } + const unsigned char *bytes_end() const { + return reinterpret_cast<const unsigned char *>(end()); + } + iterator_range<const unsigned char *> bytes() const { + return make_range(bytes_begin(), bytes_end()); + } + + /// @} + /// @name String Operations + /// @{ + + /// data - Get a pointer to the start of the string (which may not be null + /// terminated). + LLVM_NODISCARD + const char *data() const { return Data; } + + /// empty - Check if the string is empty. + LLVM_NODISCARD + bool empty() const { return Length == 0; } + + /// size - Get the string size. + LLVM_NODISCARD + size_t size() const { return Length; } + + /// front - Get the first character in the string. + LLVM_NODISCARD + char front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last character in the string. + LLVM_NODISCARD + char back() const { + assert(!empty()); + return Data[Length-1]; + } + + // copy - Allocate copy in Allocator and return StringRef to it. + template <typename Allocator> + LLVM_NODISCARD StringRef copy(Allocator &A) const { + // Don't request a length 0 copy from the allocator. + if (empty()) + return StringRef(); + char *S = A.template Allocate<char>(Length); + std::copy(begin(), end(), S); + return StringRef(S, Length); + } + + /// equals - Check for string equality, this is more efficient than + /// compare() when the relative ordering of inequal strings isn't needed. + LLVM_NODISCARD + bool equals(StringRef RHS) const { + return (Length == RHS.Length && + compareMemory(Data, RHS.Data, RHS.Length) == 0); + } + + /// equals_lower - Check for string equality, ignoring case. + LLVM_NODISCARD + bool equals_lower(StringRef RHS) const { + return Length == RHS.Length && compare_lower(RHS) == 0; + } + + /// compare - Compare two strings; the result is -1, 0, or 1 if this string + /// is lexicographically less than, equal to, or greater than the \p RHS. + LLVM_NODISCARD + int compare(StringRef RHS) const { + // Check the prefix for a mismatch. + if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length))) + return Res < 0 ? -1 : 1; + + // Otherwise the prefixes match, so we only need to check the lengths. + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; + } + + /// compare_lower - Compare two strings, ignoring case. + LLVM_NODISCARD + int compare_lower(StringRef RHS) const; + + /// compare_numeric - Compare two strings, treating sequences of digits as + /// numbers. + LLVM_NODISCARD + int compare_numeric(StringRef RHS) const; + + /// Determine the edit distance between this string and another + /// string. + /// + /// \param Other the string to compare this string against. + /// + /// \param AllowReplacements whether to allow character + /// replacements (change one character into another) as a single + /// operation, rather than as two operations (an insertion and a + /// removal). + /// + /// \param MaxEditDistance If non-zero, the maximum edit distance that + /// this routine is allowed to compute. If the edit distance will exceed + /// that maximum, returns \c MaxEditDistance+1. + /// + /// \returns the minimum number of character insertions, removals, + /// or (if \p AllowReplacements is \c true) replacements needed to + /// transform one of the given strings into the other. If zero, + /// the strings are identical. + LLVM_NODISCARD + unsigned edit_distance(StringRef Other, bool AllowReplacements = true, + unsigned MaxEditDistance = 0) const; + + /// str - Get the contents as an std::string. + LLVM_NODISCARD + std::string str() const { + if (!Data) return std::string(); + return std::string(Data, Length); + } + + /// @} + /// @name Operator Overloads + /// @{ + + LLVM_NODISCARD + char operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// Disallow accidental assignment from a temporary std::string. + /// + /// The declaration here is extra complicated so that `stringRef = {}` + /// and `stringRef = "abc"` continue to select the move assignment operator. + template <typename T> + typename std::enable_if<std::is_same<T, std::string>::value, + StringRef>::type & + operator=(T &&Str) = delete; + + /// @} + /// @name Type Conversions + /// @{ + + operator std::string() const { + return str(); + } + + /// @} + /// @name String Predicates + /// @{ + + /// Check if this string starts with the given \p Prefix. + LLVM_NODISCARD + bool startswith(StringRef Prefix) const { + return Length >= Prefix.Length && + compareMemory(Data, Prefix.Data, Prefix.Length) == 0; + } + + /// Check if this string starts with the given \p Prefix, ignoring case. + LLVM_NODISCARD + bool startswith_lower(StringRef Prefix) const; + + /// Check if this string ends with the given \p Suffix. + LLVM_NODISCARD + bool endswith(StringRef Suffix) const { + return Length >= Suffix.Length && + compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0; + } + + /// Check if this string ends with the given \p Suffix, ignoring case. + LLVM_NODISCARD + bool endswith_lower(StringRef Suffix) const; + + /// @} + /// @name String Searching + /// @{ + + /// Search for the first character \p C in the string. + /// + /// \returns The index of the first occurrence of \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t find(char C, size_t From = 0) const { + size_t FindBegin = std::min(From, Length); + if (FindBegin < Length) { // Avoid calling memchr with nullptr. + // Just forward to memchr, which is faster than a hand-rolled loop. + if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin)) + return static_cast<const char *>(P) - Data; + } + return npos; + } + + /// Search for the first character \p C in the string, ignoring case. + /// + /// \returns The index of the first occurrence of \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t find_lower(char C, size_t From = 0) const; + + /// Search for the first character satisfying the predicate \p F + /// + /// \returns The index of the first character satisfying \p F starting from + /// \p From, or npos if not found. + LLVM_NODISCARD + size_t find_if(function_ref<bool(char)> F, size_t From = 0) const { + StringRef S = drop_front(From); + while (!S.empty()) { + if (F(S.front())) + return size() - S.size(); + S = S.drop_front(); + } + return npos; + } + + /// Search for the first character not satisfying the predicate \p F + /// + /// \returns The index of the first character not satisfying \p F starting + /// from \p From, or npos if not found. + LLVM_NODISCARD + size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const { + return find_if([F](char c) { return !F(c); }, From); + } + + /// Search for the first string \p Str in the string. + /// + /// \returns The index of the first occurrence of \p Str, or npos if not + /// found. + LLVM_NODISCARD + size_t find(StringRef Str, size_t From = 0) const; + + /// Search for the first string \p Str in the string, ignoring case. + /// + /// \returns The index of the first occurrence of \p Str, or npos if not + /// found. + LLVM_NODISCARD + size_t find_lower(StringRef Str, size_t From = 0) const; + + /// Search for the last character \p C in the string. + /// + /// \returns The index of the last occurrence of \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t rfind(char C, size_t From = npos) const { + From = std::min(From, Length); + size_t i = From; + while (i != 0) { + --i; + if (Data[i] == C) + return i; + } + return npos; + } + + /// Search for the last character \p C in the string, ignoring case. + /// + /// \returns The index of the last occurrence of \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t rfind_lower(char C, size_t From = npos) const; + + /// Search for the last string \p Str in the string. + /// + /// \returns The index of the last occurrence of \p Str, or npos if not + /// found. + LLVM_NODISCARD + size_t rfind(StringRef Str) const; + + /// Search for the last string \p Str in the string, ignoring case. + /// + /// \returns The index of the last occurrence of \p Str, or npos if not + /// found. + LLVM_NODISCARD + size_t rfind_lower(StringRef Str) const; + + /// Find the first character in the string that is \p C, or npos if not + /// found. Same as find. + LLVM_NODISCARD + size_t find_first_of(char C, size_t From = 0) const { + return find(C, From); + } + + /// Find the first character in the string that is in \p Chars, or npos if + /// not found. + /// + /// Complexity: O(size() + Chars.size()) + LLVM_NODISCARD + size_t find_first_of(StringRef Chars, size_t From = 0) const; + + /// Find the first character in the string that is not \p C or npos if not + /// found. + LLVM_NODISCARD + size_t find_first_not_of(char C, size_t From = 0) const; + + /// Find the first character in the string that is not in the string + /// \p Chars, or npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + LLVM_NODISCARD + size_t find_first_not_of(StringRef Chars, size_t From = 0) const; + + /// Find the last character in the string that is \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t find_last_of(char C, size_t From = npos) const { + return rfind(C, From); + } + + /// Find the last character in the string that is in \p C, or npos if not + /// found. + /// + /// Complexity: O(size() + Chars.size()) + LLVM_NODISCARD + size_t find_last_of(StringRef Chars, size_t From = npos) const; + + /// Find the last character in the string that is not \p C, or npos if not + /// found. + LLVM_NODISCARD + size_t find_last_not_of(char C, size_t From = npos) const; + + /// Find the last character in the string that is not in \p Chars, or + /// npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + LLVM_NODISCARD + size_t find_last_not_of(StringRef Chars, size_t From = npos) const; + + /// Return true if the given string is a substring of *this, and false + /// otherwise. + LLVM_NODISCARD + bool contains(StringRef Other) const { return find(Other) != npos; } + + /// Return true if the given character is contained in *this, and false + /// otherwise. + LLVM_NODISCARD + bool contains(char C) const { return find_first_of(C) != npos; } + + /// Return true if the given string is a substring of *this, and false + /// otherwise. + LLVM_NODISCARD + bool contains_lower(StringRef Other) const { + return find_lower(Other) != npos; + } + + /// Return true if the given character is contained in *this, and false + /// otherwise. + LLVM_NODISCARD + bool contains_lower(char C) const { return find_lower(C) != npos; } + + /// @} + /// @name Helpful Algorithms + /// @{ + + /// Return the number of occurrences of \p C in the string. + LLVM_NODISCARD + size_t count(char C) const { + size_t Count = 0; + for (size_t i = 0, e = Length; i != e; ++i) + if (Data[i] == C) + ++Count; + return Count; + } + + /// Return the number of non-overlapped occurrences of \p Str in + /// the string. + size_t count(StringRef Str) const; + + /// Parse the current string as an integer of the specified radix. If + /// \p Radix is specified as zero, this does radix autosensing using + /// extended C rules: 0 is octal, 0x is hex, 0b is binary. + /// + /// If the string is invalid or if only a subset of the string is valid, + /// this returns true to signify the error. The string is considered + /// erroneous if empty or if it overflows T. + template <typename T> + typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + long long LLVal; + if (getAsSignedInteger(*this, Radix, LLVal) || + static_cast<T>(LLVal) != LLVal) + return true; + Result = LLVal; + return false; + } + + template <typename T> + typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + unsigned long long ULLVal; + // The additional cast to unsigned long long is required to avoid the + // Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type + // 'unsigned __int64' when instantiating getAsInteger with T = bool. + if (getAsUnsignedInteger(*this, Radix, ULLVal) || + static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal) + return true; + Result = ULLVal; + return false; + } + + /// Parse the current string as an integer of the specified radix. If + /// \p Radix is specified as zero, this does radix autosensing using + /// extended C rules: 0 is octal, 0x is hex, 0b is binary. + /// + /// If the string does not begin with a number of the specified radix, + /// this returns true to signify the error. The string is considered + /// erroneous if empty or if it overflows T. + /// The portion of the string representing the discovered numeric value + /// is removed from the beginning of the string. + template <typename T> + typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type + consumeInteger(unsigned Radix, T &Result) { + long long LLVal; + if (consumeSignedInteger(*this, Radix, LLVal) || + static_cast<long long>(static_cast<T>(LLVal)) != LLVal) + return true; + Result = LLVal; + return false; + } + + template <typename T> + typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type + consumeInteger(unsigned Radix, T &Result) { + unsigned long long ULLVal; + if (consumeUnsignedInteger(*this, Radix, ULLVal) || + static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal) + return true; + Result = ULLVal; + return false; + } + + /// Parse the current string as an integer of the specified \p Radix, or of + /// an autosensed radix if the \p Radix given is 0. The current value in + /// \p Result is discarded, and the storage is changed to be wide enough to + /// store the parsed integer. + /// + /// \returns true if the string does not solely consist of a valid + /// non-empty number in the appropriate base. + /// + /// APInt::fromString is superficially similar but assumes the + /// 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 + /// @{ + + // Convert the given ASCII string to lowercase. + LLVM_NODISCARD + std::string lower() const; + + /// Convert the given ASCII string to uppercase. + LLVM_NODISCARD + std::string upper() const; + + /// @} + /// @name Substring Operations + /// @{ + + /// Return a reference to the substring from [Start, Start + N). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param N The number of characters to included in the substring. If N + /// exceeds the number of characters remaining in the string, the string + /// suffix (starting with \p Start) will be returned. + LLVM_NODISCARD + StringRef substr(size_t Start, size_t N = npos) const { + Start = std::min(Start, Length); + return StringRef(Data + Start, std::min(N, Length - Start)); + } + + /// Return a StringRef equal to 'this' but with only the first \p N + /// elements remaining. If \p N is greater than the length of the + /// string, the entire string is returned. + LLVM_NODISCARD + StringRef take_front(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_back(size() - 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 + StringRef take_back(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_front(size() - N); + } + + /// Return the longest prefix of 'this' such that every character + /// in the prefix satisfies the given predicate. + LLVM_NODISCARD + StringRef take_while(function_ref<bool(char)> F) const { + return substr(0, find_if_not(F)); + } + + /// Return the longest prefix of 'this' such that no character in + /// the prefix satisfies the given predicate. + LLVM_NODISCARD + StringRef take_until(function_ref<bool(char)> F) const { + return substr(0, find_if(F)); + } + + /// Return a StringRef equal to 'this' but with the first \p N elements + /// dropped. + LLVM_NODISCARD + StringRef drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return substr(N); + } + + /// Return a StringRef equal to 'this' but with the last \p N elements + /// dropped. + LLVM_NODISCARD + StringRef drop_back(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return substr(0, size()-N); + } + + /// Return a StringRef equal to 'this', but with all characters satisfying + /// the given predicate dropped from the beginning of the string. + LLVM_NODISCARD + StringRef drop_while(function_ref<bool(char)> F) const { + return substr(find_if_not(F)); + } + + /// Return a StringRef equal to 'this', but with all characters not + /// satisfying the given predicate dropped from the beginning of the string. + LLVM_NODISCARD + StringRef drop_until(function_ref<bool(char)> F) const { + return substr(find_if(F)); + } + + /// Returns true if this StringRef has the given prefix and removes that + /// prefix. + bool consume_front(StringRef Prefix) { + if (!startswith(Prefix)) + return false; + + *this = drop_front(Prefix.size()); + return true; + } + + /// Returns true if this StringRef has the given suffix and removes that + /// suffix. + bool consume_back(StringRef Suffix) { + if (!endswith(Suffix)) + return false; + + *this = drop_back(Suffix.size()); + return true; + } + + /// Return a reference to the substring from [Start, End). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param End The index following the last character to include in the + /// substring. If this is npos or exceeds the number of characters + /// remaining in the string, the string suffix (starting with \p Start) + /// will be returned. If this is less than \p Start, an empty string will + /// be returned. + LLVM_NODISCARD + StringRef slice(size_t Start, size_t End) const { + Start = std::min(Start, Length); + End = std::min(std::max(Start, End), Length); + return StringRef(Data + Start, End - Start); + } + + /// Split into two substrings around the first occurrence of a separator + /// character. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// maximal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator The character to split on. + /// \returns The split substrings. + LLVM_NODISCARD + std::pair<StringRef, StringRef> split(char Separator) const { + return split(StringRef(&Separator, 1)); + } + + /// Split into two substrings around the first occurrence of a separator + /// string. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// maximal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator - The string to split on. + /// \return - The split substrings. + LLVM_NODISCARD + std::pair<StringRef, StringRef> split(StringRef Separator) const { + size_t Idx = find(Separator); + if (Idx == npos) + return std::make_pair(*this, StringRef()); + return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos)); + } + + /// Split into two substrings around the last occurrence of a separator + /// string. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// minimal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator - The string to split on. + /// \return - The split substrings. + LLVM_NODISCARD + std::pair<StringRef, StringRef> rsplit(StringRef Separator) const { + size_t Idx = rfind(Separator); + if (Idx == npos) + return std::make_pair(*this, StringRef()); + return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos)); + } + + /// Split into substrings around the occurrences of a separator string. + /// + /// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most + /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1 + /// elements are added to A. + /// If \p KeepEmpty is false, empty strings are not added to \p A. They + /// still count when considering \p MaxSplit + /// An useful invariant is that + /// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true + /// + /// \param A - Where to put the substrings. + /// \param Separator - The string to split on. + /// \param MaxSplit - The maximum number of times the string is split. + /// \param KeepEmpty - True if empty substring should be added. + void split(SmallVectorImpl<StringRef> &A, + StringRef Separator, int MaxSplit = -1, + bool KeepEmpty = true) const; + + /// Split into substrings around the occurrences of a separator character. + /// + /// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most + /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1 + /// elements are added to A. + /// If \p KeepEmpty is false, empty strings are not added to \p A. They + /// still count when considering \p MaxSplit + /// An useful invariant is that + /// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true + /// + /// \param A - Where to put the substrings. + /// \param Separator - The string to split on. + /// \param MaxSplit - The maximum number of times the string is split. + /// \param KeepEmpty - True if empty substring should be added. + void split(SmallVectorImpl<StringRef> &A, char Separator, int MaxSplit = -1, + bool KeepEmpty = true) const; + + /// Split into two substrings around the last occurrence of a separator + /// character. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// minimal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator - The character to split on. + /// \return - The split substrings. + LLVM_NODISCARD + std::pair<StringRef, StringRef> rsplit(char Separator) const { + return rsplit(StringRef(&Separator, 1)); + } + + /// Return string with consecutive \p Char characters starting from the + /// the left removed. + LLVM_NODISCARD + StringRef ltrim(char Char) const { + return drop_front(std::min(Length, find_first_not_of(Char))); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the left removed. + LLVM_NODISCARD + StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const { + return drop_front(std::min(Length, find_first_not_of(Chars))); + } + + /// Return string with consecutive \p Char characters starting from the + /// right removed. + LLVM_NODISCARD + StringRef rtrim(char Char) const { + return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1)); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the right removed. + LLVM_NODISCARD + StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const { + return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1)); + } + + /// Return string with consecutive \p Char characters starting from the + /// left and right removed. + LLVM_NODISCARD + StringRef trim(char Char) const { + return ltrim(Char).rtrim(Char); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the left and right removed. + LLVM_NODISCARD + StringRef trim(StringRef Chars = " \t\n\v\f\r") const { + return ltrim(Chars).rtrim(Chars); + } + + /// @} + }; + + /// A wrapper around a string literal that serves as a proxy for constructing + /// global tables of StringRefs with the length computed at compile time. + /// In order to avoid the invocation of a global constructor, StringLiteral + /// should *only* be used in a constexpr context, as such: + /// + /// constexpr StringLiteral S("test"); + /// + class StringLiteral : public StringRef { + private: + constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) { + } + + public: + template <size_t N> + constexpr StringLiteral(const char (&Str)[N]) +#if defined(__clang__) && __has_attribute(enable_if) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + __attribute((enable_if(__builtin_strlen(Str) == N - 1, + "invalid string literal"))) +#pragma clang diagnostic pop +#endif + : StringRef(Str, N - 1) { + } + + // Explicit construction for strings like "foo\0bar". + template <size_t N> + static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) { + return StringLiteral(Str, N - 1); + } + }; + + /// @name StringRef Comparison Operators + /// @{ + + inline bool operator==(StringRef LHS, StringRef RHS) { + return LHS.equals(RHS); + } + + inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); } + + inline bool operator<(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) == -1; + } + + inline bool operator<=(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) != 1; + } + + inline bool operator>(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) == 1; + } + + inline bool operator>=(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) != -1; + } + + inline std::string &operator+=(std::string &buffer, StringRef string) { + return buffer.append(string.data(), string.size()); + } + + /// @} + + /// Compute a hash_code for a StringRef. + LLVM_NODISCARD + hash_code hash_value(StringRef S); + +} // end namespace llvm + +#endif // LLVM_ADT_STRINGREF_H diff --git a/third_party/llvm-project/include/llvm/ADT/StringSet.h b/third_party/llvm-project/include/llvm/ADT/StringSet.h new file mode 100644 index 000000000..60be09d3c --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/StringSet.h @@ -0,0 +1,58 @@ +//===- StringSet.h - The LLVM Compiler Driver -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// StringSet - A set-like wrapper for the StringMap. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGSET_H +#define LLVM_ADT_STRINGSET_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <initializer_list> +#include <utility> + +namespace llvm { + + /// StringSet - A wrapper for StringMap that provides set-like functionality. + template <class AllocatorTy = MallocAllocator> + class StringSet : public StringMap<NoneType, AllocatorTy> { + using base = StringMap<NoneType, AllocatorTy>; + + public: + StringSet() = default; + StringSet(std::initializer_list<StringRef> S) { + for (StringRef X : S) + insert(X); + } + explicit StringSet(AllocatorTy A) : base(A) {} + + std::pair<typename base::iterator, bool> insert(StringRef Key) { + assert(!Key.empty()); + return base::insert(std::make_pair(Key, None)); + } + + template <typename InputIt> + void insert(const InputIt &Begin, const InputIt &End) { + for (auto It = Begin; It != End; ++It) + base::insert(std::make_pair(*It, None)); + } + + template <typename ValueTy> + std::pair<typename base::iterator, bool> + insert(const StringMapEntry<ValueTy> &MapEntry) { + return insert(MapEntry.getKey()); + } + }; + +} // end namespace llvm + +#endif // LLVM_ADT_STRINGSET_H diff --git a/third_party/llvm-project/include/llvm/ADT/StringSwitch.h b/third_party/llvm-project/include/llvm/ADT/StringSwitch.h new file mode 100644 index 000000000..fea911f69 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/StringSwitch.h @@ -0,0 +1,196 @@ +//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===/ +// +// This file implements the StringSwitch template, which mimics a switch() +// statement whose cases are string literals. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_ADT_STRINGSWITCH_H +#define LLVM_ADT_STRINGSWITCH_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include <cassert> +#include <cstring> + +namespace llvm { + +/// A switch()-like statement whose cases are string literals. +/// +/// The StringSwitch class is a simple form of a switch() statement that +/// determines whether the given string matches one of the given string +/// literals. The template type parameter \p T is the type of the value that +/// will be returned from the string-switch expression. For example, +/// the following code switches on the name of a color in \c argv[i]: +/// +/// \code +/// Color color = StringSwitch<Color>(argv[i]) +/// .Case("red", Red) +/// .Case("orange", Orange) +/// .Case("yellow", Yellow) +/// .Case("green", Green) +/// .Case("blue", Blue) +/// .Case("indigo", Indigo) +/// .Cases("violet", "purple", Violet) +/// .Default(UnknownColor); +/// \endcode +template<typename T, typename R = T> +class StringSwitch { + /// The string we are matching. + const StringRef Str; + + /// The pointer to the result of this switch statement, once known, + /// null before that. + Optional<T> Result; + +public: + explicit StringSwitch(StringRef S) + : Str(S), Result() { } + + // StringSwitch is not copyable. + StringSwitch(const StringSwitch &) = delete; + + // StringSwitch is not assignable due to 'Str' being 'const'. + void operator=(const StringSwitch &) = delete; + void operator=(StringSwitch &&other) = delete; + + StringSwitch(StringSwitch &&other) + : Str(other.Str), Result(std::move(other.Result)) { } + + ~StringSwitch() = default; + + // Case-sensitive case matchers + StringSwitch &Case(StringLiteral S, T Value) { + if (!Result && Str == S) { + Result = std::move(Value); + } + return *this; + } + + StringSwitch& EndsWith(StringLiteral S, T Value) { + if (!Result && Str.endswith(S)) { + Result = std::move(Value); + } + return *this; + } + + StringSwitch& StartsWith(StringLiteral S, T Value) { + if (!Result && Str.startswith(S)) { + Result = std::move(Value); + } + return *this; + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) { + return Case(S0, Value).Case(S1, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + T Value) { + return Case(S0, Value).Cases(S1, S2, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, T Value) { + return Case(S0, Value).Cases(S1, S2, S3, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, StringLiteral S5, + T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, StringLiteral S5, + StringLiteral S6, T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, StringLiteral S5, + StringLiteral S6, StringLiteral S7, T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, StringLiteral S5, + StringLiteral S6, StringLiteral S7, StringLiteral S8, + T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value); + } + + StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, StringLiteral S5, + StringLiteral S6, StringLiteral S7, StringLiteral S8, + StringLiteral S9, T Value) { + return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value); + } + + // Case-insensitive case matchers. + StringSwitch &CaseLower(StringLiteral S, T Value) { + if (!Result && Str.equals_lower(S)) + Result = std::move(Value); + + return *this; + } + + StringSwitch &EndsWithLower(StringLiteral S, T Value) { + if (!Result && Str.endswith_lower(S)) + Result = Value; + + return *this; + } + + StringSwitch &StartsWithLower(StringLiteral S, T Value) { + if (!Result && Str.startswith_lower(S)) + Result = std::move(Value); + + return *this; + } + + StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) { + return CaseLower(S0, Value).CaseLower(S1, Value); + } + + StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, + T Value) { + return CaseLower(S0, Value).CasesLower(S1, S2, Value); + } + + StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, T Value) { + return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value); + } + + StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, + StringLiteral S3, StringLiteral S4, T Value) { + return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value); + } + + LLVM_NODISCARD + R Default(T Value) { + if (Result) + return std::move(*Result); + return Value; + } + + LLVM_NODISCARD + operator R() { + assert(Result && "Fell off the end of a string-switch"); + return std::move(*Result); + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_STRINGSWITCH_H diff --git a/third_party/llvm-project/include/llvm/ADT/Triple.h b/third_party/llvm-project/include/llvm/ADT/Triple.h new file mode 100644 index 000000000..edeb31efa --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/Triple.h @@ -0,0 +1,881 @@ +//===-- llvm/ADT/Triple.h - Target triple helper class ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_TRIPLE_H +#define LLVM_ADT_TRIPLE_H + +#include "llvm/ADT/Twine.h" + +// Some system headers or GCC predefined macros conflict with identifiers in +// this file. Undefine them here. +#undef NetBSD +#undef mips +#undef sparc + +namespace llvm { + +/// Triple - Helper class for working with autoconf configuration names. For +/// historical reasons, we also call these 'triples' (they used to contain +/// exactly three fields). +/// +/// Configuration names are strings in the canonical form: +/// ARCHITECTURE-VENDOR-OPERATING_SYSTEM +/// or +/// ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT +/// +/// This class is used for clients which want to support arbitrary +/// configuration names, but also want to implement certain special +/// behavior for particular configurations. This class isolates the mapping +/// from the components of the configuration name to well known IDs. +/// +/// At its core the Triple class is designed to be a wrapper for a triple +/// string; the constructor does not change or normalize the triple string. +/// Clients that need to handle the non-canonical triples that users often +/// specify should use the normalize method. +/// +/// See autoconf/config.guess for a glimpse into what configuration names +/// look like in practice. +class Triple { +public: + enum ArchType { + UnknownArch, + + arm, // ARM (little endian): arm, armv.*, xscale + armeb, // ARM (big endian): armeb + aarch64, // AArch64 (little endian): aarch64 + aarch64_be, // AArch64 (big endian): aarch64_be + aarch64_32, // AArch64 (little endian) ILP32: aarch64_32 + arc, // ARC: Synopsys ARC + avr, // AVR: Atmel AVR microcontroller + bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) + bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) + hexagon, // Hexagon: hexagon + mips, // MIPS: mips, mipsallegrex, mipsr6 + mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el + mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6 + mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el + msp430, // MSP430: msp430 + ppc, // PPC: powerpc + ppc64, // PPC64: powerpc64, ppu + ppc64le, // PPC64LE: powerpc64le + r600, // R600: AMD GPUs HD2XXX - HD6XXX + amdgcn, // AMDGCN: AMD GCN GPUs + riscv32, // RISC-V (32-bit): riscv32 + riscv64, // RISC-V (64-bit): riscv64 + sparc, // Sparc: sparc + sparcv9, // Sparcv9: Sparcv9 + sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant + systemz, // SystemZ: s390x + tce, // TCE (http://tce.cs.tut.fi/): tce + tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele + thumb, // Thumb (little endian): thumb, thumbv.* + thumbeb, // Thumb (big endian): thumbeb + x86, // X86: i[3-9]86 + x86_64, // X86-64: amd64, x86_64 + xcore, // XCore: xcore + nvptx, // NVPTX: 32-bit + nvptx64, // NVPTX: 64-bit + le32, // le32: generic little-endian 32-bit CPU (PNaCl) + le64, // le64: generic little-endian 64-bit CPU (PNaCl) + amdil, // AMDIL + amdil64, // AMDIL with 64-bit pointers + hsail, // AMD HSAIL + hsail64, // AMD HSAIL with 64-bit pointers + spir, // SPIR: standard portable IR for OpenCL 32-bit version + spir64, // SPIR: standard portable IR for OpenCL 64-bit version + kalimba, // Kalimba: generic kalimba + shave, // SHAVE: Movidius vector VLIW processors + lanai, // Lanai: Lanai 32-bit + wasm32, // WebAssembly with 32-bit pointers + wasm64, // WebAssembly with 64-bit pointers + renderscript32, // 32-bit RenderScript + renderscript64, // 64-bit RenderScript + LastArchType = renderscript64 + }; + enum SubArchType { + NoSubArch, + + ARMSubArch_v8_5a, + ARMSubArch_v8_4a, + ARMSubArch_v8_3a, + ARMSubArch_v8_2a, + ARMSubArch_v8_1a, + ARMSubArch_v8, + ARMSubArch_v8r, + ARMSubArch_v8m_baseline, + ARMSubArch_v8m_mainline, + ARMSubArch_v8_1m_mainline, + ARMSubArch_v7, + ARMSubArch_v7em, + ARMSubArch_v7m, + ARMSubArch_v7s, + ARMSubArch_v7k, + ARMSubArch_v7ve, + ARMSubArch_v6, + ARMSubArch_v6m, + ARMSubArch_v6k, + ARMSubArch_v6t2, + ARMSubArch_v5, + ARMSubArch_v5te, + ARMSubArch_v4t, + + KalimbaSubArch_v3, + KalimbaSubArch_v4, + KalimbaSubArch_v5, + + MipsSubArch_r6 + }; + enum VendorType { + UnknownVendor, + + Apple, + PC, + SCEI, + BGP, + BGQ, + Freescale, + IBM, + ImaginationTechnologies, + MipsTechnologies, + NVIDIA, + CSR, + Myriad, + AMD, + Mesa, + SUSE, + OpenEmbedded, + LastVendorType = OpenEmbedded + }; + enum OSType { + UnknownOS, + + Ananas, + CloudABI, + Darwin, + DragonFly, + FreeBSD, + Fuchsia, + IOS, + KFreeBSD, + Linux, + Lv2, // PS3 + MacOSX, + NetBSD, + OpenBSD, + Solaris, + Win32, + Haiku, + Minix, + RTEMS, + NaCl, // Native Client + CNK, // BG/P Compute-Node Kernel + AIX, + CUDA, // NVIDIA CUDA + NVCL, // NVIDIA OpenCL + AMDHSA, // AMD HSA Runtime + PS4, + ELFIAMCU, + TvOS, // Apple tvOS + WatchOS, // Apple watchOS + Mesa3D, + Contiki, + AMDPAL, // AMD PAL Runtime + HermitCore, // HermitCore Unikernel/Multikernel + Hurd, // GNU/Hurd + WASI, // Experimental WebAssembly OS + Emscripten, + LastOSType = Emscripten + }; + enum EnvironmentType { + UnknownEnvironment, + + GNU, + GNUABIN32, + GNUABI64, + GNUEABI, + GNUEABIHF, + GNUX32, + CODE16, + EABI, + EABIHF, + ELFv1, + ELFv2, + Android, + Musl, + MuslEABI, + MuslEABIHF, + + MSVC, + Itanium, + Cygnus, + CoreCLR, + Simulator, // Simulator variants of other systems, e.g., Apple's iOS + MacABI, // Mac Catalyst variant of Apple's iOS deployment target. + LastEnvironmentType = MacABI + }; + enum ObjectFormatType { + UnknownObjectFormat, + + COFF, + ELF, + MachO, + Wasm, + XCOFF, + }; + +private: + std::string Data; + + /// The parsed arch type. + ArchType Arch; + + /// The parsed subarchitecture type. + SubArchType SubArch; + + /// The parsed vendor type. + VendorType Vendor; + + /// The parsed OS type. + OSType OS; + + /// The parsed Environment type. + EnvironmentType Environment; + + /// The object format type. + ObjectFormatType ObjectFormat; + +public: + /// @name Constructors + /// @{ + + /// Default constructor is the same as an empty string and leaves all + /// triple fields unknown. + Triple() + : Data(), Arch(), SubArch(), Vendor(), OS(), Environment(), + ObjectFormat() {} + + explicit Triple(const Twine &Str); + Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr); + Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr, + const Twine &EnvironmentStr); + + bool operator==(const Triple &Other) const { + return Arch == Other.Arch && SubArch == Other.SubArch && + Vendor == Other.Vendor && OS == Other.OS && + Environment == Other.Environment && + ObjectFormat == Other.ObjectFormat; + } + + bool operator!=(const Triple &Other) const { + return !(*this == Other); + } + + /// @} + /// @name Normalization + /// @{ + + /// normalize - Turn an arbitrary machine specification into the canonical + /// triple form (or something sensible that the Triple class understands if + /// nothing better can reasonably be done). In particular, it handles the + /// common case in which otherwise valid components are in the wrong order. + static std::string normalize(StringRef Str); + + /// Return the normalized form of this triple's string. + std::string normalize() const { return normalize(Data); } + + /// @} + /// @name Typed Component Access + /// @{ + + /// getArch - Get the parsed architecture type of this triple. + ArchType getArch() const { return Arch; } + + /// getSubArch - get the parsed subarchitecture type for this triple. + SubArchType getSubArch() const { return SubArch; } + + /// getVendor - Get the parsed vendor type of this triple. + VendorType getVendor() const { return Vendor; } + + /// getOS - Get the parsed operating system type of this triple. + OSType getOS() const { return OS; } + + /// hasEnvironment - Does this triple have the optional environment + /// (fourth) component? + bool hasEnvironment() const { + return getEnvironmentName() != ""; + } + + /// getEnvironment - Get the parsed environment type of this triple. + EnvironmentType getEnvironment() const { return Environment; } + + /// Parse the version number from the OS name component of the + /// triple, if present. + /// + /// For example, "fooos1.2.3" would return (1, 2, 3). + /// + /// If an entry is not defined, it will be returned as 0. + void getEnvironmentVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const; + + /// getFormat - Get the object format for this triple. + ObjectFormatType getObjectFormat() const { return ObjectFormat; } + + /// getOSVersion - Parse the version number from the OS name component of the + /// triple, if present. + /// + /// For example, "fooos1.2.3" would return (1, 2, 3). + /// + /// If an entry is not defined, it will be returned as 0. + void getOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const; + + /// getOSMajorVersion - Return just the major version number, this is + /// specialized because it is a common query. + unsigned getOSMajorVersion() const { + unsigned Maj, Min, Micro; + getOSVersion(Maj, Min, Micro); + return Maj; + } + + /// getMacOSXVersion - Parse the version number as with getOSVersion and then + /// translate generic "darwin" versions to the corresponding OS X versions. + /// This may also be called with IOS triples but the OS X version number is + /// just set to a constant 10.4.0 in that case. Returns true if successful. + bool getMacOSXVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const; + + /// getiOSVersion - Parse the version number as with getOSVersion. This should + /// only be called with IOS or generic triples. + void getiOSVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const; + + /// getWatchOSVersion - Parse the version number as with getOSVersion. This + /// should only be called with WatchOS or generic triples. + void getWatchOSVersion(unsigned &Major, unsigned &Minor, + unsigned &Micro) const; + + /// @} + /// @name Direct Component Access + /// @{ + + const std::string &str() const { return Data; } + + const std::string &getTriple() const { return Data; } + + /// getArchName - Get the architecture (first) component of the + /// triple. + StringRef getArchName() const; + + /// getVendorName - Get the vendor (second) component of the triple. + StringRef getVendorName() const; + + /// getOSName - Get the operating system (third) component of the + /// triple. + StringRef getOSName() const; + + /// getEnvironmentName - Get the optional environment (fourth) + /// component of the triple, or "" if empty. + StringRef getEnvironmentName() const; + + /// getOSAndEnvironmentName - Get the operating system and optional + /// environment components as a single string (separated by a '-' + /// if the environment component is present). + StringRef getOSAndEnvironmentName() const; + + /// @} + /// @name Convenience Predicates + /// @{ + + /// Test whether the architecture is 64-bit + /// + /// Note that this tests for 64-bit pointer width, and nothing else. Note + /// that we intentionally expose only three predicates, 64-bit, 32-bit, and + /// 16-bit. The inner details of pointer width for particular architectures + /// is not summed up in the triple, and so only a coarse grained predicate + /// system is provided. + bool isArch64Bit() const; + + /// Test whether the architecture is 32-bit + /// + /// Note that this tests for 32-bit pointer width, and nothing else. + bool isArch32Bit() const; + + /// Test whether the architecture is 16-bit + /// + /// Note that this tests for 16-bit pointer width, and nothing else. + bool isArch16Bit() const; + + /// isOSVersionLT - Helper function for doing comparisons against version + /// numbers included in the target triple. + bool isOSVersionLT(unsigned Major, unsigned Minor = 0, + unsigned Micro = 0) const { + unsigned LHS[3]; + getOSVersion(LHS[0], LHS[1], LHS[2]); + + if (LHS[0] != Major) + return LHS[0] < Major; + if (LHS[1] != Minor) + return LHS[1] < Minor; + if (LHS[2] != Micro) + return LHS[2] < Micro; + + return false; + } + + bool isOSVersionLT(const Triple &Other) const { + unsigned RHS[3]; + Other.getOSVersion(RHS[0], RHS[1], RHS[2]); + return isOSVersionLT(RHS[0], RHS[1], RHS[2]); + } + + /// isMacOSXVersionLT - Comparison function for checking OS X version + /// compatibility, which handles supporting skewed version numbering schemes + /// used by the "darwin" triples. + bool isMacOSXVersionLT(unsigned Major, unsigned Minor = 0, + unsigned Micro = 0) const { + assert(isMacOSX() && "Not an OS X triple!"); + + // If this is OS X, expect a sane version number. + if (getOS() == Triple::MacOSX) + return isOSVersionLT(Major, Minor, Micro); + + // Otherwise, compare to the "Darwin" number. + assert(Major == 10 && "Unexpected major version"); + return isOSVersionLT(Minor + 4, Micro, 0); + } + + /// isMacOSX - Is this a Mac OS X triple. For legacy reasons, we support both + /// "darwin" and "osx" as OS X triples. + bool isMacOSX() const { + return getOS() == Triple::Darwin || getOS() == Triple::MacOSX; + } + + /// Is this an iOS triple. + /// Note: This identifies tvOS as a variant of iOS. If that ever + /// changes, i.e., if the two operating systems diverge or their version + /// numbers get out of sync, that will need to be changed. + /// watchOS has completely different version numbers so it is not included. + bool isiOS() const { + return getOS() == Triple::IOS || isTvOS(); + } + + /// Is this an Apple tvOS triple. + bool isTvOS() const { + return getOS() == Triple::TvOS; + } + + /// Is this an Apple watchOS triple. + bool isWatchOS() const { + return getOS() == Triple::WatchOS; + } + + bool isWatchABI() const { + return getSubArch() == Triple::ARMSubArch_v7k; + } + + /// isOSDarwin - Is this a "Darwin" OS (OS X, iOS, or watchOS). + bool isOSDarwin() const { + return isMacOSX() || isiOS() || isWatchOS(); + } + + bool isSimulatorEnvironment() const { + return getEnvironment() == Triple::Simulator; + } + + bool isMacCatalystEnvironment() const { + return getEnvironment() == Triple::MacABI; + } + + bool isOSNetBSD() const { + return getOS() == Triple::NetBSD; + } + + bool isOSOpenBSD() const { + return getOS() == Triple::OpenBSD; + } + + bool isOSFreeBSD() const { + return getOS() == Triple::FreeBSD; + } + + bool isOSFuchsia() const { + return getOS() == Triple::Fuchsia; + } + + bool isOSDragonFly() const { return getOS() == Triple::DragonFly; } + + bool isOSSolaris() const { + return getOS() == Triple::Solaris; + } + + bool isOSIAMCU() const { + return getOS() == Triple::ELFIAMCU; + } + + bool isOSUnknown() const { return getOS() == Triple::UnknownOS; } + + bool isGNUEnvironment() const { + EnvironmentType Env = getEnvironment(); + return Env == Triple::GNU || Env == Triple::GNUABIN32 || + Env == Triple::GNUABI64 || Env == Triple::GNUEABI || + Env == Triple::GNUEABIHF || Env == Triple::GNUX32; + } + + bool isOSContiki() const { + return getOS() == Triple::Contiki; + } + + /// Tests whether the OS is Haiku. + bool isOSHaiku() const { + return getOS() == Triple::Haiku; + } + + /// Tests whether the OS is Windows. + bool isOSWindows() const { + return getOS() == Triple::Win32; + } + + /// Checks if the environment is MSVC. + bool isKnownWindowsMSVCEnvironment() const { + return isOSWindows() && getEnvironment() == Triple::MSVC; + } + + /// Checks if the environment could be MSVC. + bool isWindowsMSVCEnvironment() const { + return isKnownWindowsMSVCEnvironment() || + (isOSWindows() && getEnvironment() == Triple::UnknownEnvironment); + } + + bool isWindowsCoreCLREnvironment() const { + return isOSWindows() && getEnvironment() == Triple::CoreCLR; + } + + bool isWindowsItaniumEnvironment() const { + return isOSWindows() && getEnvironment() == Triple::Itanium; + } + + bool isWindowsCygwinEnvironment() const { + return isOSWindows() && getEnvironment() == Triple::Cygnus; + } + + bool isWindowsGNUEnvironment() const { + return isOSWindows() && getEnvironment() == Triple::GNU; + } + + /// Tests for either Cygwin or MinGW OS + bool isOSCygMing() const { + return isWindowsCygwinEnvironment() || isWindowsGNUEnvironment(); + } + + /// Is this a "Windows" OS targeting a "MSVCRT.dll" environment. + bool isOSMSVCRT() const { + return isWindowsMSVCEnvironment() || isWindowsGNUEnvironment() || + isWindowsItaniumEnvironment(); + } + + /// Tests whether the OS is NaCl (Native Client) + bool isOSNaCl() const { + return getOS() == Triple::NaCl; + } + + /// Tests whether the OS is Linux. + bool isOSLinux() const { + return getOS() == Triple::Linux; + } + + /// Tests whether the OS is kFreeBSD. + bool isOSKFreeBSD() const { + return getOS() == Triple::KFreeBSD; + } + + /// Tests whether the OS is Hurd. + bool isOSHurd() const { + return getOS() == Triple::Hurd; + } + + /// Tests whether the OS is WASI. + bool isOSWASI() const { + return getOS() == Triple::WASI; + } + + /// Tests whether the OS is Emscripten. + bool isOSEmscripten() const { + return getOS() == Triple::Emscripten; + } + + /// Tests whether the OS uses glibc. + bool isOSGlibc() const { + return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD || + getOS() == Triple::Hurd) && + !isAndroid(); + } + + /// Tests whether the OS is AIX. + bool isOSAIX() const { + return getOS() == Triple::AIX; + } + + /// Tests whether the OS uses the ELF binary format. + bool isOSBinFormatELF() const { + return getObjectFormat() == Triple::ELF; + } + + /// Tests whether the OS uses the COFF binary format. + bool isOSBinFormatCOFF() const { + return getObjectFormat() == Triple::COFF; + } + + /// Tests whether the environment is MachO. + bool isOSBinFormatMachO() const { + return getObjectFormat() == Triple::MachO; + } + + /// Tests whether the OS uses the Wasm binary format. + bool isOSBinFormatWasm() const { + return getObjectFormat() == Triple::Wasm; + } + + /// Tests whether the OS uses the XCOFF binary format. + bool isOSBinFormatXCOFF() const { + return getObjectFormat() == Triple::XCOFF; + } + + /// Tests whether the target is the PS4 CPU + bool isPS4CPU() const { + return getArch() == Triple::x86_64 && + getVendor() == Triple::SCEI && + getOS() == Triple::PS4; + } + + /// Tests whether the target is the PS4 platform + bool isPS4() const { + return getVendor() == Triple::SCEI && + getOS() == Triple::PS4; + } + + /// 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 || + getEnvironment() == Triple::MuslEABI || + getEnvironment() == Triple::MuslEABIHF; + } + + /// Tests whether the target is SPIR (32- or 64-bit). + bool isSPIR() const { + return getArch() == Triple::spir || getArch() == Triple::spir64; + } + + /// Tests whether the target is NVPTX (32- or 64-bit). + bool isNVPTX() const { + return getArch() == Triple::nvptx || getArch() == Triple::nvptx64; + } + + /// Tests whether the target is Thumb (little and big endian). + bool isThumb() const { + return getArch() == Triple::thumb || getArch() == Triple::thumbeb; + } + + /// Tests whether the target is ARM (little and big endian). + bool isARM() const { + return getArch() == Triple::arm || getArch() == Triple::armeb; + } + + /// Tests whether the target is AArch64 (little and big endian). + bool isAArch64() const { + return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be; + } + + /// Tests whether the target is MIPS 32-bit (little and big endian). + bool isMIPS32() const { + return getArch() == Triple::mips || getArch() == Triple::mipsel; + } + + /// Tests whether the target is MIPS 64-bit (little and big endian). + bool isMIPS64() const { + return getArch() == Triple::mips64 || getArch() == Triple::mips64el; + } + + /// Tests whether the target is MIPS (little and big endian, 32- or 64-bit). + bool isMIPS() const { + return isMIPS32() || isMIPS64(); + } + + /// Tests whether the target is 64-bit PowerPC (little and big endian). + bool isPPC64() const { + return getArch() == Triple::ppc64 || getArch() == Triple::ppc64le; + } + + /// Tests whether the target is RISC-V (32- and 64-bit). + bool isRISCV() const { + return getArch() == Triple::riscv32 || getArch() == Triple::riscv64; + } + + /// Tests whether the target supports comdat + bool supportsCOMDAT() const { + return !isOSBinFormatMachO(); + } + + /// Tests whether the target uses emulated TLS as default. + bool hasDefaultEmulatedTLS() const { + return isAndroid() || isOSOpenBSD() || isWindowsCygwinEnvironment(); + } + + /// @} + /// @name Mutators + /// @{ + + /// setArch - Set the architecture (first) component of the triple + /// to a known type. + void setArch(ArchType Kind); + + /// setVendor - Set the vendor (second) component of the triple to a + /// known type. + void setVendor(VendorType Kind); + + /// setOS - Set the operating system (third) component of the triple + /// to a known type. + void setOS(OSType Kind); + + /// setEnvironment - Set the environment (fourth) component of the triple + /// to a known type. + void setEnvironment(EnvironmentType Kind); + + /// setObjectFormat - Set the object file format + void setObjectFormat(ObjectFormatType Kind); + + /// setTriple - Set all components to the new triple \p Str. + void setTriple(const Twine &Str); + + /// setArchName - Set the architecture (first) component of the + /// triple by name. + void setArchName(StringRef Str); + + /// setVendorName - Set the vendor (second) component of the triple + /// by name. + void setVendorName(StringRef Str); + + /// setOSName - Set the operating system (third) component of the + /// triple by name. + void setOSName(StringRef Str); + + /// setEnvironmentName - Set the optional environment (fourth) + /// component of the triple by name. + void setEnvironmentName(StringRef Str); + + /// setOSAndEnvironmentName - Set the operating system and optional + /// environment components with a single string. + void setOSAndEnvironmentName(StringRef Str); + + /// @} + /// @name Helpers to build variants of a particular triple. + /// @{ + + /// Form a triple with a 32-bit variant of the current architecture. + /// + /// This can be used to move across "families" of architectures where useful. + /// + /// \returns A new triple with a 32-bit architecture or an unknown + /// architecture if no such variant can be found. + llvm::Triple get32BitArchVariant() const; + + /// Form a triple with a 64-bit variant of the current architecture. + /// + /// This can be used to move across "families" of architectures where useful. + /// + /// \returns A new triple with a 64-bit architecture or an unknown + /// architecture if no such variant can be found. + llvm::Triple get64BitArchVariant() const; + + /// Form a triple with a big endian variant of the current architecture. + /// + /// This can be used to move across "families" of architectures where useful. + /// + /// \returns A new triple with a big endian architecture or an unknown + /// architecture if no such variant can be found. + llvm::Triple getBigEndianArchVariant() const; + + /// Form a triple with a little endian variant of the current architecture. + /// + /// This can be used to move across "families" of architectures where useful. + /// + /// \returns A new triple with a little endian architecture or an unknown + /// architecture if no such variant can be found. + llvm::Triple getLittleEndianArchVariant() const; + + /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. + /// + /// \param Arch the architecture name (e.g., "armv7s"). If it is an empty + /// string then the triple's arch name is used. + StringRef getARMCPUForArch(StringRef Arch = StringRef()) const; + + /// Tests whether the target triple is little endian. + /// + /// \returns true if the triple is little endian, false otherwise. + bool isLittleEndian() const; + + /// Test whether target triples are compatible. + bool isCompatibleWith(const Triple &Other) const; + + /// Merge target triples. + std::string merge(const Triple &Other) const; + + /// @} + /// @name Static helpers for IDs. + /// @{ + + /// getArchTypeName - Get the canonical name for the \p Kind architecture. + static StringRef getArchTypeName(ArchType Kind); + + /// getArchTypePrefix - Get the "prefix" canonical name for the \p Kind + /// architecture. This is the prefix used by the architecture specific + /// builtins, and is suitable for passing to \see + /// Intrinsic::getIntrinsicForGCCBuiltin(). + /// + /// \return - The architecture prefix, or 0 if none is defined. + static StringRef getArchTypePrefix(ArchType Kind); + + /// getVendorTypeName - Get the canonical name for the \p Kind vendor. + static StringRef getVendorTypeName(VendorType Kind); + + /// getOSTypeName - Get the canonical name for the \p Kind operating system. + static StringRef getOSTypeName(OSType Kind); + + /// getEnvironmentTypeName - Get the canonical name for the \p Kind + /// environment. + static StringRef getEnvironmentTypeName(EnvironmentType Kind); + + /// @} + /// @name Static helpers for converting alternate architecture names. + /// @{ + + /// getArchTypeForLLVMName - The canonical type for the given LLVM + /// architecture name (e.g., "x86"). + static ArchType getArchTypeForLLVMName(StringRef Str); + + /// @} +}; + +} // End llvm namespace + + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/Twine.h b/third_party/llvm-project/include/llvm/ADT/Twine.h new file mode 100644 index 000000000..2dc7486c9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/Twine.h @@ -0,0 +1,544 @@ +//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_TWINE_H +#define LLVM_ADT_TWINE_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstdint> +#include <string> + +namespace llvm { + + class formatv_object_base; + class raw_ostream; + + /// Twine - A lightweight data structure for efficiently representing the + /// concatenation of temporary values as strings. + /// + /// A Twine is a kind of rope, it represents a concatenated string using a + /// binary-tree, where the string is the preorder of the nodes. Since the + /// Twine can be efficiently rendered into a buffer when its result is used, + /// it avoids the cost of generating temporary values for intermediate string + /// results -- particularly in cases when the Twine result is never + /// required. By explicitly tracking the type of leaf nodes, we can also avoid + /// the creation of temporary strings for conversions operations (such as + /// appending an integer to a string). + /// + /// A Twine is not intended for use directly and should not be stored, its + /// implementation relies on the ability to store pointers to temporary stack + /// objects which may be deallocated at the end of a statement. Twines should + /// only be used accepted as const references in arguments, when an API wishes + /// to accept possibly-concatenated strings. + /// + /// Twines support a special 'null' value, which always concatenates to form + /// itself, and renders as an empty string. This can be returned from APIs to + /// effectively nullify any concatenations performed on the result. + /// + /// \b Implementation + /// + /// Given the nature of a Twine, it is not possible for the Twine's + /// concatenation method to construct interior nodes; the result must be + /// represented inside the returned value. For this reason a Twine object + /// actually holds two values, the left- and right-hand sides of a + /// concatenation. We also have nullary Twine objects, which are effectively + /// sentinel values that represent empty strings. + /// + /// Thus, a Twine can effectively have zero, one, or two children. The \see + /// isNullary(), \see isUnary(), and \see isBinary() predicates exist for + /// testing the number of children. + /// + /// We maintain a number of invariants on Twine objects (FIXME: Why): + /// - Nullary twines are always represented with their Kind on the left-hand + /// side, and the Empty kind on the right-hand side. + /// - Unary twines are always represented with the value on the left-hand + /// side, and the Empty kind on the right-hand side. + /// - If a Twine has another Twine as a child, that child should always be + /// binary (otherwise it could have been folded into the parent). + /// + /// These invariants are check by \see isValid(). + /// + /// \b Efficiency Considerations + /// + /// The Twine is designed to yield efficient and small code for common + /// situations. For this reason, the concat() method is inlined so that + /// concatenations of leaf nodes can be optimized into stores directly into a + /// single stack allocated object. + /// + /// In practice, not all compilers can be trusted to optimize concat() fully, + /// so we provide two additional methods (and accompanying operator+ + /// overloads) to guarantee that particularly important cases (cstring plus + /// StringRef) codegen as desired. + class Twine { + /// NodeKind - Represent the type of an argument. + enum NodeKind : unsigned char { + /// An empty string; the result of concatenating anything with it is also + /// empty. + NullKind, + + /// The empty string. + EmptyKind, + + /// A pointer to a Twine instance. + TwineKind, + + /// A pointer to a C string instance. + CStringKind, + + /// A pointer to an std::string instance. + StdStringKind, + + /// A pointer to a StringRef instance. + StringRefKind, + + /// A pointer to a SmallString instance. + SmallStringKind, + + /// A pointer to a formatv_object_base instance. + FormatvObjectKind, + + /// A char value, to render as a character. + CharKind, + + /// An unsigned int value, to render as an unsigned decimal integer. + DecUIKind, + + /// An int value, to render as a signed decimal integer. + DecIKind, + + /// A pointer to an unsigned long value, to render as an unsigned decimal + /// integer. + DecULKind, + + /// A pointer to a long value, to render as a signed decimal integer. + DecLKind, + + /// A pointer to an unsigned long long value, to render as an unsigned + /// decimal integer. + DecULLKind, + + /// A pointer to a long long value, to render as a signed decimal integer. + DecLLKind, + + /// A pointer to a uint64_t value, to render as an unsigned hexadecimal + /// integer. + UHexKind + }; + + union Child + { + const Twine *twine; + const char *cString; + const std::string *stdString; + const StringRef *stringRef; + const SmallVectorImpl<char> *smallString; + const formatv_object_base *formatvObject; + char character; + unsigned int decUI; + int decI; + const unsigned long *decUL; + const long *decL; + const unsigned long long *decULL; + const long long *decLL; + const uint64_t *uHex; + }; + + /// LHS - The prefix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child LHS = {0}; + + /// RHS - The suffix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child RHS = {0}; + + /// LHSKind - The NodeKind of the left hand side, \see getLHSKind(). + NodeKind LHSKind = EmptyKind; + + /// RHSKind - The NodeKind of the right hand side, \see getRHSKind(). + NodeKind RHSKind = EmptyKind; + + /// Construct a nullary twine; the kind must be NullKind or EmptyKind. + explicit Twine(NodeKind Kind) : LHSKind(Kind) { + assert(isNullary() && "Invalid kind!"); + } + + /// Construct a binary twine. + explicit Twine(const Twine &LHS, const Twine &RHS) + : LHSKind(TwineKind), RHSKind(TwineKind) { + this->LHS.twine = &LHS; + this->RHS.twine = &RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Construct a twine from explicit values. + explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind) + : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) { + assert(isValid() && "Invalid twine!"); + } + + /// Check for the null twine. + bool isNull() const { + return getLHSKind() == NullKind; + } + + /// Check for the empty twine. + bool isEmpty() const { + return getLHSKind() == EmptyKind; + } + + /// Check if this is a nullary twine (null or empty). + bool isNullary() const { + return isNull() || isEmpty(); + } + + /// Check if this is a unary twine. + bool isUnary() const { + return getRHSKind() == EmptyKind && !isNullary(); + } + + /// Check if this is a binary twine. + bool isBinary() const { + return getLHSKind() != NullKind && getRHSKind() != EmptyKind; + } + + /// Check if this is a valid twine (satisfying the invariants on + /// order and number of arguments). + bool isValid() const { + // Nullary twines always have Empty on the RHS. + if (isNullary() && getRHSKind() != EmptyKind) + return false; + + // Null should never appear on the RHS. + if (getRHSKind() == NullKind) + return false; + + // The RHS cannot be non-empty if the LHS is empty. + if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind) + return false; + + // A twine child should always be binary. + if (getLHSKind() == TwineKind && + !LHS.twine->isBinary()) + return false; + if (getRHSKind() == TwineKind && + !RHS.twine->isBinary()) + return false; + + return true; + } + + /// Get the NodeKind of the left-hand side. + NodeKind getLHSKind() const { return LHSKind; } + + /// Get the NodeKind of the right-hand side. + NodeKind getRHSKind() const { return RHSKind; } + + /// Print one child from a twine. + void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const; + + /// Print the representation of one child from a twine. + void printOneChildRepr(raw_ostream &OS, Child Ptr, + NodeKind Kind) const; + + public: + /// @name Constructors + /// @{ + + /// Construct from an empty string. + /*implicit*/ Twine() { + assert(isValid() && "Invalid twine!"); + } + + Twine(const Twine &) = default; + + /// Construct from a C string. + /// + /// We take care here to optimize "" into the empty twine -- this will be + /// optimized out for string constants. This allows Twine arguments have + /// default "" values, without introducing unnecessary string constants. + /*implicit*/ Twine(const char *Str) { + if (Str[0] != '\0') { + LHS.cString = Str; + LHSKind = CStringKind; + } else + LHSKind = EmptyKind; + + assert(isValid() && "Invalid twine!"); + } + /// Delete the implicit conversion from nullptr as Twine(const char *) + /// cannot take nullptr. + /*implicit*/ Twine(std::nullptr_t) = delete; + + /// Construct from an std::string. + /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) { + LHS.stdString = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a StringRef. + /*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) { + LHS.stringRef = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a SmallString. + /*implicit*/ Twine(const SmallVectorImpl<char> &Str) + : LHSKind(SmallStringKind) { + LHS.smallString = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a formatv_object_base. + /*implicit*/ Twine(const formatv_object_base &Fmt) + : LHSKind(FormatvObjectKind) { + LHS.formatvObject = &Fmt; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a char. + explicit Twine(char Val) : LHSKind(CharKind) { + LHS.character = Val; + } + + /// Construct from a signed char. + explicit Twine(signed char Val) : LHSKind(CharKind) { + LHS.character = static_cast<char>(Val); + } + + /// Construct from an unsigned char. + explicit Twine(unsigned char Val) : LHSKind(CharKind) { + LHS.character = static_cast<char>(Val); + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(unsigned Val) : LHSKind(DecUIKind) { + LHS.decUI = Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(int Val) : LHSKind(DecIKind) { + LHS.decI = Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) { + LHS.decUL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long &Val) : LHSKind(DecLKind) { + LHS.decL = &Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) { + LHS.decULL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long long &Val) : LHSKind(DecLLKind) { + LHS.decLL = &Val; + } + + // FIXME: Unfortunately, to make sure this is as efficient as possible we + // need extra binary constructors from particular types. We can't rely on + // the compiler to be smart enough to fold operator+()/concat() down to the + // right thing. Yet. + + /// Construct as the concatenation of a C string and a StringRef. + /*implicit*/ Twine(const char *LHS, const StringRef &RHS) + : LHSKind(CStringKind), RHSKind(StringRefKind) { + this->LHS.cString = LHS; + this->RHS.stringRef = &RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Construct as the concatenation of a StringRef and a C string. + /*implicit*/ Twine(const StringRef &LHS, const char *RHS) + : LHSKind(StringRefKind), RHSKind(CStringKind) { + this->LHS.stringRef = &LHS; + this->RHS.cString = RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Since the intended use of twines is as temporary objects, assignments + /// when concatenating might cause undefined behavior or stack corruptions + Twine &operator=(const Twine &) = delete; + + /// Create a 'null' string, which is an empty string that always + /// concatenates to form another empty string. + static Twine createNull() { + return Twine(NullKind); + } + + /// @} + /// @name Numeric Conversions + /// @{ + + // Construct a twine to print \p Val as an unsigned hexadecimal integer. + static Twine utohexstr(const uint64_t &Val) { + Child LHS, RHS; + LHS.uHex = &Val; + RHS.twine = nullptr; + return Twine(LHS, UHexKind, RHS, EmptyKind); + } + + /// @} + /// @name Predicate Operations + /// @{ + + /// Check if this twine is trivially empty; a false return value does not + /// necessarily mean the twine is empty. + bool isTriviallyEmpty() const { + return isNullary(); + } + + /// Return true if this twine can be dynamically accessed as a single + /// StringRef value with getSingleStringRef(). + bool isSingleStringRef() const { + if (getRHSKind() != EmptyKind) return false; + + switch (getLHSKind()) { + case EmptyKind: + case CStringKind: + case StdStringKind: + case StringRefKind: + case SmallStringKind: + return true; + default: + return false; + } + } + + /// @} + /// @name String Operations + /// @{ + + Twine concat(const Twine &Suffix) const; + + /// @} + /// @name Output & Conversion. + /// @{ + + /// Return the twine contents as a std::string. + std::string str() const; + + /// Append the concatenated string into the given SmallString or SmallVector. + void toVector(SmallVectorImpl<char> &Out) const; + + /// This returns the twine as a single StringRef. This method is only valid + /// if isSingleStringRef() is true. + StringRef getSingleStringRef() const { + assert(isSingleStringRef() &&"This cannot be had as a single stringref!"); + switch (getLHSKind()) { + default: llvm_unreachable("Out of sync with isSingleStringRef"); + case EmptyKind: return StringRef(); + case CStringKind: return StringRef(LHS.cString); + case StdStringKind: return StringRef(*LHS.stdString); + case StringRefKind: return *LHS.stringRef; + case SmallStringKind: + return StringRef(LHS.smallString->data(), LHS.smallString->size()); + } + } + + /// This returns the twine as a single StringRef if it can be + /// represented as such. Otherwise the twine is written into the given + /// SmallVector and a StringRef to the SmallVector's data is returned. + StringRef toStringRef(SmallVectorImpl<char> &Out) const { + if (isSingleStringRef()) + return getSingleStringRef(); + toVector(Out); + return StringRef(Out.data(), Out.size()); + } + + /// This returns the twine as a single null terminated StringRef if it + /// can be represented as such. Otherwise the twine is written into the + /// given SmallVector and a StringRef to the SmallVector's data is returned. + /// + /// The returned StringRef's size does not include the null terminator. + StringRef toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const; + + /// Write the concatenated string represented by this twine to the + /// stream \p OS. + void print(raw_ostream &OS) const; + + /// Dump the concatenated string represented by this twine to stderr. + void dump() const; + + /// Write the representation of this twine to the stream \p OS. + void printRepr(raw_ostream &OS) const; + + /// Dump the representation of this twine to stderr. + void dumpRepr() const; + + /// @} + }; + + /// @name Twine Inline Implementations + /// @{ + + inline Twine Twine::concat(const Twine &Suffix) const { + // Concatenation with null is null. + if (isNull() || Suffix.isNull()) + return Twine(NullKind); + + // Concatenation with empty yields the other side. + if (isEmpty()) + return Suffix; + if (Suffix.isEmpty()) + return *this; + + // Otherwise we need to create a new node, taking care to fold in unary + // twines. + Child NewLHS, NewRHS; + NewLHS.twine = this; + NewRHS.twine = &Suffix; + NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind; + if (isUnary()) { + NewLHS = LHS; + NewLHSKind = getLHSKind(); + } + if (Suffix.isUnary()) { + NewRHS = Suffix.LHS; + NewRHSKind = Suffix.getLHSKind(); + } + + return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind); + } + + inline Twine operator+(const Twine &LHS, const Twine &RHS) { + return LHS.concat(RHS); + } + + /// Additional overload to guarantee simplified codegen; this is equivalent to + /// concat(). + + inline Twine operator+(const char *LHS, const StringRef &RHS) { + return Twine(LHS, RHS); + } + + /// Additional overload to guarantee simplified codegen; this is equivalent to + /// concat(). + + inline Twine operator+(const StringRef &LHS, const char *RHS) { + return Twine(LHS, RHS); + } + + inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) { + RHS.print(OS); + return OS; + } + + /// @} + +} // end namespace llvm + +#endif // LLVM_ADT_TWINE_H diff --git a/third_party/llvm-project/include/llvm/ADT/bit.h b/third_party/llvm-project/include/llvm/ADT/bit.h new file mode 100644 index 000000000..a790d5ed2 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/bit.h @@ -0,0 +1,58 @@ +//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the C++20 <bit> header. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BIT_H +#define LLVM_ADT_BIT_H + +#include "llvm/Support/Compiler.h" +#include <cstring> +#include <type_traits> + +namespace llvm { + +// This implementation of bit_cast is different from the C++17 one in two ways: +// - It isn't constexpr because that requires compiler support. +// - It requires trivially-constructible To, to avoid UB in the implementation. +template <typename To, typename From + , typename = typename std::enable_if<sizeof(To) == sizeof(From)>::type +#if (__has_feature(is_trivially_constructible) && defined(_LIBCPP_VERSION)) || \ + (defined(__GNUC__) && __GNUC__ >= 5) + , typename = typename std::is_trivially_constructible<To>::type +#elif __has_feature(is_trivially_constructible) + , typename = typename std::enable_if<__is_trivially_constructible(To)>::type +#else + // See comment below. +#endif +#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \ + (defined(__GNUC__) && __GNUC__ >= 5) + , typename = typename std::enable_if<std::is_trivially_copyable<To>::value>::type + , typename = typename std::enable_if<std::is_trivially_copyable<From>::value>::type +#elif __has_feature(is_trivially_copyable) + , typename = typename std::enable_if<__is_trivially_copyable(To)>::type + , typename = typename std::enable_if<__is_trivially_copyable(From)>::type +#else +// This case is GCC 4.x. clang with libc++ or libstdc++ never get here. Unlike +// llvm/Support/type_traits.h's is_trivially_copyable we don't want to +// provide a good-enough answer here: developers in that configuration will hit +// compilation failures on the bots instead of locally. That's acceptable +// because it's very few developers, and only until we move past C++11. +#endif +> +inline To bit_cast(const From &from) noexcept { + To to; + std::memcpy(&to, &from, sizeof(To)); + return to; +} + +} // namespace llvm + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/edit_distance.h b/third_party/llvm-project/include/llvm/ADT/edit_distance.h new file mode 100644 index 000000000..4f5134008 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/edit_distance.h @@ -0,0 +1,102 @@ +//===-- llvm/ADT/edit_distance.h - Array edit distance function --- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a Levenshtein distance function that works for any two +// sequences, with each element of each sequence being analogous to a character +// in a string. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_EDIT_DISTANCE_H +#define LLVM_ADT_EDIT_DISTANCE_H + +#include "llvm/ADT/ArrayRef.h" +#include <algorithm> +#include <memory> + +namespace llvm { + +/// Determine the edit distance between two sequences. +/// +/// \param FromArray the first sequence to compare. +/// +/// \param ToArray the second sequence to compare. +/// +/// \param AllowReplacements whether to allow element replacements (change one +/// element into another) as a single operation, rather than as two operations +/// (an insertion and a removal). +/// +/// \param MaxEditDistance If non-zero, the maximum edit distance that this +/// routine is allowed to compute. If the edit distance will exceed that +/// maximum, returns \c MaxEditDistance+1. +/// +/// \returns the minimum number of element insertions, removals, or (if +/// \p AllowReplacements is \c true) replacements needed to transform one of +/// the given sequences into the other. If zero, the sequences are identical. +template<typename T> +unsigned ComputeEditDistance(ArrayRef<T> FromArray, ArrayRef<T> ToArray, + bool AllowReplacements = true, + unsigned MaxEditDistance = 0) { + // The algorithm implemented below is the "classic" + // dynamic-programming algorithm for computing the Levenshtein + // distance, which is described here: + // + // http://en.wikipedia.org/wiki/Levenshtein_distance + // + // Although the algorithm is typically described using an m x n + // array, only one row plus one element are used at a time, so this + // implementation just keeps one vector for the row. To update one entry, + // only the entries to the left, top, and top-left are needed. The left + // entry is in Row[x-1], the top entry is what's in Row[x] from the last + // iteration, and the top-left entry is stored in Previous. + typename ArrayRef<T>::size_type m = FromArray.size(); + typename ArrayRef<T>::size_type n = ToArray.size(); + + const unsigned SmallBufferSize = 64; + unsigned SmallBuffer[SmallBufferSize]; + std::unique_ptr<unsigned[]> Allocated; + unsigned *Row = SmallBuffer; + if (n + 1 > SmallBufferSize) { + Row = new unsigned[n + 1]; + Allocated.reset(Row); + } + + for (unsigned i = 1; i <= n; ++i) + Row[i] = i; + + for (typename ArrayRef<T>::size_type y = 1; y <= m; ++y) { + Row[0] = y; + unsigned BestThisRow = Row[0]; + + unsigned Previous = y - 1; + for (typename ArrayRef<T>::size_type x = 1; x <= n; ++x) { + int OldRow = Row[x]; + if (AllowReplacements) { + Row[x] = std::min( + Previous + (FromArray[y-1] == ToArray[x-1] ? 0u : 1u), + std::min(Row[x-1], Row[x])+1); + } + else { + if (FromArray[y-1] == ToArray[x-1]) Row[x] = Previous; + else Row[x] = std::min(Row[x-1], Row[x]) + 1; + } + Previous = OldRow; + BestThisRow = std::min(BestThisRow, Row[x]); + } + + if (MaxEditDistance && BestThisRow > MaxEditDistance) + return MaxEditDistance + 1; + } + + unsigned Result = Row[n]; + return Result; +} + +} // End llvm namespace + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h b/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h new file mode 100644 index 000000000..6501ad223 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h @@ -0,0 +1,243 @@ +//===--- fallible_iterator.h - Wrapper for fallible iterators ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_FALLIBLE_ITERATOR_H +#define LLVM_ADT_FALLIBLE_ITERATOR_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Error.h" + +#include <type_traits> + +namespace llvm { + +/// A wrapper class for fallible iterators. +/// +/// The fallible_iterator template wraps an underlying iterator-like class +/// whose increment and decrement operations are replaced with fallible versions +/// like: +/// +/// @code{.cpp} +/// Error inc(); +/// Error dec(); +/// @endcode +/// +/// It produces an interface that is (mostly) compatible with a traditional +/// c++ iterator, including ++ and -- operators that do not fail. +/// +/// Instances of the wrapper are constructed with an instance of the +/// underlying iterator and (for non-end iterators) a reference to an Error +/// instance. If the underlying increment/decrement operations fail, the Error +/// is returned via this reference, and the resulting iterator value set to an +/// end-of-range sentinel value. This enables the following loop idiom: +/// +/// @code{.cpp} +/// class Archive { // E.g. Potentially malformed on-disk archive +/// public: +/// fallible_iterator<ArchiveChildItr> children_begin(Error &Err); +/// fallible_iterator<ArchiveChildItr> children_end(); +/// iterator_range<fallible_iterator<ArchiveChildItr>> +/// children(Error &Err) { +/// return make_range(children_begin(Err), children_end()); +/// //... +/// }; +/// +/// void walk(Archive &A) { +/// Error Err = Error::success(); +/// for (auto &C : A.children(Err)) { +/// // Loop body only entered when increment succeeds. +/// } +/// if (Err) { +/// // handle error. +/// } +/// } +/// @endcode +/// +/// The wrapper marks the referenced Error as unchecked after each increment +/// and/or decrement operation, and clears the unchecked flag when a non-end +/// value is compared against end (since, by the increment invariant, not being +/// an end value proves that there was no error, and is equivalent to checking +/// that the Error is success). This allows early exits from the loop body +/// without requiring redundant error checks. +template <typename Underlying> class fallible_iterator { +private: + template <typename T> + using enable_if_struct_deref_supported = std::enable_if< + !std::is_void<decltype(std::declval<T>().operator->())>::value, + decltype(std::declval<T>().operator->())>; + +public: + /// Construct a fallible iterator that *cannot* be used as an end-of-range + /// value. + /// + /// A value created by this method can be dereferenced, incremented, + /// decremented and compared, providing the underlying type supports it. + /// + /// The error that is passed in will be initially marked as checked, so if the + /// iterator is not used at all the Error need not be checked. + static fallible_iterator itr(Underlying I, Error &Err) { + (void)!!Err; + return fallible_iterator(std::move(I), &Err); + } + + /// Construct a fallible iteratro that can be used as an end-of-range value. + /// + /// A value created by this method can be dereferenced (if the underlying + /// value points at a valid value) and compared, but not incremented or + /// decremented. + static fallible_iterator end(Underlying I) { + return fallible_iterator(std::move(I), nullptr); + } + + /// Forward dereference to the underlying iterator. + auto operator*() -> decltype(*std::declval<Underlying>()) { return *I; } + + /// Forward const dereference to the underlying iterator. + auto operator*() const -> decltype(*std::declval<const Underlying>()) { + return *I; + } + + /// Forward structure dereference to the underlying iterator (if the + /// underlying iterator supports it). + template <typename T = Underlying> + typename enable_if_struct_deref_supported<T>::type operator->() { + return I.operator->(); + } + + /// Forward const structure dereference to the underlying iterator (if the + /// underlying iterator supports it). + template <typename T = Underlying> + typename enable_if_struct_deref_supported<const T>::type operator->() const { + return I.operator->(); + } + + /// Increment the fallible iterator. + /// + /// If the underlying 'inc' operation fails, this will set the Error value + /// and update this iterator value to point to end-of-range. + /// + /// The Error value is marked as needing checking, regardless of whether the + /// 'inc' operation succeeds or fails. + fallible_iterator &operator++() { + assert(getErrPtr() && "Cannot increment end iterator"); + if (auto Err = I.inc()) + handleError(std::move(Err)); + else + resetCheckedFlag(); + return *this; + } + + /// Decrement the fallible iterator. + /// + /// If the underlying 'dec' operation fails, this will set the Error value + /// and update this iterator value to point to end-of-range. + /// + /// The Error value is marked as needing checking, regardless of whether the + /// 'dec' operation succeeds or fails. + fallible_iterator &operator--() { + assert(getErrPtr() && "Cannot decrement end iterator"); + if (auto Err = I.dec()) + handleError(std::move(Err)); + else + resetCheckedFlag(); + return *this; + } + + /// Compare fallible iterators for equality. + /// + /// Returns true if both LHS and RHS are end-of-range values, or if both are + /// non-end-of-range values whose underlying iterator values compare equal. + /// + /// If this is a comparison between an end-of-range iterator and a + /// non-end-of-range iterator, then the Error (referenced by the + /// non-end-of-range value) is marked as checked: Since all + /// increment/decrement operations result in an end-of-range value, comparing + /// false against end-of-range is equivalent to checking that the Error value + /// is success. This flag management enables early returns from loop bodies + /// without redundant Error checks. + friend bool operator==(const fallible_iterator &LHS, + const fallible_iterator &RHS) { + // If both iterators are in the end state they compare + // equal, regardless of whether either is valid. + if (LHS.isEnd() && RHS.isEnd()) + return true; + + assert(LHS.isValid() && RHS.isValid() && + "Invalid iterators can only be compared against end"); + + bool Equal = LHS.I == RHS.I; + + // If the iterators differ and this is a comparison against end then mark + // the Error as checked. + if (!Equal) { + if (LHS.isEnd()) + (void)!!*RHS.getErrPtr(); + else + (void)!!*LHS.getErrPtr(); + } + + return Equal; + } + + /// Compare fallible iterators for inequality. + /// + /// See notes for operator==. + friend bool operator!=(const fallible_iterator &LHS, + const fallible_iterator &RHS) { + return !(LHS == RHS); + } + +private: + fallible_iterator(Underlying I, Error *Err) + : I(std::move(I)), ErrState(Err, false) {} + + Error *getErrPtr() const { return ErrState.getPointer(); } + + bool isEnd() const { return getErrPtr() == nullptr; } + + bool isValid() const { return !ErrState.getInt(); } + + void handleError(Error Err) { + *getErrPtr() = std::move(Err); + ErrState.setPointer(nullptr); + ErrState.setInt(true); + } + + void resetCheckedFlag() { + *getErrPtr() = Error::success(); + } + + Underlying I; + mutable PointerIntPair<Error *, 1> ErrState; +}; + +/// Convenience wrapper to make a fallible_iterator value from an instance +/// of an underlying iterator and an Error reference. +template <typename Underlying> +fallible_iterator<Underlying> make_fallible_itr(Underlying I, Error &Err) { + return fallible_iterator<Underlying>::itr(std::move(I), Err); +} + +/// Convenience wrapper to make a fallible_iterator end value from an instance +/// of an underlying iterator. +template <typename Underlying> +fallible_iterator<Underlying> make_fallible_end(Underlying E) { + return fallible_iterator<Underlying>::end(std::move(E)); +} + +template <typename Underlying> +iterator_range<fallible_iterator<Underlying>> +make_fallible_range(Underlying I, Underlying E, Error &Err) { + return make_range(make_fallible_itr(std::move(I), Err), + make_fallible_end(std::move(E))); +} + +} // end namespace llvm + +#endif // LLVM_ADT_FALLIBLE_ITERATOR_H diff --git a/third_party/llvm-project/include/llvm/ADT/ilist_base.h b/third_party/llvm-project/include/llvm/ADT/ilist_base.h new file mode 100644 index 000000000..b8c098b95 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ilist_base.h @@ -0,0 +1,92 @@ +//===- llvm/ADT/ilist_base.h - Intrusive List Base --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ILIST_BASE_H +#define LLVM_ADT_ILIST_BASE_H + +#include "llvm/ADT/ilist_node_base.h" +#include <cassert> + +namespace llvm { + +/// Implementations of list algorithms using ilist_node_base. +template <bool EnableSentinelTracking> class ilist_base { +public: + using node_base_type = ilist_node_base<EnableSentinelTracking>; + + static void insertBeforeImpl(node_base_type &Next, node_base_type &N) { + node_base_type &Prev = *Next.getPrev(); + N.setNext(&Next); + N.setPrev(&Prev); + Prev.setNext(&N); + Next.setPrev(&N); + } + + static void removeImpl(node_base_type &N) { + node_base_type *Prev = N.getPrev(); + node_base_type *Next = N.getNext(); + Next->setPrev(Prev); + Prev->setNext(Next); + + // Not strictly necessary, but helps catch a class of bugs. + N.setPrev(nullptr); + N.setNext(nullptr); + } + + static void removeRangeImpl(node_base_type &First, node_base_type &Last) { + node_base_type *Prev = First.getPrev(); + node_base_type *Final = Last.getPrev(); + Last.setPrev(Prev); + Prev->setNext(&Last); + + // Not strictly necessary, but helps catch a class of bugs. + First.setPrev(nullptr); + Final->setNext(nullptr); + } + + static void transferBeforeImpl(node_base_type &Next, node_base_type &First, + node_base_type &Last) { + if (&Next == &Last || &First == &Last) + return; + + // Position cannot be contained in the range to be transferred. + assert(&Next != &First && + // Check for the most common mistake. + "Insertion point can't be one of the transferred nodes"); + + node_base_type &Final = *Last.getPrev(); + + // Detach from old list/position. + First.getPrev()->setNext(&Last); + Last.setPrev(First.getPrev()); + + // Splice [First, Final] into its new list/position. + node_base_type &Prev = *Next.getPrev(); + Final.setNext(&Next); + First.setPrev(&Prev); + Prev.setNext(&First); + Next.setPrev(&Final); + } + + template <class T> static void insertBefore(T &Next, T &N) { + insertBeforeImpl(Next, N); + } + + template <class T> static void remove(T &N) { removeImpl(N); } + template <class T> static void removeRange(T &First, T &Last) { + removeRangeImpl(First, Last); + } + + template <class T> static void transferBefore(T &Next, T &First, T &Last) { + transferBeforeImpl(Next, First, Last); + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_ILIST_BASE_H diff --git a/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h b/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h new file mode 100644 index 000000000..cbe5cefa9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h @@ -0,0 +1,198 @@ +//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ILIST_ITERATOR_H +#define LLVM_ADT_ILIST_ITERATOR_H + +#include "llvm/ADT/ilist_node.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <type_traits> + +namespace llvm { + +namespace ilist_detail { + +/// Find const-correct node types. +template <class OptionsT, bool IsConst> struct IteratorTraits; +template <class OptionsT> struct IteratorTraits<OptionsT, false> { + using value_type = typename OptionsT::value_type; + using pointer = typename OptionsT::pointer; + using reference = typename OptionsT::reference; + using node_pointer = ilist_node_impl<OptionsT> *; + using node_reference = ilist_node_impl<OptionsT> &; +}; +template <class OptionsT> struct IteratorTraits<OptionsT, true> { + using value_type = const typename OptionsT::value_type; + using pointer = typename OptionsT::const_pointer; + using reference = typename OptionsT::const_reference; + using node_pointer = const ilist_node_impl<OptionsT> *; + using node_reference = const ilist_node_impl<OptionsT> &; +}; + +template <bool IsReverse> struct IteratorHelper; +template <> struct IteratorHelper<false> : ilist_detail::NodeAccess { + using Access = ilist_detail::NodeAccess; + + template <class T> static void increment(T *&I) { I = Access::getNext(*I); } + template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); } +}; +template <> struct IteratorHelper<true> : ilist_detail::NodeAccess { + using Access = ilist_detail::NodeAccess; + + template <class T> static void increment(T *&I) { I = Access::getPrev(*I); } + template <class T> static void decrement(T *&I) { I = Access::getNext(*I); } +}; + +} // end namespace ilist_detail + +/// Iterator for intrusive lists based on ilist_node. +template <class OptionsT, bool IsReverse, bool IsConst> +class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> { + friend ilist_iterator<OptionsT, IsReverse, !IsConst>; + friend ilist_iterator<OptionsT, !IsReverse, IsConst>; + friend ilist_iterator<OptionsT, !IsReverse, !IsConst>; + + using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>; + using Access = ilist_detail::SpecificNodeAccess<OptionsT>; + +public: + using value_type = typename Traits::value_type; + using pointer = typename Traits::pointer; + using reference = typename Traits::reference; + using difference_type = ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + using const_pointer = typename OptionsT::const_pointer; + using const_reference = typename OptionsT::const_reference; + +private: + using node_pointer = typename Traits::node_pointer; + using node_reference = typename Traits::node_reference; + + node_pointer NodePtr = nullptr; + +public: + /// Create from an ilist_node. + explicit ilist_iterator(node_reference N) : NodePtr(&N) {} + + explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {} + explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {} + ilist_iterator() = default; + + // This is templated so that we can allow constructing a const iterator from + // a nonconst iterator... + template <bool RHSIsConst> + ilist_iterator( + const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS, + typename std::enable_if<IsConst || !RHSIsConst, void *>::type = nullptr) + : NodePtr(RHS.NodePtr) {} + + // This is templated so that we can allow assigning to a const iterator from + // a nonconst iterator... + template <bool RHSIsConst> + typename std::enable_if<IsConst || !RHSIsConst, ilist_iterator &>::type + operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) { + NodePtr = RHS.NodePtr; + return *this; + } + + /// Explicit conversion between forward/reverse iterators. + /// + /// Translate between forward and reverse iterators without changing range + /// boundaries. The resulting iterator will dereference (and have a handle) + /// to the previous node, which is somewhat unexpected; but converting the + /// two endpoints in a range will give the same range in reverse. + /// + /// This matches std::reverse_iterator conversions. + explicit ilist_iterator( + const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS) + : ilist_iterator(++RHS.getReverse()) {} + + /// Get a reverse iterator to the same node. + /// + /// Gives a reverse iterator that will dereference (and have a handle) to the + /// same node. Converting the endpoint iterators in a range will give a + /// different range; for range operations, use the explicit conversions. + ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const { + if (NodePtr) + return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr); + return ilist_iterator<OptionsT, !IsReverse, IsConst>(); + } + + /// Const-cast. + ilist_iterator<OptionsT, IsReverse, false> getNonConst() const { + if (NodePtr) + return ilist_iterator<OptionsT, IsReverse, false>( + const_cast<typename ilist_iterator<OptionsT, IsReverse, + false>::node_reference>(*NodePtr)); + return ilist_iterator<OptionsT, IsReverse, false>(); + } + + // Accessors... + reference operator*() const { + assert(!NodePtr->isKnownSentinel()); + return *Access::getValuePtr(NodePtr); + } + pointer operator->() const { return &operator*(); } + + // Comparison operators + friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) { + return LHS.NodePtr == RHS.NodePtr; + } + friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) { + return LHS.NodePtr != RHS.NodePtr; + } + + // Increment and decrement operators... + ilist_iterator &operator--() { + NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev(); + return *this; + } + ilist_iterator &operator++() { + NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext(); + return *this; + } + ilist_iterator operator--(int) { + ilist_iterator tmp = *this; + --*this; + return tmp; + } + ilist_iterator operator++(int) { + ilist_iterator tmp = *this; + ++*this; + return tmp; + } + + /// Get the underlying ilist_node. + node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); } + + /// Check for end. Only valid if ilist_sentinel_tracking<true>. + bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; } +}; + +template <typename From> struct simplify_type; + +/// Allow ilist_iterators to convert into pointers to a node automatically when +/// used by the dyn_cast, cast, isa mechanisms... +/// +/// FIXME: remove this, since there is no implicit conversion to NodeTy. +template <class OptionsT, bool IsConst> +struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> { + using iterator = ilist_iterator<OptionsT, false, IsConst>; + using SimpleType = typename iterator::pointer; + + static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; } +}; +template <class OptionsT, bool IsConst> +struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>> + : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {}; + +} // end namespace llvm + +#endif // LLVM_ADT_ILIST_ITERATOR_H diff --git a/third_party/llvm-project/include/llvm/ADT/ilist_node.h b/third_party/llvm-project/include/llvm/ADT/ilist_node.h new file mode 100644 index 000000000..e040d9630 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ilist_node.h @@ -0,0 +1,305 @@ +//===- llvm/ADT/ilist_node.h - Intrusive Linked List Helper -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ilist_node class template, which is a convenient +// base class for creating classes that can be used with ilists. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ILIST_NODE_H +#define LLVM_ADT_ILIST_NODE_H + +#include "llvm/ADT/ilist_node_base.h" +#include "llvm/ADT/ilist_node_options.h" + +namespace llvm { + +namespace ilist_detail { + +struct NodeAccess; + +} // end namespace ilist_detail + +template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator; +template <class OptionsT> class ilist_sentinel; + +/// Implementation for an ilist node. +/// +/// Templated on an appropriate \a ilist_detail::node_options, usually computed +/// by \a ilist_detail::compute_node_options. +/// +/// This is a wrapper around \a ilist_node_base whose main purpose is to +/// provide type safety: you can't insert nodes of \a ilist_node_impl into the +/// wrong \a simple_ilist or \a iplist. +template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type { + using value_type = typename OptionsT::value_type; + using node_base_type = typename OptionsT::node_base_type; + using list_base_type = typename OptionsT::list_base_type; + + friend typename OptionsT::list_base_type; + friend struct ilist_detail::NodeAccess; + friend class ilist_sentinel<OptionsT>; + friend class ilist_iterator<OptionsT, false, false>; + friend class ilist_iterator<OptionsT, false, true>; + friend class ilist_iterator<OptionsT, true, false>; + friend class ilist_iterator<OptionsT, true, true>; + +protected: + using self_iterator = ilist_iterator<OptionsT, false, false>; + using const_self_iterator = ilist_iterator<OptionsT, false, true>; + using reverse_self_iterator = ilist_iterator<OptionsT, true, false>; + using const_reverse_self_iterator = ilist_iterator<OptionsT, true, true>; + + ilist_node_impl() = default; + +private: + ilist_node_impl *getPrev() { + return static_cast<ilist_node_impl *>(node_base_type::getPrev()); + } + + ilist_node_impl *getNext() { + return static_cast<ilist_node_impl *>(node_base_type::getNext()); + } + + const ilist_node_impl *getPrev() const { + return static_cast<ilist_node_impl *>(node_base_type::getPrev()); + } + + const ilist_node_impl *getNext() const { + return static_cast<ilist_node_impl *>(node_base_type::getNext()); + } + + void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); } + void setNext(ilist_node_impl *N) { node_base_type::setNext(N); } + +public: + self_iterator getIterator() { return self_iterator(*this); } + const_self_iterator getIterator() const { return const_self_iterator(*this); } + + reverse_self_iterator getReverseIterator() { + return reverse_self_iterator(*this); + } + + const_reverse_self_iterator getReverseIterator() const { + return const_reverse_self_iterator(*this); + } + + // Under-approximation, but always available for assertions. + using node_base_type::isKnownSentinel; + + /// Check whether this is the sentinel node. + /// + /// This requires sentinel tracking to be explicitly enabled. Use the + /// ilist_sentinel_tracking<true> option to get this API. + bool isSentinel() const { + static_assert(OptionsT::is_sentinel_tracking_explicit, + "Use ilist_sentinel_tracking<true> to enable isSentinel()"); + return node_base_type::isSentinel(); + } +}; + +/// An intrusive list node. +/// +/// A base class to enable membership in intrusive lists, including \a +/// simple_ilist, \a iplist, and \a ilist. The first template parameter is the +/// \a value_type for the list. +/// +/// An ilist node can be configured with compile-time options to change +/// behaviour and/or add API. +/// +/// By default, an \a ilist_node knows whether it is the list sentinel (an +/// instance of \a ilist_sentinel) if and only if +/// LLVM_ENABLE_ABI_BREAKING_CHECKS. The function \a isKnownSentinel() always +/// returns \c false tracking is off. Sentinel tracking steals a bit from the +/// "prev" link, which adds a mask operation when decrementing an iterator, but +/// enables bug-finding assertions in \a ilist_iterator. +/// +/// To turn sentinel tracking on all the time, pass in the +/// ilist_sentinel_tracking<true> template parameter. This also enables the \a +/// isSentinel() function. The same option must be passed to the intrusive +/// list. (ilist_sentinel_tracking<false> turns sentinel tracking off all the +/// time.) +/// +/// A type can inherit from ilist_node multiple times by passing in different +/// \a ilist_tag options. This allows a single instance to be inserted into +/// multiple lists simultaneously, where each list is given the same tag. +/// +/// \example +/// struct A {}; +/// struct B {}; +/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {}; +/// +/// void foo() { +/// simple_ilist<N, ilist_tag<A>> ListA; +/// simple_ilist<N, ilist_tag<B>> ListB; +/// N N1; +/// ListA.push_back(N1); +/// ListB.push_back(N1); +/// } +/// \endexample +/// +/// See \a is_valid_option for steps on adding a new option. +template <class T, class... Options> +class ilist_node + : public ilist_node_impl< + typename ilist_detail::compute_node_options<T, Options...>::type> { + static_assert(ilist_detail::check_options<Options...>::value, + "Unrecognized node option!"); +}; + +namespace ilist_detail { + +/// An access class for ilist_node private API. +/// +/// This gives access to the private parts of ilist nodes. Nodes for an ilist +/// should friend this class if they inherit privately from ilist_node. +/// +/// Using this class outside of the ilist implementation is unsupported. +struct NodeAccess { +protected: + template <class OptionsT> + static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) { + return N; + } + + template <class OptionsT> + static const ilist_node_impl<OptionsT> * + getNodePtr(typename OptionsT::const_pointer N) { + return N; + } + + template <class OptionsT> + static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) { + return static_cast<typename OptionsT::pointer>(N); + } + + template <class OptionsT> + static typename OptionsT::const_pointer + getValuePtr(const ilist_node_impl<OptionsT> *N) { + return static_cast<typename OptionsT::const_pointer>(N); + } + + template <class OptionsT> + static ilist_node_impl<OptionsT> *getPrev(ilist_node_impl<OptionsT> &N) { + return N.getPrev(); + } + + template <class OptionsT> + static ilist_node_impl<OptionsT> *getNext(ilist_node_impl<OptionsT> &N) { + return N.getNext(); + } + + template <class OptionsT> + static const ilist_node_impl<OptionsT> * + getPrev(const ilist_node_impl<OptionsT> &N) { + return N.getPrev(); + } + + template <class OptionsT> + static const ilist_node_impl<OptionsT> * + getNext(const ilist_node_impl<OptionsT> &N) { + return N.getNext(); + } +}; + +template <class OptionsT> struct SpecificNodeAccess : NodeAccess { +protected: + using pointer = typename OptionsT::pointer; + using const_pointer = typename OptionsT::const_pointer; + using node_type = ilist_node_impl<OptionsT>; + + static node_type *getNodePtr(pointer N) { + return NodeAccess::getNodePtr<OptionsT>(N); + } + + static const node_type *getNodePtr(const_pointer N) { + return NodeAccess::getNodePtr<OptionsT>(N); + } + + static pointer getValuePtr(node_type *N) { + return NodeAccess::getValuePtr<OptionsT>(N); + } + + static const_pointer getValuePtr(const node_type *N) { + return NodeAccess::getValuePtr<OptionsT>(N); + } +}; + +} // end namespace ilist_detail + +template <class OptionsT> +class ilist_sentinel : public ilist_node_impl<OptionsT> { +public: + ilist_sentinel() { + this->initializeSentinel(); + reset(); + } + + void reset() { + this->setPrev(this); + this->setNext(this); + } + + bool empty() const { return this == this->getPrev(); } +}; + +/// An ilist node that can access its parent list. +/// +/// Requires \c NodeTy to have \a getParent() to find the parent node, and the +/// \c ParentTy to have \a getSublistAccess() to get a reference to the list. +template <typename NodeTy, typename ParentTy, class... Options> +class ilist_node_with_parent : public ilist_node<NodeTy, Options...> { +protected: + ilist_node_with_parent() = default; + +private: + /// Forward to NodeTy::getParent(). + /// + /// Note: do not use the name "getParent()". We want a compile error + /// (instead of recursion) when the subclass fails to implement \a + /// getParent(). + const ParentTy *getNodeParent() const { + return static_cast<const NodeTy *>(this)->getParent(); + } + +public: + /// @name Adjacent Node Accessors + /// @{ + /// Get the previous node, or \c nullptr for the list head. + NodeTy *getPrevNode() { + // Should be separated to a reused function, but then we couldn't use auto + // (and would need the type of the list). + const auto &List = + getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); + return List.getPrevNode(*static_cast<NodeTy *>(this)); + } + + /// Get the previous node, or \c nullptr for the list head. + const NodeTy *getPrevNode() const { + return const_cast<ilist_node_with_parent *>(this)->getPrevNode(); + } + + /// Get the next node, or \c nullptr for the list tail. + NodeTy *getNextNode() { + // Should be separated to a reused function, but then we couldn't use auto + // (and would need the type of the list). + const auto &List = + getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); + return List.getNextNode(*static_cast<NodeTy *>(this)); + } + + /// Get the next node, or \c nullptr for the list tail. + const NodeTy *getNextNode() const { + return const_cast<ilist_node_with_parent *>(this)->getNextNode(); + } + /// @} +}; + +} // end namespace llvm + +#endif // LLVM_ADT_ILIST_NODE_H diff --git a/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h b/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h new file mode 100644 index 000000000..f6c518e6e --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h @@ -0,0 +1,52 @@ +//===- llvm/ADT/ilist_node_base.h - Intrusive List Node Base -----*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ILIST_NODE_BASE_H +#define LLVM_ADT_ILIST_NODE_BASE_H + +#include "llvm/ADT/PointerIntPair.h" + +namespace llvm { + +/// Base class for ilist nodes. +/// +/// Optionally tracks whether this node is the sentinel. +template <bool EnableSentinelTracking> class ilist_node_base; + +template <> class ilist_node_base<false> { + ilist_node_base *Prev = nullptr; + ilist_node_base *Next = nullptr; + +public: + void setPrev(ilist_node_base *Prev) { this->Prev = Prev; } + void setNext(ilist_node_base *Next) { this->Next = Next; } + ilist_node_base *getPrev() const { return Prev; } + ilist_node_base *getNext() const { return Next; } + + bool isKnownSentinel() const { return false; } + void initializeSentinel() {} +}; + +template <> class ilist_node_base<true> { + PointerIntPair<ilist_node_base *, 1> PrevAndSentinel; + ilist_node_base *Next = nullptr; + +public: + void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); } + void setNext(ilist_node_base *Next) { this->Next = Next; } + ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); } + ilist_node_base *getNext() const { return Next; } + + bool isSentinel() const { return PrevAndSentinel.getInt(); } + bool isKnownSentinel() const { return isSentinel(); } + void initializeSentinel() { PrevAndSentinel.setInt(true); } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_ILIST_NODE_BASE_H diff --git a/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h b/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h new file mode 100644 index 000000000..9b95cdbe0 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h @@ -0,0 +1,131 @@ +//===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H +#define LLVM_ADT_ILIST_NODE_OPTIONS_H + +#include "llvm/Config/abi-breaking.h" + +#include <type_traits> + +namespace llvm { + +template <bool EnableSentinelTracking> class ilist_node_base; +template <bool EnableSentinelTracking> class ilist_base; + +/// Option to choose whether to track sentinels. +/// +/// This option affects the ABI for the nodes. When not specified explicitly, +/// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS. Specify explicitly to +/// enable \a ilist_node::isSentinel(). +template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {}; + +/// Option to specify a tag for the node type. +/// +/// This option allows a single value type to be inserted in multiple lists +/// simultaneously. See \a ilist_node for usage examples. +template <class Tag> struct ilist_tag {}; + +namespace ilist_detail { + +/// Helper trait for recording whether an option is specified explicitly. +template <bool IsExplicit> struct explicitness { + static const bool is_explicit = IsExplicit; +}; +typedef explicitness<true> is_explicit; +typedef explicitness<false> is_implicit; + +/// Check whether an option is valid. +/// +/// The steps for adding and enabling a new ilist option include: +/// \li define the option, ilist_foo<Bar>, above; +/// \li add new parameters for Bar to \a ilist_detail::node_options; +/// \li add an extraction meta-function, ilist_detail::extract_foo; +/// \li call extract_foo from \a ilist_detail::compute_node_options and pass it +/// into \a ilist_detail::node_options; and +/// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c +/// std::true_type to get static assertions passing in \a simple_ilist and \a +/// ilist_node. +template <class Option> struct is_valid_option : std::false_type {}; + +/// Extract sentinel tracking option. +/// +/// Look through \p Options for the \a ilist_sentinel_tracking option, with the +/// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS. +template <class... Options> struct extract_sentinel_tracking; +template <bool EnableSentinelTracking, class... Options> +struct extract_sentinel_tracking< + ilist_sentinel_tracking<EnableSentinelTracking>, Options...> + : std::integral_constant<bool, EnableSentinelTracking>, is_explicit {}; +template <class Option1, class... Options> +struct extract_sentinel_tracking<Option1, Options...> + : extract_sentinel_tracking<Options...> {}; +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {}; +#else +template <> +struct extract_sentinel_tracking<> : std::false_type, is_implicit {}; +#endif +template <bool EnableSentinelTracking> +struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>> + : std::true_type {}; + +/// Extract custom tag option. +/// +/// Look through \p Options for the \a ilist_tag option, pulling out the +/// custom tag type, using void as a default. +template <class... Options> struct extract_tag; +template <class Tag, class... Options> +struct extract_tag<ilist_tag<Tag>, Options...> { + typedef Tag type; +}; +template <class Option1, class... Options> +struct extract_tag<Option1, Options...> : extract_tag<Options...> {}; +template <> struct extract_tag<> { typedef void type; }; +template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {}; + +/// Check whether options are valid. +/// +/// The conjunction of \a is_valid_option on each individual option. +template <class... Options> struct check_options; +template <> struct check_options<> : std::true_type {}; +template <class Option1, class... Options> +struct check_options<Option1, Options...> + : std::integral_constant<bool, is_valid_option<Option1>::value && + check_options<Options...>::value> {}; + +/// Traits for options for \a ilist_node. +/// +/// This is usually computed via \a compute_node_options. +template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit, + class TagT> +struct node_options { + typedef T value_type; + typedef T *pointer; + typedef T &reference; + typedef const T *const_pointer; + typedef const T &const_reference; + + static const bool enable_sentinel_tracking = EnableSentinelTracking; + static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit; + typedef TagT tag; + typedef ilist_node_base<enable_sentinel_tracking> node_base_type; + typedef ilist_base<enable_sentinel_tracking> list_base_type; +}; + +template <class T, class... Options> struct compute_node_options { + typedef node_options<T, extract_sentinel_tracking<Options...>::value, + extract_sentinel_tracking<Options...>::is_explicit, + typename extract_tag<Options...>::type> + type; +}; + +} // end namespace ilist_detail +} // end namespace llvm + +#endif // LLVM_ADT_ILIST_NODE_OPTIONS_H diff --git a/third_party/llvm-project/include/llvm/ADT/iterator.h b/third_party/llvm-project/include/llvm/ADT/iterator.h new file mode 100644 index 000000000..467fd4c00 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/iterator.h @@ -0,0 +1,366 @@ +//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ITERATOR_H +#define LLVM_ADT_ITERATOR_H + +#include "llvm/ADT/iterator_range.h" +#include <algorithm> +#include <cstddef> +#include <iterator> +#include <type_traits> +#include <utility> + +namespace llvm { + +/// CRTP base class which implements the entire standard iterator facade +/// in terms of a minimal subset of the interface. +/// +/// Use this when it is reasonable to implement most of the iterator +/// functionality in terms of a core subset. If you need special behavior or +/// there are performance implications for this, you may want to override the +/// relevant members instead. +/// +/// Note, one abstraction that this does *not* provide is implementing +/// subtraction in terms of addition by negating the difference. Negation isn't +/// always information preserving, and I can see very reasonable iterator +/// designs where this doesn't work well. It doesn't really force much added +/// boilerplate anyways. +/// +/// Another abstraction that this doesn't provide is implementing increment in +/// terms of addition of one. These aren't equivalent for all iterator +/// categories, and respecting that adds a lot of complexity for little gain. +/// +/// Classes wishing to use `iterator_facade_base` should implement the following +/// methods: +/// +/// Forward Iterators: +/// (All of the following methods) +/// - DerivedT &operator=(const DerivedT &R); +/// - bool operator==(const DerivedT &R) const; +/// - const T &operator*() const; +/// - T &operator*(); +/// - DerivedT &operator++(); +/// +/// Bidirectional Iterators: +/// (All methods of forward iterators, plus the following) +/// - DerivedT &operator--(); +/// +/// Random-access Iterators: +/// (All methods of bidirectional iterators excluding the following) +/// - DerivedT &operator++(); +/// - DerivedT &operator--(); +/// (and plus the following) +/// - bool operator<(const DerivedT &RHS) const; +/// - DifferenceTypeT operator-(const DerivedT &R) const; +/// - DerivedT &operator+=(DifferenceTypeT N); +/// - DerivedT &operator-=(DifferenceTypeT N); +/// +template <typename DerivedT, typename IteratorCategoryT, typename T, + typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *, + typename ReferenceT = T &> +class iterator_facade_base + : public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT, + ReferenceT> { +protected: + enum { + IsRandomAccess = std::is_base_of<std::random_access_iterator_tag, + IteratorCategoryT>::value, + IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag, + IteratorCategoryT>::value, + }; + + /// A proxy object for computing a reference via indirecting a copy of an + /// iterator. This is used in APIs which need to produce a reference via + /// indirection but for which the iterator object might be a temporary. The + /// proxy preserves the iterator internally and exposes the indirected + /// reference via a conversion operator. + class ReferenceProxy { + friend iterator_facade_base; + + DerivedT I; + + ReferenceProxy(DerivedT I) : I(std::move(I)) {} + + public: + operator ReferenceT() const { return *I; } + }; + +public: + DerivedT operator+(DifferenceTypeT n) const { + static_assert(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."); + DerivedT tmp = *static_cast<const DerivedT *>(this); + tmp += n; + return tmp; + } + friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) { + static_assert( + IsRandomAccess, + "The '+' operator is only defined for random access iterators."); + return i + n; + } + DerivedT operator-(DifferenceTypeT n) const { + static_assert( + IsRandomAccess, + "The '-' operator is only defined for random access iterators."); + DerivedT tmp = *static_cast<const DerivedT *>(this); + tmp -= n; + return tmp; + } + + 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) { + DerivedT tmp = *static_cast<DerivedT *>(this); + ++*static_cast<DerivedT *>(this); + return tmp; + } + DerivedT &operator--() { + static_assert( + IsBidirectional, + "The decrement operator is only defined for bidirectional iterators."); + return static_cast<DerivedT *>(this)->operator-=(1); + } + DerivedT operator--(int) { + static_assert( + IsBidirectional, + "The decrement operator is only defined for bidirectional iterators."); + DerivedT tmp = *static_cast<DerivedT *>(this); + --*static_cast<DerivedT *>(this); + return tmp; + } + + bool operator!=(const DerivedT &RHS) const { + return !static_cast<const DerivedT *>(this)->operator==(RHS); + } + + bool operator>(const DerivedT &RHS) const { + static_assert( + IsRandomAccess, + "Relational operators are only defined for random access iterators."); + return !static_cast<const DerivedT *>(this)->operator<(RHS) && + !static_cast<const DerivedT *>(this)->operator==(RHS); + } + bool operator<=(const DerivedT &RHS) const { + static_assert( + IsRandomAccess, + "Relational operators are only defined for random access iterators."); + return !static_cast<const DerivedT *>(this)->operator>(RHS); + } + bool operator>=(const DerivedT &RHS) const { + static_assert( + IsRandomAccess, + "Relational operators are only defined for random access iterators."); + 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."); + return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n)); + } +}; + +/// CRTP base class for adapting an iterator to a different type. +/// +/// This class can be used through CRTP to adapt one iterator into another. +/// Typically this is done through providing in the derived class a custom \c +/// operator* implementation. Other methods can be overridden as well. +template < + typename DerivedT, typename WrappedIteratorT, + typename IteratorCategoryT = + typename std::iterator_traits<WrappedIteratorT>::iterator_category, + typename T = typename std::iterator_traits<WrappedIteratorT>::value_type, + typename DifferenceTypeT = + typename std::iterator_traits<WrappedIteratorT>::difference_type, + typename PointerT = typename std::conditional< + std::is_same<T, typename std::iterator_traits< + WrappedIteratorT>::value_type>::value, + typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type, + typename ReferenceT = typename std::conditional< + std::is_same<T, typename std::iterator_traits< + WrappedIteratorT>::value_type>::value, + typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type> +class iterator_adaptor_base + : public iterator_facade_base<DerivedT, IteratorCategoryT, T, + DifferenceTypeT, PointerT, ReferenceT> { + using BaseT = typename iterator_adaptor_base::iterator_facade_base; + +protected: + WrappedIteratorT I; + + iterator_adaptor_base() = default; + + 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; } + +public: + using difference_type = DifferenceTypeT; + + DerivedT &operator+=(difference_type n) { + static_assert( + BaseT::IsRandomAccess, + "The '+=' operator is only defined for random access iterators."); + I += n; + return *static_cast<DerivedT *>(this); + } + DerivedT &operator-=(difference_type n) { + static_assert( + BaseT::IsRandomAccess, + "The '-=' operator is only defined for random access iterators."); + I -= n; + return *static_cast<DerivedT *>(this); + } + using BaseT::operator-; + difference_type operator-(const DerivedT &RHS) const { + static_assert( + BaseT::IsRandomAccess, + "The '-' operator is only defined for random access iterators."); + return I - RHS.I; + } + + // We have to explicitly provide ++ and -- rather than letting the facade + // forward to += because WrappedIteratorT might not support +=. + using BaseT::operator++; + DerivedT &operator++() { + ++I; + return *static_cast<DerivedT *>(this); + } + using BaseT::operator--; + DerivedT &operator--() { + static_assert( + BaseT::IsBidirectional, + "The decrement operator is only defined for bidirectional iterators."); + --I; + return *static_cast<DerivedT *>(this); + } + + bool operator==(const DerivedT &RHS) const { return I == RHS.I; } + bool operator<(const DerivedT &RHS) const { + static_assert( + BaseT::IsRandomAccess, + "Relational operators are only defined for random access iterators."); + return I < RHS.I; + } + + ReferenceT operator*() const { return *I; } +}; + +/// An iterator type that allows iterating over the pointees via some +/// other iterator. +/// +/// The typical usage of this is to expose a type that iterates over Ts, but +/// which is implemented with some iterator over T*s: +/// +/// \code +/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>; +/// \endcode +template <typename WrappedIteratorT, + typename T = typename std::remove_reference< + decltype(**std::declval<WrappedIteratorT>())>::type> +struct pointee_iterator + : iterator_adaptor_base< + pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT, + typename std::iterator_traits<WrappedIteratorT>::iterator_category, + T> { + pointee_iterator() = default; + template <typename U> + pointee_iterator(U &&u) + : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {} + + 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 + : public iterator_adaptor_base< + pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT, + typename std::iterator_traits<WrappedIteratorT>::iterator_category, + T> { + mutable T Ptr; + +public: + pointer_iterator() = default; + + explicit pointer_iterator(WrappedIteratorT u) + : pointer_iterator::iterator_adaptor_base(std::move(u)) {} + + T &operator*() { return Ptr = &*this->I; } + 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)))); +} + +// Wrapper iterator over iterator ItType, adding DataRef to the type of ItType, +// to create NodeRef = std::pair<InnerTypeOfItType, DataRef>. +template <typename ItType, typename NodeRef, typename DataRef> +class WrappedPairNodeDataIterator + : public iterator_adaptor_base< + WrappedPairNodeDataIterator<ItType, NodeRef, DataRef>, ItType, + typename std::iterator_traits<ItType>::iterator_category, NodeRef, + std::ptrdiff_t, NodeRef *, NodeRef &> { + using BaseT = iterator_adaptor_base< + WrappedPairNodeDataIterator, ItType, + typename std::iterator_traits<ItType>::iterator_category, NodeRef, + std::ptrdiff_t, NodeRef *, NodeRef &>; + + const DataRef DR; + mutable NodeRef NR; + +public: + WrappedPairNodeDataIterator(ItType Begin, const DataRef DR) + : BaseT(Begin), DR(DR) { + NR.first = DR; + } + + NodeRef &operator*() const { + NR.second = *this->I; + return NR; + } +}; + +} // end namespace llvm + +#endif // LLVM_ADT_ITERATOR_H diff --git a/third_party/llvm-project/include/llvm/ADT/iterator_range.h b/third_party/llvm-project/include/llvm/ADT/iterator_range.h new file mode 100644 index 000000000..aa8830943 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/iterator_range.h @@ -0,0 +1,69 @@ +//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This provides a very simple, boring adaptor for a begin and end iterator +/// into a range type. This should be used to build range views that work well +/// with range based for loops and range based constructors. +/// +/// Note that code here follows more standards-based coding conventions as it +/// is mirroring proposed interfaces for standardization. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ITERATOR_RANGE_H +#define LLVM_ADT_ITERATOR_RANGE_H + +#include <iterator> +#include <utility> + +namespace llvm { + +/// A range adaptor for a pair of iterators. +/// +/// This just wraps two iterators into a range-compatible interface. Nothing +/// fancy at all. +template <typename IteratorT> +class iterator_range { + IteratorT begin_iterator, end_iterator; + +public: + //TODO: Add SFINAE to test that the Container's iterators match the range's + // iterators. + template <typename Container> + iterator_range(Container &&c) + //TODO: Consider ADL/non-member begin/end calls. + : begin_iterator(c.begin()), end_iterator(c.end()) {} + iterator_range(IteratorT begin_iterator, IteratorT end_iterator) + : begin_iterator(std::move(begin_iterator)), + end_iterator(std::move(end_iterator)) {} + + IteratorT begin() const { return begin_iterator; } + IteratorT end() const { return end_iterator; } + bool empty() const { return begin_iterator == end_iterator; } +}; + +/// Convenience function for iterating over sub-ranges. +/// +/// This provides a bit of syntactic sugar to make using sub-ranges +/// in for loops a bit easier. Analogous to std::make_pair(). +template <class T> iterator_range<T> make_range(T x, T y) { + return iterator_range<T>(std::move(x), std::move(y)); +} + +template <typename T> iterator_range<T> make_range(std::pair<T, T> p) { + return iterator_range<T>(std::move(p.first), std::move(p.second)); +} + +template <typename T> +iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t, + int n) { + return make_range(std::next(adl_begin(t), n), adl_end(t)); +} +} + +#endif diff --git a/third_party/llvm-project/include/llvm/ADT/simple_ilist.h b/third_party/llvm-project/include/llvm/ADT/simple_ilist.h new file mode 100644 index 000000000..9257b47b9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/ADT/simple_ilist.h @@ -0,0 +1,314 @@ +//===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SIMPLE_ILIST_H +#define LLVM_ADT_SIMPLE_ILIST_H + +#include "llvm/ADT/ilist_base.h" +#include "llvm/ADT/ilist_iterator.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/ilist_node_options.h" +#include "llvm/Support/Compiler.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <iterator> +#include <utility> + +namespace llvm { + +/// A simple intrusive list implementation. +/// +/// This is a simple intrusive list for a \c T that inherits from \c +/// ilist_node<T>. The list never takes ownership of anything inserted in it. +/// +/// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never allocates or +/// deletes values, and has no callback traits. +/// +/// The API for adding nodes include \a push_front(), \a push_back(), and \a +/// insert(). These all take values by reference (not by pointer), except for +/// the range version of \a insert(). +/// +/// There are three sets of API for discarding nodes from the list: \a +/// remove(), which takes a reference to the node to remove, \a erase(), which +/// takes an iterator or iterator range and returns the next one, and \a +/// clear(), which empties out the container. All three are constant time +/// operations. None of these deletes any nodes; in particular, if there is a +/// single node in the list, then these have identical semantics: +/// \li \c L.remove(L.front()); +/// \li \c L.erase(L.begin()); +/// \li \c L.clear(); +/// +/// As a convenience for callers, there are parallel APIs that take a \c +/// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a +/// eraseAndDispose(), and \a clearAndDispose(). These have different names +/// because the extra semantic is otherwise non-obvious. They are equivalent +/// to calling \a std::for_each() on the range to be discarded. +/// +/// The currently available \p Options customize the nodes in the list. The +/// same options must be specified in the \a ilist_node instantation for +/// compatibility (although the order is irrelevant). +/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this +/// list should use. This is useful if a type \p T is part of multiple, +/// independent lists simultaneously. +/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a +/// node is a sentinel. Specifying \c true enables the \a +/// ilist_node::isSentinel() API. Unlike \a ilist_node::isKnownSentinel(), +/// which is only appropriate for assertions, \a ilist_node::isSentinel() is +/// appropriate for real logic. +/// +/// Here are examples of \p Options usage: +/// \li \c simple_ilist<T> gives the defaults. \li \c +/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a +/// ilist_node::isSentinel() API. +/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>> +/// specifies a tag of A and that tracking should be off (even when +/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled). +/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is +/// equivalent to the last. +/// +/// See \a is_valid_option for steps on adding a new option. +template <typename T, class... Options> +class simple_ilist + : ilist_detail::compute_node_options<T, Options...>::type::list_base_type, + ilist_detail::SpecificNodeAccess< + typename ilist_detail::compute_node_options<T, Options...>::type> { + static_assert(ilist_detail::check_options<Options...>::value, + "Unrecognized node option!"); + using OptionsT = + typename ilist_detail::compute_node_options<T, Options...>::type; + using list_base_type = typename OptionsT::list_base_type; + ilist_sentinel<OptionsT> Sentinel; + +public: + using value_type = typename OptionsT::value_type; + using pointer = typename OptionsT::pointer; + using reference = typename OptionsT::reference; + using const_pointer = typename OptionsT::const_pointer; + using const_reference = typename OptionsT::const_reference; + using iterator = ilist_iterator<OptionsT, false, false>; + using const_iterator = ilist_iterator<OptionsT, false, true>; + using reverse_iterator = ilist_iterator<OptionsT, true, false>; + using const_reverse_iterator = ilist_iterator<OptionsT, true, true>; + using size_type = size_t; + using difference_type = ptrdiff_t; + + simple_ilist() = default; + ~simple_ilist() = default; + + // No copy constructors. + simple_ilist(const simple_ilist &) = delete; + simple_ilist &operator=(const simple_ilist &) = delete; + + // Move constructors. + simple_ilist(simple_ilist &&X) { splice(end(), X); } + simple_ilist &operator=(simple_ilist &&X) { + clear(); + splice(end(), X); + return *this; + } + + iterator begin() { return ++iterator(Sentinel); } + const_iterator begin() const { return ++const_iterator(Sentinel); } + iterator end() { return iterator(Sentinel); } + const_iterator end() const { return const_iterator(Sentinel); } + reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); } + const_reverse_iterator rbegin() const { + return ++const_reverse_iterator(Sentinel); + } + reverse_iterator rend() { return reverse_iterator(Sentinel); } + const_reverse_iterator rend() const { + return const_reverse_iterator(Sentinel); + } + + /// Check if the list is empty in constant time. + LLVM_NODISCARD bool empty() const { return Sentinel.empty(); } + + /// Calculate the size of the list in linear time. + LLVM_NODISCARD size_type size() const { + return std::distance(begin(), end()); + } + + reference front() { return *begin(); } + const_reference front() const { return *begin(); } + reference back() { return *rbegin(); } + const_reference back() const { return *rbegin(); } + + /// Insert a node at the front; never copies. + void push_front(reference Node) { insert(begin(), Node); } + + /// Insert a node at the back; never copies. + void push_back(reference Node) { insert(end(), Node); } + + /// Remove the node at the front; never deletes. + void pop_front() { erase(begin()); } + + /// Remove the node at the back; never deletes. + void pop_back() { erase(--end()); } + + /// Swap with another list in place using std::swap. + void swap(simple_ilist &X) { std::swap(*this, X); } + + /// Insert a node by reference; never copies. + iterator insert(iterator I, reference Node) { + list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node)); + return iterator(&Node); + } + + /// Insert a range of nodes; never copies. + template <class Iterator> + void insert(iterator I, Iterator First, Iterator Last) { + for (; First != Last; ++First) + insert(I, *First); + } + + /// Clone another list. + template <class Cloner, class Disposer> + void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) { + clearAndDispose(dispose); + for (const_reference V : L2) + push_back(*clone(V)); + } + + /// Remove a node by reference; never deletes. + /// + /// \see \a erase() for removing by iterator. + /// \see \a removeAndDispose() if the node should be deleted. + void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); } + + /// Remove a node by reference and dispose of it. + template <class Disposer> + void removeAndDispose(reference N, Disposer dispose) { + remove(N); + dispose(&N); + } + + /// Remove a node by iterator; never deletes. + /// + /// \see \a remove() for removing by reference. + /// \see \a eraseAndDispose() it the node should be deleted. + iterator erase(iterator I) { + assert(I != end() && "Cannot remove end of list!"); + remove(*I++); + return I; + } + + /// Remove a range of nodes; never deletes. + /// + /// \see \a eraseAndDispose() if the nodes should be deleted. + iterator erase(iterator First, iterator Last) { + list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr()); + return Last; + } + + /// Remove a node by iterator and dispose of it. + template <class Disposer> + iterator eraseAndDispose(iterator I, Disposer dispose) { + auto Next = std::next(I); + erase(I); + dispose(&*I); + return Next; + } + + /// Remove a range of nodes and dispose of them. + template <class Disposer> + iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) { + while (First != Last) + First = eraseAndDispose(First, dispose); + return Last; + } + + /// Clear the list; never deletes. + /// + /// \see \a clearAndDispose() if the nodes should be deleted. + void clear() { Sentinel.reset(); } + + /// Clear the list and dispose of the nodes. + template <class Disposer> void clearAndDispose(Disposer dispose) { + eraseAndDispose(begin(), end(), dispose); + } + + /// Splice in another list. + void splice(iterator I, simple_ilist &L2) { + splice(I, L2, L2.begin(), L2.end()); + } + + /// Splice in a node from another list. + void splice(iterator I, simple_ilist &L2, iterator Node) { + splice(I, L2, Node, std::next(Node)); + } + + /// Splice in a range of nodes from another list. + void splice(iterator I, simple_ilist &, iterator First, iterator Last) { + list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(), + *Last.getNodePtr()); + } + + /// Merge in another list. + /// + /// \pre \c this and \p RHS are sorted. + ///@{ + void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); } + template <class Compare> void merge(simple_ilist &RHS, Compare comp); + ///@} + + /// Sort the list. + ///@{ + void sort() { sort(std::less<T>()); } + template <class Compare> void sort(Compare comp); + ///@} +}; + +template <class T, class... Options> +template <class Compare> +void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) { + if (this == &RHS || RHS.empty()) + return; + iterator LI = begin(), LE = end(); + iterator RI = RHS.begin(), RE = RHS.end(); + while (LI != LE) { + if (comp(*RI, *LI)) { + // Transfer a run of at least size 1 from RHS to LHS. + iterator RunStart = RI++; + RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); }); + splice(LI, RHS, RunStart, RI); + if (RI == RE) + return; + } + ++LI; + } + // Transfer the remaining RHS nodes once LHS is finished. + splice(LE, RHS, RI, RE); +} + +template <class T, class... Options> +template <class Compare> +void simple_ilist<T, Options...>::sort(Compare comp) { + // Vacuously sorted. + if (empty() || std::next(begin()) == end()) + return; + + // Split the list in the middle. + iterator Center = begin(), End = begin(); + while (End != end() && ++End != end()) { + ++Center; + ++End; + } + simple_ilist RHS; + RHS.splice(RHS.end(), *this, Center, end()); + + // Sort the sublists and merge back together. + sort(comp); + RHS.sort(comp); + merge(RHS, comp); +} + +} // end namespace llvm + +#endif // LLVM_ADT_SIMPLE_ILIST_H |